summaryrefslogtreecommitdiffstats
path: root/clang/lib/Sema/SemaDecl.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/Sema/SemaDecl.cpp')
-rw-r--r--clang/lib/Sema/SemaDecl.cpp253
1 files changed, 233 insertions, 20 deletions
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 683905b1480..ea7a31dbc77 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -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();
OpenPOWER on IntegriCloud