From 06b9847147cfb26851368ef6acad5c7d81235a8c Mon Sep 17 00:00:00 2001 From: Reid Kleckner Date: Mon, 15 Dec 2014 23:16:32 +0000 Subject: [PATCH] Diagnose function template definitions inside functions The parser can only be tricked into parsing a function template definition by inserting a typename keyword before the function template declaration. This used to make us crash, and now it's fixed. While here, remove an unneeded boolean parameter from ParseDeclGroup. This boolean always corresponded to non-typedef declarators at file scope. ParseDeclGroup already has precise diagnostics for the function definition typedef case, so we can let that through. Fixes PR21839. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@224287 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Parse/Parser.h | 1 - lib/Parse/ParseDecl.cpp | 8 +++++--- lib/Parse/ParseTemplate.cpp | 10 ++++++++++ lib/Parse/Parser.cpp | 2 +- test/CXX/drs/dr5xx.cpp | 2 +- test/Parser/cxx-template-decl.cpp | 13 +++++++++++++ 6 files changed, 30 insertions(+), 6 deletions(-) diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index ba5c946d35..f12bec6929 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -1728,7 +1728,6 @@ private: ForRangeInit *FRI = nullptr); bool MightBeDeclarator(unsigned Context); DeclGroupPtrTy ParseDeclGroup(ParsingDeclSpec &DS, unsigned Context, - bool AllowFunctionDefinitions, SourceLocation *DeclEnd = nullptr, ForRangeInit *FRI = nullptr); Decl *ParseDeclarationAfterDeclarator(Declarator &D, diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 03e827e69c..0b84f2fbbd 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -1466,7 +1466,7 @@ Parser::ParseSimpleDeclaration(unsigned Context, } DS.takeAttributesFrom(Attrs); - return ParseDeclGroup(DS, Context, /*FunctionDefs=*/ false, &DeclEnd, FRI); + return ParseDeclGroup(DS, Context, &DeclEnd, FRI); } /// Returns true if this might be the start of a declarator, or a common typo @@ -1621,7 +1621,6 @@ void Parser::SkipMalformedDecl() { /// result. Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, unsigned Context, - bool AllowFunctionDefinitions, SourceLocation *DeclEnd, ForRangeInit *FRI) { // Parse the first declarator. @@ -1669,7 +1668,10 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, // start of a function definition in GCC-extended K&R C. !isDeclarationAfterDeclarator()) { - if (AllowFunctionDefinitions) { + // Function definitions are only allowed at file scope and in C++ classes. + // The C++ inline method definition case is handled elsewhere, so we only + // need to handle the file scope definition case. + if (Context == Declarator::FileContext) { if (isStartOfFunctionDefinition(D)) { if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef) { Diag(Tok, diag::err_function_declared_typedef); diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp index ba1f98515e..53de72cd3c 100644 --- a/lib/Parse/ParseTemplate.cpp +++ b/lib/Parse/ParseTemplate.cpp @@ -231,6 +231,16 @@ Parser::ParseSingleDeclarationAfterTemplate( if (DeclaratorInfo.isFunctionDeclarator() && isStartOfFunctionDefinition(DeclaratorInfo)) { + + // Function definitions are only allowed at file scope and in C++ classes. + // The C++ inline method definition case is handled elsewhere, so we only + // need to handle the file scope definition case. + if (Context != Declarator::FileContext) { + Diag(Tok, diag::err_function_definition_not_allowed); + SkipMalformedDecl(); + return nullptr; + } + if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef) { // Recover by ignoring the 'typedef'. This was probably supposed to be // the 'typename' keyword, which we should have already suggested adding diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index 7119e9af76..cf7c0fe32d 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -890,7 +890,7 @@ Parser::ParseDeclOrFunctionDefInternal(ParsedAttributesWithRange &attrs, return Actions.ConvertDeclToDeclGroup(TheDecl); } - return ParseDeclGroup(DS, Declarator::FileContext, true); + return ParseDeclGroup(DS, Declarator::FileContext); } Parser::DeclGroupPtrTy diff --git a/test/CXX/drs/dr5xx.cpp b/test/CXX/drs/dr5xx.cpp index b0254f298e..5bf085f522 100644 --- a/test/CXX/drs/dr5xx.cpp +++ b/test/CXX/drs/dr5xx.cpp @@ -798,7 +798,7 @@ namespace dr575 { // dr575: yes } namespace dr576 { // dr576: yes - typedef void f() {} // expected-error {{function definition is not allowed}} + typedef void f() {} // expected-error {{function definition declared 'typedef'}} void f(typedef int n); // expected-error {{invalid storage class}} void f(char c) { typedef int n; } } diff --git a/test/Parser/cxx-template-decl.cpp b/test/Parser/cxx-template-decl.cpp index bce1b7cbde..efa42ad30d 100644 --- a/test/Parser/cxx-template-decl.cpp +++ b/test/Parser/cxx-template-decl.cpp @@ -211,6 +211,19 @@ void Instantiate() { } +namespace func_tmpl_spec_def_in_func { +// We failed to diagnose function template specialization definitions inside +// functions during recovery previously. +template void FuncTemplate() {} +void TopLevelFunc() { + // expected-error@+2 {{expected a qualified name after 'typename'}} + // expected-error@+1 {{function definition is not allowed here}} + typename template <> void FuncTemplate() { } + // expected-error@+1 {{function definition is not allowed here}} + void NonTemplateInner() { } +} +} + namespace broken_baseclause { template struct base { }; -- 2.40.0