diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index ec9e3ef07057f..efd925e990f43 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -144,6 +144,8 @@ Improvements to Clang's diagnostics - Clang now applies syntax highlighting to the code snippets it prints. +- Clang now diagnoses member template declarations with multiple declarators. + Improvements to Clang's time-trace ---------------------------------- diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 4a066acf511a1..da18cf88edcc9 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -2423,6 +2423,7 @@ class Parser : public CodeCompletionHandler { bool MightBeDeclarator(DeclaratorContext Context); DeclGroupPtrTy ParseDeclGroup(ParsingDeclSpec &DS, DeclaratorContext Context, ParsedAttributes &Attrs, + ParsedTemplateInfo &TemplateInfo, SourceLocation *DeclEnd = nullptr, ForRangeInit *FRI = nullptr); Decl *ParseDeclarationAfterDeclarator(Declarator &D, @@ -3615,16 +3616,15 @@ class Parser : public CodeCompletionHandler { // C++ 14: Templates [temp] // C++ 14.1: Template Parameters [temp.param] - Decl *ParseDeclarationStartingWithTemplate(DeclaratorContext Context, - SourceLocation &DeclEnd, - ParsedAttributes &AccessAttrs, - AccessSpecifier AS = AS_none); - Decl *ParseTemplateDeclarationOrSpecialization(DeclaratorContext Context, - SourceLocation &DeclEnd, - ParsedAttributes &AccessAttrs, - AccessSpecifier AS); - Decl *ParseSingleDeclarationAfterTemplate( - DeclaratorContext Context, const ParsedTemplateInfo &TemplateInfo, + DeclGroupPtrTy + ParseDeclarationStartingWithTemplate(DeclaratorContext Context, + SourceLocation &DeclEnd, + ParsedAttributes &AccessAttrs); + DeclGroupPtrTy ParseTemplateDeclarationOrSpecialization( + DeclaratorContext Context, SourceLocation &DeclEnd, + ParsedAttributes &AccessAttrs, AccessSpecifier AS); + DeclGroupPtrTy ParseDeclarationAfterTemplate( + DeclaratorContext Context, ParsedTemplateInfo &TemplateInfo, ParsingDeclRAIIObject &DiagsFromParams, SourceLocation &DeclEnd, ParsedAttributes &AccessAttrs, AccessSpecifier AS = AS_none); bool ParseTemplateParameters(MultiParseScope &TemplateScopes, unsigned Depth, @@ -3673,12 +3673,12 @@ class Parser : public CodeCompletionHandler { TemplateTy Template, SourceLocation OpenLoc); ParsedTemplateArgument ParseTemplateTemplateArgument(); ParsedTemplateArgument ParseTemplateArgument(); - Decl *ParseExplicitInstantiation(DeclaratorContext Context, - SourceLocation ExternLoc, - SourceLocation TemplateLoc, - SourceLocation &DeclEnd, - ParsedAttributes &AccessAttrs, - AccessSpecifier AS = AS_none); + DeclGroupPtrTy ParseExplicitInstantiation(DeclaratorContext Context, + SourceLocation ExternLoc, + SourceLocation TemplateLoc, + SourceLocation &DeclEnd, + ParsedAttributes &AccessAttrs, + AccessSpecifier AS = AS_none); // C++2a: Template, concept definition [temp] Decl * ParseConceptDefinition(const ParsedTemplateInfo &TemplateInfo, diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index bcbe2d9c635a6..a186253954f68 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -1916,9 +1916,7 @@ Parser::DeclGroupPtrTy Parser::ParseDeclaration(DeclaratorContext Context, case tok::kw_export: ProhibitAttributes(DeclAttrs); ProhibitAttributes(DeclSpecAttrs); - SingleDecl = - ParseDeclarationStartingWithTemplate(Context, DeclEnd, DeclAttrs); - break; + return ParseDeclarationStartingWithTemplate(Context, DeclEnd, DeclAttrs); case tok::kw_inline: // Could be the start of an inline namespace. Allowed as an ext in C++03. if (getLangOpts().CPlusPlus && NextToken().is(tok::kw_namespace)) { @@ -1994,8 +1992,9 @@ Parser::DeclGroupPtrTy Parser::ParseSimpleDeclaration( ParsingDeclSpec DS(*this); DS.takeAttributesFrom(DeclSpecAttrs); + ParsedTemplateInfo TemplateInfo; DeclSpecContext DSContext = getDeclSpecContextFromDeclaratorContext(Context); - ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS_none, DSContext); + ParseDeclarationSpecifiers(DS, TemplateInfo, AS_none, DSContext); // If we had a free-standing type definition with a missing semicolon, we // may get this far before the problem becomes obvious. @@ -2027,7 +2026,7 @@ Parser::DeclGroupPtrTy Parser::ParseSimpleDeclaration( if (DeclSpecStart) DS.SetRangeStart(*DeclSpecStart); - return ParseDeclGroup(DS, Context, DeclAttrs, &DeclEnd, FRI); + return ParseDeclGroup(DS, Context, DeclAttrs, TemplateInfo, &DeclEnd, FRI); } /// Returns true if this might be the start of a declarator, or a common typo @@ -2184,6 +2183,7 @@ void Parser::SkipMalformedDecl() { Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, DeclaratorContext Context, ParsedAttributes &Attrs, + ParsedTemplateInfo &TemplateInfo, SourceLocation *DeclEnd, ForRangeInit *FRI) { // Parse the first declarator. @@ -2193,8 +2193,19 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, ParsedAttributes LocalAttrs(AttrFactory); LocalAttrs.takeAllFrom(Attrs); ParsingDeclarator D(*this, DS, LocalAttrs, Context); + if (TemplateInfo.TemplateParams) + D.setTemplateParameterLists(*TemplateInfo.TemplateParams); + + bool IsTemplateSpecOrInst = + (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation || + TemplateInfo.Kind == ParsedTemplateInfo::ExplicitSpecialization); + SuppressAccessChecks SAC(*this, IsTemplateSpecOrInst); + ParseDeclarator(D); + if (IsTemplateSpecOrInst) + SAC.done(); + // Bail out if the first declarator didn't seem well-formed. if (!D.hasName() && !D.mayOmitIdentifier()) { SkipMalformedDecl(); @@ -2262,15 +2273,54 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, // need to handle the file scope definition case. if (Context == DeclaratorContext::File) { if (isStartOfFunctionDefinition(D)) { + // C++23 [dcl.typedef] p1: + // The typedef specifier shall not be [...], and it shall not be + // used in the decl-specifier-seq of a parameter-declaration nor in + // the decl-specifier-seq of a function-definition. if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef) { - Diag(Tok, diag::err_function_declared_typedef); - - // Recover by treating the 'typedef' as spurious. + // If the user intended to write 'typename', we should have already + // suggested adding it elsewhere. In any case, recover by ignoring + // 'typedef' and suggest removing it. + Diag(DS.getStorageClassSpecLoc(), + diag::err_function_declared_typedef) + << FixItHint::CreateRemoval(DS.getStorageClassSpecLoc()); DS.ClearStorageClassSpecs(); } + Decl *TheDecl = nullptr; + + if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation) { + if (D.getName().getKind() != UnqualifiedIdKind::IK_TemplateId) { + // If the declarator-id is not a template-id, issue a diagnostic + // and recover by ignoring the 'template' keyword. + Diag(Tok, diag::err_template_defn_explicit_instantiation) << 0; + TheDecl = ParseFunctionDefinition(D, ParsedTemplateInfo(), + &LateParsedAttrs); + } else { + SourceLocation LAngleLoc = + PP.getLocForEndOfToken(TemplateInfo.TemplateLoc); + Diag(D.getIdentifierLoc(), + diag::err_explicit_instantiation_with_definition) + << SourceRange(TemplateInfo.TemplateLoc) + << FixItHint::CreateInsertion(LAngleLoc, "<>"); + + // Recover as if it were an explicit specialization. + TemplateParameterLists FakedParamLists; + FakedParamLists.push_back(Actions.ActOnTemplateParameterList( + 0, SourceLocation(), TemplateInfo.TemplateLoc, LAngleLoc, + std::nullopt, LAngleLoc, nullptr)); + + TheDecl = ParseFunctionDefinition( + D, + ParsedTemplateInfo(&FakedParamLists, + /*isSpecialization=*/true, + /*lastParameterListWasEmpty=*/true), + &LateParsedAttrs); + } + } else { + TheDecl = + ParseFunctionDefinition(D, TemplateInfo, &LateParsedAttrs); + } - Decl *TheDecl = ParseFunctionDefinition(D, ParsedTemplateInfo(), - &LateParsedAttrs); return Actions.ConvertDeclToDeclGroup(TheDecl); } @@ -2360,8 +2410,8 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, } SmallVector DeclsInGroup; - Decl *FirstDecl = ParseDeclarationAfterDeclaratorAndAttributes( - D, ParsedTemplateInfo(), FRI); + Decl *FirstDecl = + ParseDeclarationAfterDeclaratorAndAttributes(D, TemplateInfo, FRI); if (LateParsedAttrs.size() > 0) ParseLexedAttributeList(LateParsedAttrs, FirstDecl, true, false); D.complete(FirstDecl); @@ -2384,6 +2434,16 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, break; } + // C++23 [temp.pre]p5: + // In a template-declaration, explicit specialization, or explicit + // instantiation the init-declarator-list in the declaration shall + // contain at most one declarator. + if (TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate && + D.isFirstDeclarator()) { + Diag(CommaLoc, diag::err_multiple_template_declarators) + << TemplateInfo.Kind; + } + // Parse the next declarator. D.clear(); D.setCommaLoc(CommaLoc); @@ -2413,7 +2473,7 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, // declarator requires-clause if (Tok.is(tok::kw_requires)) ParseTrailingRequiresClause(D); - Decl *ThisDecl = ParseDeclarationAfterDeclarator(D); + Decl *ThisDecl = ParseDeclarationAfterDeclarator(D, TemplateInfo); D.complete(ThisDecl); if (ThisDecl) DeclsInGroup.push_back(ThisDecl); @@ -6526,6 +6586,17 @@ void Parser::ParseDirectDeclarator(Declarator &D) { /*ObjectHasErrors=*/false, EnteringContext); } + // C++23 [basic.scope.namespace]p1: + // For each non-friend redeclaration or specialization whose target scope + // is or is contained by the scope, the portion after the declarator-id, + // class-head-name, or enum-head-name is also included in the scope. + // C++23 [basic.scope.class]p1: + // For each non-friend redeclaration or specialization whose target scope + // is or is contained by the scope, the portion after the declarator-id, + // class-head-name, or enum-head-name is also included in the scope. + // + // FIXME: We should not be doing this for friend declarations; they have + // their own special lookup semantics specified by [basic.lookup.unqual]p6. if (D.getCXXScopeSpec().isValid()) { if (Actions.ShouldEnterDeclaratorScope(getCurScope(), D.getCXXScopeSpec())) diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index 06ccc1e3d04e9..cdbfbb1bc9fff 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -2855,7 +2855,7 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, } // static_assert-declaration. A templated static_assert declaration is - // diagnosed in Parser::ParseSingleDeclarationAfterTemplate. + // diagnosed in Parser::ParseDeclarationAfterTemplate. if (!TemplateInfo.Kind && Tok.isOneOf(tok::kw_static_assert, tok::kw__Static_assert)) { SourceLocation DeclEnd; @@ -2868,9 +2868,8 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, "Nested template improperly parsed?"); ObjCDeclContextSwitch ObjCDC(*this); SourceLocation DeclEnd; - return DeclGroupPtrTy::make( - DeclGroupRef(ParseTemplateDeclarationOrSpecialization( - DeclaratorContext::Member, DeclEnd, AccessAttrs, AS))); + return ParseTemplateDeclarationOrSpecialization(DeclaratorContext::Member, + DeclEnd, AccessAttrs, AS); } // Handle: member-declaration ::= '__extension__' member-declaration @@ -3279,6 +3278,16 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, break; } + // C++23 [temp.pre]p5: + // In a template-declaration, explicit specialization, or explicit + // instantiation the init-declarator-list in the declaration shall + // contain at most one declarator. + if (TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate && + DeclaratorInfo.isFirstDeclarator()) { + Diag(CommaLoc, diag::err_multiple_template_declarators) + << TemplateInfo.Kind; + } + // Parse the next declarator. DeclaratorInfo.clear(); VS.clear(); @@ -4228,6 +4237,24 @@ void Parser::ParseTrailingRequiresClause(Declarator &D) { SourceLocation RequiresKWLoc = ConsumeToken(); + // C++23 [basic.scope.namespace]p1: + // For each non-friend redeclaration or specialization whose target scope + // is or is contained by the scope, the portion after the declarator-id, + // class-head-name, or enum-head-name is also included in the scope. + // C++23 [basic.scope.class]p1: + // For each non-friend redeclaration or specialization whose target scope + // is or is contained by the scope, the portion after the declarator-id, + // class-head-name, or enum-head-name is also included in the scope. + // + // FIXME: We should really be calling ParseTrailingRequiresClause in + // ParseDirectDeclarator, when we are already in the declarator scope. + // This would also correctly suppress access checks for specializations + // and explicit instantiations, which we currently do not do. + CXXScopeSpec &SS = D.getCXXScopeSpec(); + DeclaratorScopeObj DeclScopeObj(*this, SS); + if (SS.isValid() && Actions.ShouldEnterDeclaratorScope(getCurScope(), SS)) + DeclScopeObj.EnterDeclaratorScope(); + ExprResult TrailingRequiresClause; ParseScope ParamScope(this, Scope::DeclScope | Scope::FunctionDeclarationScope | diff --git a/clang/lib/Parse/ParseTemplate.cpp b/clang/lib/Parse/ParseTemplate.cpp index 64fe4d50bba27..d4897f8f66072 100644 --- a/clang/lib/Parse/ParseTemplate.cpp +++ b/clang/lib/Parse/ParseTemplate.cpp @@ -36,17 +36,19 @@ unsigned Parser::ReenterTemplateScopes(MultiParseScope &S, Decl *D) { /// Parse a template declaration, explicit instantiation, or /// explicit specialization. -Decl *Parser::ParseDeclarationStartingWithTemplate( - DeclaratorContext Context, SourceLocation &DeclEnd, - ParsedAttributes &AccessAttrs, AccessSpecifier AS) { +Parser::DeclGroupPtrTy +Parser::ParseDeclarationStartingWithTemplate(DeclaratorContext Context, + SourceLocation &DeclEnd, + ParsedAttributes &AccessAttrs) { ObjCDeclContextSwitch ObjCDC(*this); if (Tok.is(tok::kw_template) && NextToken().isNot(tok::less)) { return ParseExplicitInstantiation(Context, SourceLocation(), ConsumeToken(), - DeclEnd, AccessAttrs, AS); + DeclEnd, AccessAttrs, + AccessSpecifier::AS_none); } return ParseTemplateDeclarationOrSpecialization(Context, DeclEnd, AccessAttrs, - AS); + AccessSpecifier::AS_none); } /// Parse a template declaration or an explicit specialization. @@ -73,7 +75,7 @@ Decl *Parser::ParseDeclarationStartingWithTemplate( /// /// explicit-specialization: [ C++ temp.expl.spec] /// 'template' '<' '>' declaration -Decl *Parser::ParseTemplateDeclarationOrSpecialization( +Parser::DeclGroupPtrTy Parser::ParseTemplateDeclarationOrSpecialization( DeclaratorContext Context, SourceLocation &DeclEnd, ParsedAttributes &AccessAttrs, AccessSpecifier AS) { assert(Tok.isOneOf(tok::kw_export, tok::kw_template) && @@ -161,17 +163,16 @@ Decl *Parser::ParseTemplateDeclarationOrSpecialization( TemplateParams, RAngleLoc, OptionalRequiresClauseConstraintER.get())); } while (Tok.isOneOf(tok::kw_export, tok::kw_template)); + ParsedTemplateInfo TemplateInfo(&ParamLists, isSpecialization, + LastParamListWasEmpty); + // Parse the actual template declaration. if (Tok.is(tok::kw_concept)) - return ParseConceptDefinition( - ParsedTemplateInfo(&ParamLists, isSpecialization, - LastParamListWasEmpty), - DeclEnd); - - return ParseSingleDeclarationAfterTemplate( - Context, - ParsedTemplateInfo(&ParamLists, isSpecialization, LastParamListWasEmpty), - ParsingTemplateParams, DeclEnd, AccessAttrs, AS); + return Actions.ConvertDeclToDeclGroup( + ParseConceptDefinition(TemplateInfo, DeclEnd)); + + return ParseDeclarationAfterTemplate( + Context, TemplateInfo, ParsingTemplateParams, DeclEnd, AccessAttrs, AS); } /// Parse a single declaration that declares a template, @@ -184,8 +185,8 @@ Decl *Parser::ParseTemplateDeclarationOrSpecialization( /// declaration. Will be AS_none for namespace-scope declarations. /// /// \returns the new declaration. -Decl *Parser::ParseSingleDeclarationAfterTemplate( - DeclaratorContext Context, const ParsedTemplateInfo &TemplateInfo, +Parser::DeclGroupPtrTy Parser::ParseDeclarationAfterTemplate( + DeclaratorContext Context, ParsedTemplateInfo &TemplateInfo, ParsingDeclRAIIObject &DiagsFromTParams, SourceLocation &DeclEnd, ParsedAttributes &AccessAttrs, AccessSpecifier AS) { assert(TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate && @@ -196,37 +197,29 @@ Decl *Parser::ParseSingleDeclarationAfterTemplate( Diag(Tok.getLocation(), diag::err_templated_invalid_declaration) << TemplateInfo.getSourceRange(); // Parse the static_assert declaration to improve error recovery. - return ParseStaticAssertDeclaration(DeclEnd); + return Actions.ConvertDeclToDeclGroup( + ParseStaticAssertDeclaration(DeclEnd)); } - if (Context == DeclaratorContext::Member) { - // We are parsing a member template. - DeclGroupPtrTy D = ParseCXXClassMemberDeclaration( - AS, AccessAttrs, TemplateInfo, &DiagsFromTParams); + // We are parsing a member template. + if (Context == DeclaratorContext::Member) + return ParseCXXClassMemberDeclaration(AS, AccessAttrs, TemplateInfo, + &DiagsFromTParams); - if (!D || !D.get().isSingleDecl()) - return nullptr; - return D.get().getSingleDecl(); - } - - ParsedAttributes prefixAttrs(AttrFactory); + ParsedAttributes DeclAttrs(AttrFactory); ParsedAttributes DeclSpecAttrs(AttrFactory); // GNU attributes are applied to the declaration specification while the // standard attributes are applied to the declaration. We parse the two // attribute sets into different containters so we can apply them during // the regular parsing process. - while (MaybeParseCXX11Attributes(prefixAttrs) || + while (MaybeParseCXX11Attributes(DeclAttrs) || MaybeParseGNUAttributes(DeclSpecAttrs)) ; - if (Tok.is(tok::kw_using)) { - auto usingDeclPtr = ParseUsingDirectiveOrDeclaration(Context, TemplateInfo, DeclEnd, - prefixAttrs); - if (!usingDeclPtr || !usingDeclPtr.get().isSingleDecl()) - return nullptr; - return usingDeclPtr.get().getSingleDecl(); - } + if (Tok.is(tok::kw_using)) + return ParseUsingDirectiveOrDeclaration(Context, TemplateInfo, DeclEnd, + DeclAttrs); // Parse the declaration specifiers, stealing any diagnostics from // the template parameters. @@ -239,7 +232,7 @@ Decl *Parser::ParseSingleDeclarationAfterTemplate( getDeclSpecContextFromDeclaratorContext(Context)); if (Tok.is(tok::semi)) { - ProhibitAttributes(prefixAttrs); + ProhibitAttributes(DeclAttrs); DeclEnd = ConsumeToken(); RecordDecl *AnonRecord = nullptr; Decl *Decl = Actions.ParsedFreeStandingDeclSpec( @@ -252,7 +245,7 @@ Decl *Parser::ParseSingleDeclarationAfterTemplate( assert(!AnonRecord && "Anonymous unions/structs should not be valid with template"); DS.complete(Decl); - return Decl; + return Actions.ConvertDeclToDeclGroup(Decl); } if (DS.hasTagDefinition()) @@ -260,125 +253,9 @@ Decl *Parser::ParseSingleDeclarationAfterTemplate( // Move the attributes from the prefix into the DS. if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation) - ProhibitAttributes(prefixAttrs); - - // Parse the declarator. - ParsingDeclarator DeclaratorInfo(*this, DS, prefixAttrs, - (DeclaratorContext)Context); - if (TemplateInfo.TemplateParams) - DeclaratorInfo.setTemplateParameterLists(*TemplateInfo.TemplateParams); - - // Turn off usual access checking for template specializations and - // instantiations. - // C++20 [temp.spec] 13.9/6. - // This disables the access checking rules for function template explicit - // instantiation and explicit specialization: - // - parameter-list; - // - template-argument-list; - // - noexcept-specifier; - // - dynamic-exception-specifications (deprecated in C++11, removed since - // C++17). - bool IsTemplateSpecOrInst = - (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation || - TemplateInfo.Kind == ParsedTemplateInfo::ExplicitSpecialization); - SuppressAccessChecks SAC(*this, IsTemplateSpecOrInst); - - ParseDeclarator(DeclaratorInfo); - - if (IsTemplateSpecOrInst) - SAC.done(); - - // Error parsing the declarator? - if (!DeclaratorInfo.hasName()) { - SkipMalformedDecl(); - return nullptr; - } - - LateParsedAttrList LateParsedAttrs(true); - if (DeclaratorInfo.isFunctionDeclarator()) { - if (Tok.is(tok::kw_requires)) { - CXXScopeSpec &ScopeSpec = DeclaratorInfo.getCXXScopeSpec(); - DeclaratorScopeObj DeclScopeObj(*this, ScopeSpec); - if (ScopeSpec.isValid() && - Actions.ShouldEnterDeclaratorScope(getCurScope(), ScopeSpec)) - DeclScopeObj.EnterDeclaratorScope(); - ParseTrailingRequiresClause(DeclaratorInfo); - } - - MaybeParseGNUAttributes(DeclaratorInfo, &LateParsedAttrs); - } - - if (DeclaratorInfo.isFunctionDeclarator() && - isStartOfFunctionDefinition(DeclaratorInfo)) { + ProhibitAttributes(DeclAttrs); - // 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 != DeclaratorContext::File) { - 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 - // if it's appropriate. - Diag(DS.getStorageClassSpecLoc(), diag::err_function_declared_typedef) - << FixItHint::CreateRemoval(DS.getStorageClassSpecLoc()); - DS.ClearStorageClassSpecs(); - } - - if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation) { - if (DeclaratorInfo.getName().getKind() != - UnqualifiedIdKind::IK_TemplateId) { - // If the declarator-id is not a template-id, issue a diagnostic and - // recover by ignoring the 'template' keyword. - Diag(Tok, diag::err_template_defn_explicit_instantiation) << 0; - return ParseFunctionDefinition(DeclaratorInfo, ParsedTemplateInfo(), - &LateParsedAttrs); - } else { - SourceLocation LAngleLoc - = PP.getLocForEndOfToken(TemplateInfo.TemplateLoc); - Diag(DeclaratorInfo.getIdentifierLoc(), - diag::err_explicit_instantiation_with_definition) - << SourceRange(TemplateInfo.TemplateLoc) - << FixItHint::CreateInsertion(LAngleLoc, "<>"); - - // Recover as if it were an explicit specialization. - TemplateParameterLists FakedParamLists; - FakedParamLists.push_back(Actions.ActOnTemplateParameterList( - 0, SourceLocation(), TemplateInfo.TemplateLoc, LAngleLoc, - std::nullopt, LAngleLoc, nullptr)); - - return ParseFunctionDefinition( - DeclaratorInfo, ParsedTemplateInfo(&FakedParamLists, - /*isSpecialization=*/true, - /*lastParameterListWasEmpty=*/true), - &LateParsedAttrs); - } - } - return ParseFunctionDefinition(DeclaratorInfo, TemplateInfo, - &LateParsedAttrs); - } - - // Parse this declaration. - Decl *ThisDecl = ParseDeclarationAfterDeclarator(DeclaratorInfo, - TemplateInfo); - - if (Tok.is(tok::comma)) { - Diag(Tok, diag::err_multiple_template_declarators) - << (int)TemplateInfo.Kind; - SkipUntil(tok::semi); - return ThisDecl; - } - - // Eat the semi colon after the declaration. - ExpectAndConsumeSemi(diag::err_expected_semi_declaration); - if (LateParsedAttrs.size() > 0) - ParseLexedAttributeList(LateParsedAttrs, ThisDecl, true, false); - DeclaratorInfo.complete(ThisDecl); - return ThisDecl; + return ParseDeclGroup(DS, Context, DeclAttrs, TemplateInfo, &DeclEnd); } /// \brief Parse a single declaration that declares a concept. @@ -1686,19 +1563,16 @@ bool Parser::ParseTemplateArgumentList(TemplateArgList &TemplateArgs, /// 'extern' [opt] 'template' declaration /// /// Note that the 'extern' is a GNU extension and C++11 feature. -Decl *Parser::ParseExplicitInstantiation(DeclaratorContext Context, - SourceLocation ExternLoc, - SourceLocation TemplateLoc, - SourceLocation &DeclEnd, - ParsedAttributes &AccessAttrs, - AccessSpecifier AS) { +Parser::DeclGroupPtrTy Parser::ParseExplicitInstantiation( + DeclaratorContext Context, SourceLocation ExternLoc, + SourceLocation TemplateLoc, SourceLocation &DeclEnd, + ParsedAttributes &AccessAttrs, AccessSpecifier AS) { // This isn't really required here. ParsingDeclRAIIObject ParsingTemplateParams(*this, ParsingDeclRAIIObject::NoParent); - - return ParseSingleDeclarationAfterTemplate( - Context, ParsedTemplateInfo(ExternLoc, TemplateLoc), - ParsingTemplateParams, DeclEnd, AccessAttrs, AS); + ParsedTemplateInfo TemplateInfo(ExternLoc, TemplateLoc); + return ParseDeclarationAfterTemplate( + Context, TemplateInfo, ParsingTemplateParams, DeclEnd, AccessAttrs, AS); } SourceRange Parser::ParsedTemplateInfo::getSourceRange() const { diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index 3dfd44677e5a2..2dd4a73bfbc26 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -1040,8 +1040,8 @@ Parser::ParseExternalDeclaration(ParsedAttributes &Attrs, diag::warn_cxx98_compat_extern_template : diag::ext_extern_template) << SourceRange(ExternLoc, TemplateLoc); SourceLocation DeclEnd; - return Actions.ConvertDeclToDeclGroup(ParseExplicitInstantiation( - DeclaratorContext::File, ExternLoc, TemplateLoc, DeclEnd, Attrs)); + return ParseExplicitInstantiation(DeclaratorContext::File, ExternLoc, + TemplateLoc, DeclEnd, Attrs); } goto dont_know; @@ -1143,9 +1143,10 @@ Parser::DeclGroupPtrTy Parser::ParseDeclOrFunctionDefInternal( DS.SetRangeEnd(DeclSpecAttrs.Range.getEnd()); DS.takeAttributesFrom(DeclSpecAttrs); + ParsedTemplateInfo TemplateInfo; MaybeParseMicrosoftAttributes(DS.getAttributes()); // Parse the common declaration-specifiers piece. - ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS, + ParseDeclarationSpecifiers(DS, TemplateInfo, AS, DeclSpecContext::DSC_top_level); // If we had a free-standing type definition with a missing semicolon, we @@ -1241,7 +1242,7 @@ Parser::DeclGroupPtrTy Parser::ParseDeclOrFunctionDefInternal( return Actions.ConvertDeclToDeclGroup(TheDecl); } - return ParseDeclGroup(DS, DeclaratorContext::File, Attrs); + return ParseDeclGroup(DS, DeclaratorContext::File, Attrs, TemplateInfo); } Parser::DeclGroupPtrTy Parser::ParseDeclarationOrFunctionDefinition( diff --git a/clang/test/CXX/temp/p3.cpp b/clang/test/CXX/temp/p3.cpp index b708c613d352d..9e561d0b9a83b 100644 --- a/clang/test/CXX/temp/p3.cpp +++ b/clang/test/CXX/temp/p3.cpp @@ -15,3 +15,9 @@ template struct B { } f(); // expected-error {{expected ';' after st template struct C { } // expected-error {{expected ';' after struct}} A c; + +struct D { + template static const int x = 0, f(); // expected-error {{can only declare a single entity}} + + template static const int g(), y = 0; // expected-error {{can only declare a single entity}} +}; diff --git a/clang/test/OpenMP/declare_simd_messages.cpp b/clang/test/OpenMP/declare_simd_messages.cpp index dd24322694b69..fea045400e1fa 100644 --- a/clang/test/OpenMP/declare_simd_messages.cpp +++ b/clang/test/OpenMP/declare_simd_messages.cpp @@ -33,10 +33,9 @@ int main(); int main(); struct A { -// expected-error@+1 {{function declaration is expected after 'declare simd' directive}} #pragma omp declare simd template - T infunc1(T a), infunc2(T a); + T infunc1(T a); }; // expected-error@+1 {{single declaration is expected after 'declare simd' directive}}