r203733 - Fix crash if delayed template parsing meets an erroneous trailing return type.
Richard Smith
richard-llvm at metafoo.co.uk
Wed Mar 12 16:14:33 PDT 2014
Author: rsmith
Date: Wed Mar 12 18:14:33 2014
New Revision: 203733
URL: http://llvm.org/viewvc/llvm-project?rev=203733&view=rev
Log:
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.
Modified:
cfe/trunk/include/clang/Sema/Sema.h
cfe/trunk/lib/Parse/Parser.cpp
cfe/trunk/lib/Sema/SemaDecl.cpp
cfe/trunk/test/Parser/DelayedTemplateParsing.cpp
Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=203733&r1=203732&r2=203733&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Wed Mar 12 18:14:33 2014
@@ -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.
Modified: cfe/trunk/lib/Parse/Parser.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/Parser.cpp?rev=203733&r1=203732&r2=203733&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/Parser.cpp (original)
+++ cfe/trunk/lib/Parse/Parser.cpp Wed Mar 12 18:14:33 2014
@@ -901,26 +901,6 @@ Parser::ParseDeclarationOrFunctionDefini
}
}
-
-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(Pa
// 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(Pa
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(Pa
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);
Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=203733&r1=203732&r2=203733&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Wed Mar 12 18:14:33 2014
@@ -9695,6 +9695,30 @@ void Sema::computeNRVO(Stmt *Body, Funct
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
Modified: cfe/trunk/test/Parser/DelayedTemplateParsing.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/DelayedTemplateParsing.cpp?rev=203733&r1=203732&r2=203733&view=diff
==============================================================================
--- cfe/trunk/test/Parser/DelayedTemplateParsing.cpp (original)
+++ cfe/trunk/test/Parser/DelayedTemplateParsing.cpp Wed Mar 12 18:14:33 2014
@@ -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'}}
More information about the cfe-commits
mailing list