diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2016-07-22 23:36:59 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2016-07-22 23:36:59 +0000 |
commit | bdb84f374cde7736ca68d5db2c2ecf5468346710 (patch) | |
tree | 06ae6652b753c321b50df713f3a69b46240f38a8 /clang/lib/Sema | |
parent | eea7c267b9af73bec73949f99c43c4177a14a2f5 (diff) | |
download | bcm5719-llvm-bdb84f374cde7736ca68d5db2c2ecf5468346710.tar.gz bcm5719-llvm-bdb84f374cde7736ca68d5db2c2ecf5468346710.zip |
P0217R3: Parsing support and framework for AST representation of C++1z
decomposition declarations.
There are a couple of things in the wording that seem strange here:
decomposition declarations are permitted at namespace scope (which we partially
support here) and they are permitted as the declaration in a template (which we
reject).
llvm-svn: 276492
Diffstat (limited to 'clang/lib/Sema')
-rw-r--r-- | clang/lib/Sema/DeclSpec.cpp | 36 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 253 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDeclCXX.cpp | 3 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExpr.cpp | 13 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplateInstantiateDecl.cpp | 10 |
5 files changed, 289 insertions, 26 deletions
diff --git a/clang/lib/Sema/DeclSpec.cpp b/clang/lib/Sema/DeclSpec.cpp index b9d2843b055..c294658c031 100644 --- a/clang/lib/Sema/DeclSpec.cpp +++ b/clang/lib/Sema/DeclSpec.cpp @@ -220,11 +220,11 @@ DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto, // parameter list there (in an effort to avoid new/delete traffic). If it // is already used (consider a function returning a function pointer) or too // small (function with too many parameters), go to the heap. - if (!TheDeclarator.InlineParamsUsed && + if (!TheDeclarator.InlineStorageUsed && NumParams <= llvm::array_lengthof(TheDeclarator.InlineParams)) { I.Fun.Params = TheDeclarator.InlineParams; I.Fun.DeleteParams = false; - TheDeclarator.InlineParamsUsed = true; + TheDeclarator.InlineStorageUsed = true; } else { I.Fun.Params = new DeclaratorChunk::ParamInfo[NumParams]; I.Fun.DeleteParams = true; @@ -258,6 +258,38 @@ DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto, return I; } +void Declarator::setDecompositionBindings( + SourceLocation LSquareLoc, + ArrayRef<DecompositionDeclarator::Binding> Bindings, + SourceLocation RSquareLoc) { + assert(!hasName() && "declarator given multiple names!"); + + BindingGroup.LSquareLoc = LSquareLoc; + BindingGroup.RSquareLoc = RSquareLoc; + BindingGroup.NumBindings = Bindings.size(); + Range.setEnd(RSquareLoc); + + // We're now past the identifier. + SetIdentifier(nullptr, LSquareLoc); + Name.EndLocation = RSquareLoc; + + // Allocate storage for bindings and stash them away. + if (Bindings.size()) { + if (!InlineStorageUsed && + Bindings.size() <= llvm::array_lengthof(InlineBindings)) { + BindingGroup.Bindings = InlineBindings; + BindingGroup.DeleteBindings = false; + InlineStorageUsed = true; + } else { + BindingGroup.Bindings = + new DecompositionDeclarator::Binding[Bindings.size()]; + BindingGroup.DeleteBindings = true; + } + std::uninitialized_copy(Bindings.begin(), Bindings.end(), + BindingGroup.Bindings); + } +} + bool Declarator::isDeclarationOfFunction() const { for (unsigned i = 0, i_end = DeclTypeInfo.size(); i < i_end; ++i) { switch (DeclTypeInfo[i].Kind) { 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(); diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 8efce20a547..3bcce07a3a5 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -2192,7 +2192,8 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, } else { Member = HandleField(S, cast<CXXRecordDecl>(CurContext), Loc, D, BitWidth, InitStyle, AS); - assert(Member && "HandleField never returns null"); + if (!Member) + return nullptr; } } else { Member = HandleDeclarator(S, D, TemplateParameterLists); diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 0abe75ab2d8..6322e15826a 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -340,10 +340,15 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc, // See if this is an auto-typed variable whose initializer we are parsing. if (ParsingInitForAutoVars.count(D)) { - const AutoType *AT = cast<VarDecl>(D)->getType()->getContainedAutoType(); + if (isa<BindingDecl>(D)) { + Diag(Loc, diag::err_binding_cannot_appear_in_own_initializer) + << D->getDeclName(); + } else { + const AutoType *AT = cast<VarDecl>(D)->getType()->getContainedAutoType(); - Diag(Loc, diag::err_auto_variable_cannot_appear_in_own_initializer) - << D->getDeclName() << (unsigned)AT->getKeyword(); + Diag(Loc, diag::err_auto_variable_cannot_appear_in_own_initializer) + << D->getDeclName() << (unsigned)AT->getKeyword(); + } return true; } @@ -2939,6 +2944,8 @@ ExprResult Sema::BuildDeclarationNameExpr( case Decl::Var: case Decl::VarTemplateSpecialization: case Decl::VarTemplatePartialSpecialization: + case Decl::Decomposition: + case Decl::Binding: case Decl::OMPCapturedExpr: // In C, "extern void blah;" is valid and is an r-value. if (!getLangOpts().CPlusPlus && diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 6a213953ec9..967c2beec4c 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -598,6 +598,16 @@ TemplateDeclInstantiator::VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) { return Inst; } +Decl *TemplateDeclInstantiator::VisitBindingDecl(BindingDecl *D) { + return BindingDecl::Create(SemaRef.Context, Owner, D->getLocation(), + D->getIdentifier()); +} + +Decl *TemplateDeclInstantiator::VisitDecompositionDecl(DecompositionDecl *D) { + // FIXME: Instantiate bindings and pass them in. + return VisitVarDecl(D, /*InstantiatingVarTemplate=*/false); +} + Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) { return VisitVarDecl(D, /*InstantiatingVarTemplate=*/false); } |