diff options
author | Reid Kleckner <rnk@google.com> | 2016-12-09 17:14:05 +0000 |
---|---|---|
committer | Reid Kleckner <rnk@google.com> | 2016-12-09 17:14:05 +0000 |
commit | 078aea904331271c3fdc65b52d128a8acefe4e38 (patch) | |
tree | 0fae177059857ad3ca7c9abba5dfe641151aec7c /clang/lib | |
parent | 1ef90d2f25ca2dc6c538949d4f5d4e6f7de18986 (diff) | |
download | bcm5719-llvm-078aea904331271c3fdc65b52d128a8acefe4e38.tar.gz bcm5719-llvm-078aea904331271c3fdc65b52d128a8acefe4e38.zip |
Store decls in prototypes on the declarator instead of in the AST
This saves two pointers from FunctionDecl that were being used for some
rare and questionable C-only functionality. The DeclsInPrototypeScope
ArrayRef was added in r151712 in order to parse this kind of C code:
enum e {x, y};
int f(enum {y, x} n) {
return x; // should return 1, not 0
}
The challenge is that we parse 'int f(enum {y, x} n)' it its own
function prototype scope that gets popped before we build the
FunctionDecl for 'f'. The original change was doing two questionable
things:
1. Saving all tag decls introduced in prototype scope on a TU-global
Sema variable. This is problematic when you have cases like this, where
'x' and 'y' shouldn't be visible in 'f':
void f(void (*fp)(enum { x, y } e)) { /* no x */ }
This patch fixes that, so now 'f' can't see 'x', which is consistent
with GCC.
2. Storing the decls in FunctionDecl in ActOnFunctionDeclarator so that
they could be used in ActOnStartOfFunctionDef. This is just an
inefficient way to move information around. The AST lives forever, but
the list of non-parameter decls in prototype scope is short lived.
Moving these things to the Declarator solves both of these issues.
Reviewers: rsmith
Subscribers: jmolloy, cfe-commits
Differential Revision: https://reviews.llvm.org/D27279
llvm-svn: 289225
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/AST/ASTDumper.cpp | 5 | ||||
-rw-r--r-- | clang/lib/AST/Decl.cpp | 22 | ||||
-rw-r--r-- | clang/lib/Parse/ParseDecl.cpp | 16 | ||||
-rw-r--r-- | clang/lib/Parse/ParseExpr.cpp | 1 | ||||
-rw-r--r-- | clang/lib/Parse/ParseExprCXX.cpp | 2 | ||||
-rw-r--r-- | clang/lib/Sema/DeclSpec.cpp | 17 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 85 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplateVariadic.cpp | 2 | ||||
-rw-r--r-- | clang/lib/Sema/SemaType.cpp | 3 |
9 files changed, 77 insertions, 76 deletions
diff --git a/clang/lib/AST/ASTDumper.cpp b/clang/lib/AST/ASTDumper.cpp index a3bdd610371..248128861e2 100644 --- a/clang/lib/AST/ASTDumper.cpp +++ b/clang/lib/AST/ASTDumper.cpp @@ -1164,11 +1164,6 @@ void ASTDumper::VisitFunctionDecl(const FunctionDecl *D) { D->getTemplateSpecializationInfo()) dumpTemplateArgumentList(*FTSI->TemplateArguments); - for (ArrayRef<NamedDecl *>::iterator - I = D->getDeclsInPrototypeScope().begin(), - E = D->getDeclsInPrototypeScope().end(); I != E; ++I) - dumpDecl(*I); - if (!D->param_begin() && D->getNumParams()) dumpChild([=] { OS << "<<NULL params x " << D->getNumParams() << ">>"; }); else diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index 2c8061564f4..c3fa1c87aff 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -2840,28 +2840,6 @@ void FunctionDecl::setParams(ASTContext &C, } } -void FunctionDecl::setDeclsInPrototypeScope(ArrayRef<NamedDecl *> NewDecls) { - assert(DeclsInPrototypeScope.empty() && "Already has prototype decls!"); - - if (!NewDecls.empty()) { - NamedDecl **A = new (getASTContext()) NamedDecl*[NewDecls.size()]; - std::copy(NewDecls.begin(), NewDecls.end(), A); - DeclsInPrototypeScope = llvm::makeArrayRef(A, NewDecls.size()); - // Move declarations introduced in prototype to the function context. - for (auto I : NewDecls) { - DeclContext *DC = I->getDeclContext(); - // Forward-declared reference to an enumeration is not added to - // declaration scope, so skip declaration that is absent from its - // declaration contexts. - if (DC->containsDecl(I)) { - DC->removeDecl(I); - I->setDeclContext(this); - addDecl(I); - } - } - } -} - /// getMinRequiredArguments - Returns the minimum number of arguments /// needed to call this function. This may be fewer than the number of /// function parameters, if some of the parameters have default diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index ea7ab267701..9dda75e3f98 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -5827,6 +5827,21 @@ void Parser::ParseFunctionDeclarator(Declarator &D, } } + // Collect non-parameter declarations from the prototype if this is a function + // declaration. They will be moved into the scope of the function. Only do + // this in C and not C++, where the decls will continue to live in the + // surrounding context. + SmallVector<NamedDecl *, 0> DeclsInPrototype; + if (getCurScope()->getFlags() & Scope::FunctionDeclarationScope && + !getLangOpts().CPlusPlus) { + for (Decl *D : getCurScope()->decls()) { + NamedDecl *ND = dyn_cast<NamedDecl>(D); + if (!ND || isa<ParmVarDecl>(ND)) + continue; + DeclsInPrototype.push_back(ND); + } + } + // Remember that we parsed a function type, and remember the attributes. D.AddTypeInfo(DeclaratorChunk::getFunction(HasProto, IsAmbiguous, @@ -5846,6 +5861,7 @@ void Parser::ParseFunctionDeclarator(Declarator &D, NoexceptExpr.isUsable() ? NoexceptExpr.get() : nullptr, ExceptionSpecTokens, + DeclsInPrototype, StartLoc, LocalEndLoc, D, TrailingReturnType), FnAttrs, EndLoc); diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp index 4b0a83446e5..caf2320f8fc 100644 --- a/clang/lib/Parse/ParseExpr.cpp +++ b/clang/lib/Parse/ParseExpr.cpp @@ -2842,6 +2842,7 @@ ExprResult Parser::ParseBlockLiteralExpression() { /*NumExceptions=*/0, /*NoexceptExpr=*/nullptr, /*ExceptionSpecTokens=*/nullptr, + /*DeclsInPrototype=*/None, CaretLoc, CaretLoc, ParamInfo), attrs, CaretLoc); diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp index 83e6ae4ef53..cabc7b5266d 100644 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -1244,6 +1244,7 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( NoexceptExpr.isUsable() ? NoexceptExpr.get() : nullptr, /*ExceptionSpecTokens*/nullptr, + /*DeclsInPrototype=*/None, LParenLoc, FunLocalRangeEnd, D, TrailingReturnType), Attr, DeclEndLoc); @@ -1313,6 +1314,7 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( /*NumExceptions=*/0, /*NoexceptExpr=*/nullptr, /*ExceptionSpecTokens=*/nullptr, + /*DeclsInPrototype=*/None, DeclLoc, DeclEndLoc, D, TrailingReturnType), Attr, DeclEndLoc); diff --git a/clang/lib/Sema/DeclSpec.cpp b/clang/lib/Sema/DeclSpec.cpp index 4107977533d..cc644c7093b 100644 --- a/clang/lib/Sema/DeclSpec.cpp +++ b/clang/lib/Sema/DeclSpec.cpp @@ -173,6 +173,8 @@ DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto, unsigned NumExceptions, Expr *NoexceptExpr, CachedTokens *ExceptionSpecTokens, + ArrayRef<NamedDecl*> + DeclsInPrototype, SourceLocation LocalRangeBegin, SourceLocation LocalRangeEnd, Declarator &TheDeclarator, @@ -204,7 +206,7 @@ DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto, I.Fun.ExceptionSpecType = ESpecType; I.Fun.ExceptionSpecLocBeg = ESpecRange.getBegin().getRawEncoding(); I.Fun.ExceptionSpecLocEnd = ESpecRange.getEnd().getRawEncoding(); - I.Fun.NumExceptions = 0; + I.Fun.NumExceptionsOrDecls = 0; I.Fun.Exceptions = nullptr; I.Fun.NoexceptExpr = nullptr; I.Fun.HasTrailingReturnType = TrailingReturnType.isUsable() || @@ -240,7 +242,7 @@ DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto, case EST_Dynamic: // new[] an exception array if needed if (NumExceptions) { - I.Fun.NumExceptions = NumExceptions; + I.Fun.NumExceptionsOrDecls = NumExceptions; I.Fun.Exceptions = new DeclaratorChunk::TypeAndRange[NumExceptions]; for (unsigned i = 0; i != NumExceptions; ++i) { I.Fun.Exceptions[i].Ty = Exceptions[i]; @@ -257,6 +259,17 @@ DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto, I.Fun.ExceptionSpecTokens = ExceptionSpecTokens; break; } + + if (!DeclsInPrototype.empty()) { + assert(ESpecType == EST_None && NumExceptions == 0 && + "cannot have exception specifiers and decls in prototype"); + I.Fun.NumExceptionsOrDecls = DeclsInPrototype.size(); + // Copy the array of decls into stable heap storage. + I.Fun.DeclsInPrototype = new NamedDecl *[DeclsInPrototype.size()]; + for (size_t J = 0; J < DeclsInPrototype.size(); ++J) + I.Fun.DeclsInPrototype[J] = DeclsInPrototype[J]; + } + return I; } diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 5d13c8fa039..9e764e3f5a7 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -8222,8 +8222,9 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, // Copy the parameter declarations from the declarator D to the function // declaration NewFD, if they are available. First scavenge them into Params. SmallVector<ParmVarDecl*, 16> Params; - if (D.isFunctionDeclarator()) { - DeclaratorChunk::FunctionTypeInfo &FTI = D.getFunctionTypeInfo(); + unsigned FTIIdx; + if (D.isFunctionDeclarator(FTIIdx)) { + DeclaratorChunk::FunctionTypeInfo &FTI = D.getTypeObject(FTIIdx).Fun; // Check for C99 6.7.5.3p10 - foo(void) is a non-varargs // function that takes no arguments, not a function that takes a @@ -8241,6 +8242,19 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, NewFD->setInvalidDecl(); } } + + if (!getLangOpts().CPlusPlus) { + // In C, find all the non-parameter declarations from the prototype and + // move them into the new function decl context as well. Typically they + // will have been added to the surrounding context of the prototype. + for (NamedDecl *NonParmDecl : FTI.getDeclsInPrototype()) { + DeclContext *OldDC = NonParmDecl->getDeclContext(); + if (OldDC->containsDecl(NonParmDecl)) + OldDC->removeDecl(NonParmDecl); + NonParmDecl->setDeclContext(NewFD); + NewFD->addDecl(NonParmDecl); + } + } } else if (const FunctionProtoType *FT = R->getAs<FunctionProtoType>()) { // When we're declaring a function with a typedef, typeof, etc as in the // following example, we'll need to synthesize (unnamed) @@ -8266,15 +8280,6 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, // Finally, we know we have the right number of parameters, install them. NewFD->setParams(Params); - // Find all anonymous symbols defined during the declaration of this function - // and add to NewFD. This lets us track decls such 'enum Y' in: - // - // void f(enum Y {AA} x) {} - // - // which would otherwise incorrectly end up in the translation unit scope. - NewFD->setDeclsInPrototypeScope(DeclsInPrototypeScope); - DeclsInPrototypeScope.clear(); - if (D.getDeclSpec().isNoreturnSpecified()) NewFD->addAttr( ::new(Context) C11NoReturnAttr(D.getDeclSpec().getNoreturnSpecLoc(), @@ -11632,6 +11637,29 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D, CheckParmsForFunctionDef(FD->parameters(), /*CheckParameterNames=*/true); + // Add non-parameter declarations already in the function to the current + // scope. + if (FnBodyScope) { + for (Decl *NPD : FD->decls()) { + auto *NonParmDecl = dyn_cast<NamedDecl>(NPD); + if (!NonParmDecl) + continue; + assert(!isa<ParmVarDecl>(NonParmDecl) && + "parameters should not be in newly created FD yet"); + + // If the decl has a name, make it accessible in the current scope. + if (NonParmDecl->getDeclName()) + PushOnScopeChains(NonParmDecl, FnBodyScope, /*AddToContext=*/false); + + // Similarly, dive into enums and fish their constants out, making them + // accessible in this scope. + if (auto *ED = dyn_cast<EnumDecl>(NonParmDecl)) { + for (auto *EI : ED->enumerators()) + PushOnScopeChains(EI, FnBodyScope, /*AddToContext=*/false); + } + } + } + // Introduce our parameters into the function scope for (auto Param : FD->parameters()) { Param->setOwningFunction(FD); @@ -11644,39 +11672,6 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D, } } - // If we had any tags defined in the function prototype, - // introduce them into the function scope. - if (FnBodyScope) { - for (ArrayRef<NamedDecl *>::iterator - I = FD->getDeclsInPrototypeScope().begin(), - E = FD->getDeclsInPrototypeScope().end(); - I != E; ++I) { - NamedDecl *D = *I; - - // Some of these decls (like enums) may have been pinned to the - // translation unit for lack of a real context earlier. If so, remove - // from the translation unit and reattach to the current context. - if (D->getLexicalDeclContext() == Context.getTranslationUnitDecl()) { - // Is the decl actually in the context? - if (Context.getTranslationUnitDecl()->containsDecl(D)) - Context.getTranslationUnitDecl()->removeDecl(D); - // Either way, reassign the lexical decl context to our FunctionDecl. - D->setLexicalDeclContext(CurContext); - } - - // If the decl has a non-null name, make accessible in the current scope. - if (!D->getName().empty()) - PushOnScopeChains(D, FnBodyScope, /*AddToContext=*/false); - - // Similarly, dive into enums and fish their constants out, making them - // accessible in this scope. - if (auto *ED = dyn_cast<EnumDecl>(D)) { - for (auto *EI : ED->enumerators()) - PushOnScopeChains(EI, FnBodyScope, /*AddToContext=*/false); - } - } - } - // Ensure that the function's exception specification is instantiated. if (const FunctionProtoType *FPT = FD->getType()->getAs<FunctionProtoType>()) ResolveExceptionSpec(D->getLocation(), FPT); @@ -12161,6 +12156,7 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc, /*NumExceptions=*/0, /*NoexceptExpr=*/nullptr, /*ExceptionSpecTokens=*/nullptr, + /*DeclsInPrototype=*/None, Loc, Loc, D), DS.getAttributes(), SourceLocation()); @@ -13430,7 +13426,6 @@ CreateNewDecl: } else if (!PrevDecl) { Diag(Loc, diag::warn_decl_in_param_list) << Context.getTagDeclType(New); } - DeclsInPrototypeScope.push_back(New); } if (Invalid) diff --git a/clang/lib/Sema/SemaTemplateVariadic.cpp b/clang/lib/Sema/SemaTemplateVariadic.cpp index c278639073b..c8bc2c38809 100644 --- a/clang/lib/Sema/SemaTemplateVariadic.cpp +++ b/clang/lib/Sema/SemaTemplateVariadic.cpp @@ -772,7 +772,7 @@ bool Sema::containsUnexpandedParameterPacks(Declarator &D) { } if (Chunk.Fun.getExceptionSpecType() == EST_Dynamic) { - for (unsigned i = 0; i != Chunk.Fun.NumExceptions; ++i) { + for (unsigned i = 0; i != Chunk.Fun.getNumExceptions(); ++i) { if (Chunk.Fun.Exceptions[i] .Ty.get() ->containsUnexpandedParameterPack()) diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 9bfc6ccfdc9..6ea34511212 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -718,6 +718,7 @@ static void maybeSynthesizeBlockSignature(TypeProcessingState &state, /*NumExceptions=*/0, /*NoexceptExpr=*/nullptr, /*ExceptionSpecTokens=*/nullptr, + /*DeclsInPrototype=*/None, loc, loc, declarator)); // For consistency, make sure the state still has us as processing @@ -4469,7 +4470,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, if (FTI.getExceptionSpecType() == EST_Dynamic) { // FIXME: It's rather inefficient to have to split into two vectors // here. - unsigned N = FTI.NumExceptions; + unsigned N = FTI.getNumExceptions(); DynamicExceptions.reserve(N); DynamicExceptionRanges.reserve(N); for (unsigned I = 0; I != N; ++I) { |