diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2014-03-12 23:14:33 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2014-03-12 23:14:33 +0000 |
commit | 8e6002f3bd52a87d697b348ac5d049898c8214d5 (patch) | |
tree | 2704abd975118fcf98e6cd20b6b270e4331d05bb | |
parent | 8a5a590cd1a058bf7227daf8b0de43a84822200b (diff) | |
download | bcm5719-llvm-8e6002f3bd52a87d697b348ac5d049898c8214d5.tar.gz bcm5719-llvm-8e6002f3bd52a87d697b348ac5d049898c8214d5.zip |
Fix crash if delayed template parsing meets an erroneous trailing return type.
Based on a patch and test by Stephan Tolksdorf! Refactoring and fixing adjacent
brokenness by me.
llvm-svn: 203733
-rw-r--r-- | clang/include/clang/Sema/Sema.h | 10 | ||||
-rw-r--r-- | clang/lib/Parse/Parser.cpp | 28 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 24 | ||||
-rw-r--r-- | clang/test/Parser/DelayedTemplateParsing.cpp | 2 |
4 files changed, 40 insertions, 24 deletions
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index b030002270d..cd87d4e04ee 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -1578,6 +1578,16 @@ public: return D && isa<ObjCMethodDecl>(D); } + /// \brief Determine whether we can delay parsing the body of a function or + /// function template until it is used, assuming we don't care about emitting + /// code for that function. + /// + /// This will be \c false if we may need the body of the function in the + /// middle of parsing an expression (where it's impractical to switch to + /// parsing a different function), for instance, if it's constexpr in C++11 + /// or has an 'auto' return type in C++14. These cases are essentially bugs. + bool canDelayFunctionBody(const Declarator &D); + /// \brief Determine whether we can skip parsing the body of a function /// definition, assuming we don't care about analyzing its body or emitting /// code for that function. diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index e882b0a60b4..9936a5a3abf 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -901,26 +901,6 @@ Parser::ParseDeclarationOrFunctionDefinition(ParsedAttributesWithRange &attrs, } } - -static inline bool isFunctionDeclaratorRequiringReturnTypeDeduction( - const Declarator &D) { - if (!D.isFunctionDeclarator() || !D.getDeclSpec().containsPlaceholderType()) - return false; - for (unsigned I = 0, E = D.getNumTypeObjects(); I != E; ++I) { - unsigned chunkIndex = E - I - 1; - const DeclaratorChunk &DeclType = D.getTypeObject(chunkIndex); - if (DeclType.Kind == DeclaratorChunk::Function) { - const DeclaratorChunk::FunctionTypeInfo &FTI = DeclType.Fun; - if (!FTI.hasTrailingReturnType()) - return true; - QualType TrailingRetType = FTI.getTrailingReturnType().get(); - return TrailingRetType->getCanonicalTypeInternal() - ->getContainedAutoType(); - } - } - return false; -} - /// ParseFunctionDefinition - We parsed and verified that the specified /// Declarator is well formed. If this is a K&R-style function, read the /// parameters declaration-list, then start the compound-statement. @@ -996,8 +976,7 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D, // tokens and store them for late parsing at the end of the translation unit. if (getLangOpts().DelayedTemplateParsing && Tok.isNot(tok::equal) && TemplateInfo.Kind == ParsedTemplateInfo::Template && - !D.getDeclSpec().isConstexprSpecified() && - !isFunctionDeclaratorRequiringReturnTypeDeduction(D)) { + Actions.canDelayFunctionBody(D)) { MultiTemplateParamsArg TemplateParameterLists(*TemplateInfo.TemplateParams); ParseScope BodyScope(this, Scope::FnScope|Scope::DeclScope); @@ -1026,7 +1005,7 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D, Actions.CurContext->isTranslationUnit()) { ParseScope BodyScope(this, Scope::FnScope|Scope::DeclScope); Scope *ParentScope = getCurScope()->getParent(); - + D.setFunctionDefinitionKind(FDK_Definition); Decl *FuncDecl = Actions.HandleDeclarator(ParentScope, D, MultiTemplateParamsArg()); @@ -1038,8 +1017,9 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D, CurParsedObjCImpl->HasCFunction = true; return FuncDecl; } + // FIXME: Should we really fall through here? } - + // Enter a scope for the function body. ParseScope BodyScope(this, Scope::FnScope|Scope::DeclScope); diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 521fc3f2cbc..ec062852789 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -9695,6 +9695,30 @@ void Sema::computeNRVO(Stmt *Body, FunctionScopeInfo *Scope) { const_cast<VarDecl*>(NRVOCandidate)->setNRVOVariable(true); } +bool Sema::canDelayFunctionBody(const Declarator &D) { + // We can't delay parsing the body of a constexpr function template (yet). + if (D.getDeclSpec().isConstexprSpecified()) + return false; + + // We can't delay parsing the body of a function template with a deduced + // return type (yet). + if (D.getDeclSpec().containsPlaceholderType()) { + // If the placeholder introduces a non-deduced trailing return type, + // we can still delay parsing it. + if (D.getNumTypeObjects()) { + const auto &Outer = D.getTypeObject(D.getNumTypeObjects() - 1); + if (Outer.Kind == DeclaratorChunk::Function && + Outer.Fun.hasTrailingReturnType()) { + QualType Ty = GetTypeFromParser(Outer.Fun.getTrailingReturnType()); + return Ty.isNull() || !Ty->isUndeducedType(); + } + } + return false; + } + + return true; +} + bool Sema::canSkipFunctionBody(Decl *D) { // We cannot skip the body of a function (or function template) which is // constexpr, since we may need to evaluate its body in order to parse the diff --git a/clang/test/Parser/DelayedTemplateParsing.cpp b/clang/test/Parser/DelayedTemplateParsing.cpp index 73128c49f24..29af6a01e9c 100644 --- a/clang/test/Parser/DelayedTemplateParsing.cpp +++ b/clang/test/Parser/DelayedTemplateParsing.cpp @@ -121,3 +121,5 @@ constexpr T Fun(T A) { return T(0); } constexpr int Var = Fun(20); } +template <typename T> +auto invalidTrailingRetType() -> Bogus {} // expected-error {{unknown type name 'Bogus'}} |