diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index e158284aabeab..32440ee64e3eb 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -215,6 +215,8 @@ Bug Fixes to C++ Support Fixes (`#68490 `_) - Fix a crash when trying to call a varargs function that also has an explicit object parameter. Fixes (`#80971 ICE when explicit object parameter be a function parameter pack`) +- Fixed a bug where abbreviated function templates would append their invented template parameters to + an empty template parameter lists. Bug Fixes to AST Handling ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/include/clang/AST/DeclTemplate.h b/clang/include/clang/AST/DeclTemplate.h index baf71145d99dc..e3b6a7efb1127 100644 --- a/clang/include/clang/AST/DeclTemplate.h +++ b/clang/include/clang/AST/DeclTemplate.h @@ -134,6 +134,7 @@ class TemplateParameterList final const_iterator end() const { return begin() + NumParams; } unsigned size() const { return NumParams; } + bool empty() const { return NumParams == 0; } ArrayRef asArray() { return llvm::ArrayRef(begin(), end()); } ArrayRef asArray() const { diff --git a/clang/lib/AST/DeclPrinter.cpp b/clang/lib/AST/DeclPrinter.cpp index 822ac12c4c7dd..43d221968ea3f 100644 --- a/clang/lib/AST/DeclPrinter.cpp +++ b/clang/lib/AST/DeclPrinter.cpp @@ -1215,6 +1215,10 @@ void DeclPrinter::printTemplateParameters(const TemplateParameterList *Params, bool OmitTemplateKW) { assert(Params); + // Don't print invented template parameter lists. + if (!Params->empty() && Params->getParam(0)->isImplicit()) + return; + if (!OmitTemplateKW) Out << "template "; Out << '<'; diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 18a5d93ab8e8c..2c526cd0d0e67 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -9759,7 +9759,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, SmallVector TemplateParamLists; llvm::append_range(TemplateParamLists, TemplateParamListsRef); if (TemplateParameterList *Invented = D.getInventedTemplateParameterList()) { - if (!TemplateParamLists.empty() && + if (!TemplateParamLists.empty() && !TemplateParamLists.back()->empty() && Invented->getDepth() == TemplateParamLists.back()->getDepth()) TemplateParamLists.back() = Invented; else diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index ab8a967b06a45..fea8c5036c80b 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -19294,7 +19294,16 @@ void Sema::ActOnStartFunctionDeclarationDeclarator( ExplicitLists, /*IsFriend=*/false, IsMemberSpecialization, IsInvalid, /*SuppressDiagnostic=*/true); } - if (ExplicitParams) { + // C++23 [dcl.fct]p23: + // An abbreviated function template can have a template-head. The invented + // template-parameters are appended to the template-parameter-list after + // the explicitly declared template-parameters. + // + // A template-head must have one or more template-parameters (read: + // 'template<>' is *not* a template-head). Only append the invented + // template parameters if we matched the nested-name-specifier to a non-empty + // TemplateParameterList. + if (ExplicitParams && !ExplicitParams->empty()) { Info.AutoTemplateParameterDepth = ExplicitParams->getDepth(); llvm::append_range(Info.TemplateParams, *ExplicitParams); Info.NumExplicitTemplateParams = ExplicitParams->size(); diff --git a/clang/test/AST/ast-print-method-decl.cpp b/clang/test/AST/ast-print-method-decl.cpp index 9f5d112609944..75dea0cac16be 100644 --- a/clang/test/AST/ast-print-method-decl.cpp +++ b/clang/test/AST/ast-print-method-decl.cpp @@ -32,8 +32,7 @@ struct DelegatingCtor2 { // CHECK: struct DelegatingCtor3 { struct DelegatingCtor3 { - // FIXME: template <> should not be output - // CHECK: template <> DelegatingCtor3(auto); + // CHECK: DelegatingCtor3(auto); DelegatingCtor3(auto); // FIXME: Implicitly specialized method should not be output diff --git a/clang/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p23.cpp b/clang/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p23.cpp new file mode 100644 index 0000000000000..469c4e091953c --- /dev/null +++ b/clang/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p23.cpp @@ -0,0 +1,24 @@ +// RUN: %clang_cc1 -std=c++20 -pedantic-errors -verify %s + +// FIXME: This should be an error with -pedantic-errors. +template<> // expected-warning {{extraneous template parameter list in template specialization}} +void f(auto); + +template +void f(auto); + +template +struct A { + void g(auto); +}; + +template +void A::g(auto) { } + +template<> +void A::g(auto) { } + +// FIXME: This should be an error with -pedantic-errors. +template<> +template<> // expected-warning {{extraneous template parameter list in template specialization}} +void A::g(auto) { } diff --git a/clang/test/OpenMP/for_loop_auto.cpp b/clang/test/OpenMP/for_loop_auto.cpp index b2c5540a7785a..4467de6bba18d 100644 --- a/clang/test/OpenMP/for_loop_auto.cpp +++ b/clang/test/OpenMP/for_loop_auto.cpp @@ -10,7 +10,7 @@ #ifndef HEADER #define HEADER -// CHECK: template <> void do_loop(const auto &v) { +// CHECK: void do_loop(const auto &v) { // CHECK-NEXT: #pragma omp parallel for // CHECK-NEXT: for (const auto &i : v) // CHECK-NEXT: ;