|
@@ -43,6 +43,7 @@
|
|
|
#include "clang/Sema/SemaInternal.h"
|
|
|
#include "clang/Sema/Template.h"
|
|
|
#include "llvm/ADT/SmallString.h"
|
|
|
+#include "llvm/ADT/StringExtras.h"
|
|
|
#include "llvm/ADT/Triple.h"
|
|
|
#include <algorithm>
|
|
|
#include <cstring>
|
|
@@ -4921,7 +4922,9 @@ NamedDecl *Sema::HandleDeclarator(Scope *S, Declarator &D,
|
|
|
|
|
|
// All of these full declarators require an identifier. If it doesn't have
|
|
|
// one, the ParsedFreeStandingDeclSpec action should be used.
|
|
|
- if (!Name) {
|
|
|
+ if (D.isDecompositionDeclarator()) {
|
|
|
+ return ActOnDecompositionDeclarator(S, D, TemplateParamLists);
|
|
|
+ } else if (!Name) {
|
|
|
if (!D.isInvalidType()) // Reject this if we think it is valid.
|
|
|
Diag(D.getDeclSpec().getLocStart(),
|
|
|
diag::err_declarator_need_ident)
|
|
@@ -5845,14 +5848,30 @@ static bool isDeclExternC(const Decl *D) {
|
|
|
llvm_unreachable("Unknown type of decl!");
|
|
|
}
|
|
|
|
|
|
-NamedDecl *
|
|
|
-Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
|
|
|
- TypeSourceInfo *TInfo, LookupResult &Previous,
|
|
|
- MultiTemplateParamsArg TemplateParamLists,
|
|
|
- bool &AddToScope) {
|
|
|
+NamedDecl *Sema::ActOnVariableDeclarator(
|
|
|
+ Scope *S, Declarator &D, DeclContext *DC, TypeSourceInfo *TInfo,
|
|
|
+ LookupResult &Previous, MultiTemplateParamsArg TemplateParamLists,
|
|
|
+ bool &AddToScope, ArrayRef<BindingDecl *> Bindings) {
|
|
|
QualType R = TInfo->getType();
|
|
|
DeclarationName Name = GetNameForDeclarator(D).getName();
|
|
|
|
|
|
+ IdentifierInfo *II = Name.getAsIdentifierInfo();
|
|
|
+
|
|
|
+ if (D.isDecompositionDeclarator()) {
|
|
|
+ AddToScope = false;
|
|
|
+ // Take the name of the first declarator as our name for diagnostic
|
|
|
+ // purposes.
|
|
|
+ auto &Decomp = D.getDecompositionDeclarator();
|
|
|
+ if (!Decomp.bindings().empty()) {
|
|
|
+ II = Decomp.bindings()[0].Name;
|
|
|
+ Name = II;
|
|
|
+ }
|
|
|
+ } else if (!II) {
|
|
|
+ Diag(D.getIdentifierLoc(), diag::err_bad_variable_name)
|
|
|
+ << Name;
|
|
|
+ return nullptr;
|
|
|
+ }
|
|
|
+
|
|
|
// OpenCL v2.0 s6.9.b - Image type can only be used as a function argument.
|
|
|
// OpenCL v2.0 s6.13.16.1 - Pipe type can only be used as a function
|
|
|
// argument.
|
|
@@ -5920,13 +5939,6 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
|
|
|
<< FixItHint::CreateRemoval(D.getDeclSpec().getStorageClassSpecLoc());
|
|
|
}
|
|
|
|
|
|
- IdentifierInfo *II = Name.getAsIdentifierInfo();
|
|
|
- if (!II) {
|
|
|
- Diag(D.getIdentifierLoc(), diag::err_bad_variable_name)
|
|
|
- << Name;
|
|
|
- return nullptr;
|
|
|
- }
|
|
|
-
|
|
|
DiagnoseFunctionSpecifiers(D.getDeclSpec());
|
|
|
|
|
|
if (!DC->isRecord() && S->getFnParent() == nullptr) {
|
|
@@ -6095,6 +6107,10 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
|
|
|
return nullptr;
|
|
|
NewVD = cast<VarDecl>(Res.get());
|
|
|
AddToScope = false;
|
|
|
+ } else if (D.isDecompositionDeclarator()) {
|
|
|
+ NewVD = DecompositionDecl::Create(Context, DC, D.getLocStart(),
|
|
|
+ D.getIdentifierLoc(), R, TInfo, SC,
|
|
|
+ Bindings);
|
|
|
} else
|
|
|
NewVD = VarDecl::Create(Context, DC, D.getLocStart(),
|
|
|
D.getIdentifierLoc(), II, R, TInfo, SC);
|
|
@@ -6200,8 +6216,13 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
|
|
|
if (NewTemplate)
|
|
|
NewTemplate->setLexicalDeclContext(CurContext);
|
|
|
|
|
|
- if (IsLocalExternDecl)
|
|
|
- NewVD->setLocalExternDecl();
|
|
|
+ if (IsLocalExternDecl) {
|
|
|
+ if (D.isDecompositionDeclarator())
|
|
|
+ for (auto *B : Bindings)
|
|
|
+ B->setLocalExternDecl();
|
|
|
+ else
|
|
|
+ NewVD->setLocalExternDecl();
|
|
|
+ }
|
|
|
|
|
|
bool EmitTLSUnsupportedError = false;
|
|
|
if (DeclSpec::TSCS TSCS = D.getDeclSpec().getThreadStorageClassSpec()) {
|
|
@@ -6273,6 +6294,8 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
|
|
|
NewVD->setModulePrivate();
|
|
|
if (NewTemplate)
|
|
|
NewTemplate->setModulePrivate();
|
|
|
+ for (auto *B : Bindings)
|
|
|
+ B->setModulePrivate();
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -6480,7 +6503,7 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
|
|
|
}
|
|
|
|
|
|
// Special handling of variable named 'main'.
|
|
|
- if (Name.isIdentifier() && Name.getAsIdentifierInfo()->isStr("main") &&
|
|
|
+ if (Name.getAsIdentifierInfo() && Name.getAsIdentifierInfo()->isStr("main") &&
|
|
|
NewVD->getDeclContext()->getRedeclContext()->isTranslationUnit() &&
|
|
|
!getLangOpts().Freestanding && !NewVD->getDescribedVarTemplate()) {
|
|
|
|
|
@@ -6511,6 +6534,157 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
|
|
|
return NewVD;
|
|
|
}
|
|
|
|
|
|
+NamedDecl *
|
|
|
+Sema::ActOnDecompositionDeclarator(Scope *S, Declarator &D,
|
|
|
+ MultiTemplateParamsArg TemplateParamLists) {
|
|
|
+ assert(D.isDecompositionDeclarator());
|
|
|
+ const DecompositionDeclarator &Decomp = D.getDecompositionDeclarator();
|
|
|
+
|
|
|
+ // The syntax only allows a decomposition declarator as a simple-declaration
|
|
|
+ // or a for-range-declaration, but we parse it in more cases than that.
|
|
|
+ if (!D.mayHaveDecompositionDeclarator()) {
|
|
|
+ Diag(Decomp.getLSquareLoc(), diag::err_decomp_decl_context)
|
|
|
+ << Decomp.getSourceRange();
|
|
|
+ return nullptr;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!TemplateParamLists.empty()) {
|
|
|
+ // FIXME: There's no rule against this, but there are also no rules that
|
|
|
+ // would actually make it usable, so we reject it for now.
|
|
|
+ Diag(TemplateParamLists.front()->getTemplateLoc(),
|
|
|
+ diag::err_decomp_decl_template);
|
|
|
+ return nullptr;
|
|
|
+ }
|
|
|
+
|
|
|
+ Diag(Decomp.getLSquareLoc(), getLangOpts().CPlusPlus1z
|
|
|
+ ? diag::warn_cxx14_compat_decomp_decl
|
|
|
+ : diag::ext_decomp_decl)
|
|
|
+ << Decomp.getSourceRange();
|
|
|
+
|
|
|
+ // The semantic context is always just the current context.
|
|
|
+ DeclContext *const DC = CurContext;
|
|
|
+
|
|
|
+ // C++1z [dcl.dcl]/8:
|
|
|
+ // The decl-specifier-seq shall contain only the type-specifier auto
|
|
|
+ // and cv-qualifiers.
|
|
|
+ auto &DS = D.getDeclSpec();
|
|
|
+ {
|
|
|
+ SmallVector<StringRef, 8> BadSpecifiers;
|
|
|
+ SmallVector<SourceLocation, 8> BadSpecifierLocs;
|
|
|
+ if (auto SCS = DS.getStorageClassSpec()) {
|
|
|
+ BadSpecifiers.push_back(DeclSpec::getSpecifierName(SCS));
|
|
|
+ BadSpecifierLocs.push_back(DS.getStorageClassSpecLoc());
|
|
|
+ }
|
|
|
+ if (auto TSCS = DS.getThreadStorageClassSpec()) {
|
|
|
+ BadSpecifiers.push_back(DeclSpec::getSpecifierName(TSCS));
|
|
|
+ BadSpecifierLocs.push_back(DS.getThreadStorageClassSpecLoc());
|
|
|
+ }
|
|
|
+ if (DS.isConstexprSpecified()) {
|
|
|
+ BadSpecifiers.push_back("constexpr");
|
|
|
+ BadSpecifierLocs.push_back(DS.getConstexprSpecLoc());
|
|
|
+ }
|
|
|
+ if (DS.isInlineSpecified()) {
|
|
|
+ BadSpecifiers.push_back("inline");
|
|
|
+ BadSpecifierLocs.push_back(DS.getInlineSpecLoc());
|
|
|
+ }
|
|
|
+ if (!BadSpecifiers.empty()) {
|
|
|
+ auto &&Err = Diag(BadSpecifierLocs.front(), diag::err_decomp_decl_spec);
|
|
|
+ Err << (int)BadSpecifiers.size()
|
|
|
+ << llvm::join(BadSpecifiers.begin(), BadSpecifiers.end(), " ");
|
|
|
+ // Don't add FixItHints to remove the specifiers; we do still respect
|
|
|
+ // them when building the underlying variable.
|
|
|
+ for (auto Loc : BadSpecifierLocs)
|
|
|
+ Err << SourceRange(Loc, Loc);
|
|
|
+ }
|
|
|
+ // We can't recover from it being declared as a typedef.
|
|
|
+ if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef)
|
|
|
+ return nullptr;
|
|
|
+ }
|
|
|
+
|
|
|
+ TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S);
|
|
|
+ QualType R = TInfo->getType();
|
|
|
+
|
|
|
+ if (DiagnoseUnexpandedParameterPack(D.getIdentifierLoc(), TInfo,
|
|
|
+ UPPC_DeclarationType))
|
|
|
+ D.setInvalidType();
|
|
|
+
|
|
|
+ // The syntax only allows a single ref-qualifier prior to the decomposition
|
|
|
+ // declarator. No other declarator chunks are permitted. Also check the type
|
|
|
+ // specifier here.
|
|
|
+ if (DS.getTypeSpecType() != DeclSpec::TST_auto ||
|
|
|
+ D.hasGroupingParens() || D.getNumTypeObjects() > 1 ||
|
|
|
+ (D.getNumTypeObjects() == 1 &&
|
|
|
+ D.getTypeObject(0).Kind != DeclaratorChunk::Reference)) {
|
|
|
+ Diag(Decomp.getLSquareLoc(),
|
|
|
+ (D.hasGroupingParens() ||
|
|
|
+ (D.getNumTypeObjects() &&
|
|
|
+ D.getTypeObject(0).Kind == DeclaratorChunk::Paren))
|
|
|
+ ? diag::err_decomp_decl_parens
|
|
|
+ : diag::err_decomp_decl_type)
|
|
|
+ << R;
|
|
|
+
|
|
|
+ // In most cases, there's no actual problem with an explicitly-specified
|
|
|
+ // type, but a function type won't work here, and ActOnVariableDeclarator
|
|
|
+ // shouldn't be called for such a type.
|
|
|
+ if (R->isFunctionType())
|
|
|
+ D.setInvalidType();
|
|
|
+ }
|
|
|
+
|
|
|
+ // Build the BindingDecls.
|
|
|
+ SmallVector<BindingDecl*, 8> Bindings;
|
|
|
+
|
|
|
+ // Build the BindingDecls.
|
|
|
+ for (auto &B : D.getDecompositionDeclarator().bindings()) {
|
|
|
+ // Check for name conflicts.
|
|
|
+ DeclarationNameInfo NameInfo(B.Name, B.NameLoc);
|
|
|
+ LookupResult Previous(*this, NameInfo, LookupOrdinaryName,
|
|
|
+ ForRedeclaration);
|
|
|
+ LookupName(Previous, S,
|
|
|
+ /*CreateBuiltins*/DC->getRedeclContext()->isTranslationUnit());
|
|
|
+
|
|
|
+ // It's not permitted to shadow a template parameter name.
|
|
|
+ if (Previous.isSingleResult() &&
|
|
|
+ Previous.getFoundDecl()->isTemplateParameter()) {
|
|
|
+ DiagnoseTemplateParameterShadow(D.getIdentifierLoc(),
|
|
|
+ Previous.getFoundDecl());
|
|
|
+ Previous.clear();
|
|
|
+ }
|
|
|
+
|
|
|
+ bool ConsiderLinkage = DC->isFunctionOrMethod() &&
|
|
|
+ DS.getStorageClassSpec() == DeclSpec::SCS_extern;
|
|
|
+ FilterLookupForScope(Previous, DC, S, ConsiderLinkage,
|
|
|
+ /*AllowInlineNamespace*/false);
|
|
|
+ if (!Previous.empty()) {
|
|
|
+ auto *Old = Previous.getRepresentativeDecl();
|
|
|
+ Diag(B.NameLoc, diag::err_redefinition) << B.Name;
|
|
|
+ Diag(Old->getLocation(), diag::note_previous_definition);
|
|
|
+ }
|
|
|
+
|
|
|
+ auto *BD = BindingDecl::Create(Context, DC, B.NameLoc, B.Name);
|
|
|
+ PushOnScopeChains(BD, S, true);
|
|
|
+ Bindings.push_back(BD);
|
|
|
+ ParsingInitForAutoVars.insert(BD);
|
|
|
+ }
|
|
|
+
|
|
|
+ // There are no prior lookup results for the variable itself, because it
|
|
|
+ // is unnamed.
|
|
|
+ DeclarationNameInfo NameInfo((IdentifierInfo *)nullptr,
|
|
|
+ Decomp.getLSquareLoc());
|
|
|
+ LookupResult Previous(*this, NameInfo, LookupOrdinaryName, ForRedeclaration);
|
|
|
+
|
|
|
+ // Build the variable that holds the non-decomposed object.
|
|
|
+ bool AddToScope = true;
|
|
|
+ NamedDecl *New =
|
|
|
+ ActOnVariableDeclarator(S, D, DC, TInfo, Previous,
|
|
|
+ MultiTemplateParamsArg(), AddToScope, Bindings);
|
|
|
+ CurContext->addHiddenDecl(New);
|
|
|
+
|
|
|
+ if (isInOpenMPDeclareTargetContext())
|
|
|
+ checkDeclIsAllowedInOpenMPTarget(nullptr, New);
|
|
|
+
|
|
|
+ return New;
|
|
|
+}
|
|
|
+
|
|
|
/// Enum describing the %select options in diag::warn_decl_shadow.
|
|
|
enum ShadowedDeclKind { SDK_Local, SDK_Global, SDK_StaticMember, SDK_Field };
|
|
|
|
|
@@ -9956,6 +10130,11 @@ void Sema::ActOnInitializerError(Decl *D) {
|
|
|
VarDecl *VD = dyn_cast<VarDecl>(D);
|
|
|
if (!VD) return;
|
|
|
|
|
|
+ // Bindings are not usable if we can't make sense of the initializer.
|
|
|
+ if (auto *DD = dyn_cast<DecompositionDecl>(D))
|
|
|
+ for (auto *BD : DD->bindings())
|
|
|
+ BD->setInvalidDecl();
|
|
|
+
|
|
|
// Auto types are meaningless if we can't make sense of the initializer.
|
|
|
if (ParsingInitForAutoVars.count(D)) {
|
|
|
D->setInvalidDecl();
|
|
@@ -10501,6 +10680,10 @@ Sema::FinalizeDeclaration(Decl *ThisDecl) {
|
|
|
if (!VD)
|
|
|
return;
|
|
|
|
|
|
+ if (auto *DD = dyn_cast<DecompositionDecl>(ThisDecl))
|
|
|
+ for (auto *BD : DD->bindings())
|
|
|
+ FinalizeDeclaration(BD);
|
|
|
+
|
|
|
checkAttributesAfterMerging(*this, *VD);
|
|
|
|
|
|
// Perform TLS alignment check here after attributes attached to the variable
|
|
@@ -10679,13 +10862,36 @@ Sema::DeclGroupPtrTy Sema::FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS,
|
|
|
Decls.push_back(DS.getRepAsDecl());
|
|
|
|
|
|
DeclaratorDecl *FirstDeclaratorInGroup = nullptr;
|
|
|
- for (unsigned i = 0, e = Group.size(); i != e; ++i)
|
|
|
+ DecompositionDecl *FirstDecompDeclaratorInGroup = nullptr;
|
|
|
+ bool DiagnosedMultipleDecomps = false;
|
|
|
+
|
|
|
+ for (unsigned i = 0, e = Group.size(); i != e; ++i) {
|
|
|
if (Decl *D = Group[i]) {
|
|
|
- if (DeclaratorDecl *DD = dyn_cast<DeclaratorDecl>(D))
|
|
|
- if (!FirstDeclaratorInGroup)
|
|
|
- FirstDeclaratorInGroup = DD;
|
|
|
+ auto *DD = dyn_cast<DeclaratorDecl>(D);
|
|
|
+ if (DD && !FirstDeclaratorInGroup)
|
|
|
+ FirstDeclaratorInGroup = DD;
|
|
|
+
|
|
|
+ auto *Decomp = dyn_cast<DecompositionDecl>(D);
|
|
|
+ if (Decomp && !FirstDecompDeclaratorInGroup)
|
|
|
+ FirstDecompDeclaratorInGroup = Decomp;
|
|
|
+
|
|
|
+ // A decomposition declaration cannot be combined with any other
|
|
|
+ // declaration in the same group.
|
|
|
+ auto *OtherDD = FirstDeclaratorInGroup;
|
|
|
+ if (OtherDD == FirstDecompDeclaratorInGroup)
|
|
|
+ OtherDD = DD;
|
|
|
+ if (OtherDD && FirstDecompDeclaratorInGroup &&
|
|
|
+ OtherDD != FirstDecompDeclaratorInGroup &&
|
|
|
+ !DiagnosedMultipleDecomps) {
|
|
|
+ Diag(FirstDecompDeclaratorInGroup->getLocation(),
|
|
|
+ diag::err_decomp_decl_not_alone)
|
|
|
+ << OtherDD->getSourceRange();
|
|
|
+ DiagnosedMultipleDecomps = true;
|
|
|
+ }
|
|
|
+
|
|
|
Decls.push_back(D);
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
if (DeclSpec::isDeclRep(DS.getTypeSpecType())) {
|
|
|
if (TagDecl *Tag = dyn_cast_or_null<TagDecl>(DS.getRepAsDecl())) {
|
|
@@ -13351,6 +13557,13 @@ FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record,
|
|
|
Declarator &D, Expr *BitWidth,
|
|
|
InClassInitStyle InitStyle,
|
|
|
AccessSpecifier AS) {
|
|
|
+ if (D.isDecompositionDeclarator()) {
|
|
|
+ const DecompositionDeclarator &Decomp = D.getDecompositionDeclarator();
|
|
|
+ Diag(Decomp.getLSquareLoc(), diag::err_decomp_decl_context)
|
|
|
+ << Decomp.getSourceRange();
|
|
|
+ return nullptr;
|
|
|
+ }
|
|
|
+
|
|
|
IdentifierInfo *II = D.getIdentifier();
|
|
|
SourceLocation Loc = DeclStart;
|
|
|
if (II) Loc = D.getIdentifierLoc();
|