https://github.com/philnik777 updated https://github.com/llvm/llvm-project/pull/200670
>From 9891738fa1ad6d78932484c81e65d62245adf154 Mon Sep 17 00:00:00 2001 From: Nikolas Klauser <[email protected]> Date: Sun, 31 May 2026 17:52:02 +0200 Subject: [PATCH 1/4] [Clang] Accept auto parameters in all language modes as an extension --- .../clang/Basic/DiagnosticSemaKinds.td | 3 ++ clang/lib/Sema/SemaType.cpp | 13 +++-- .../dcl.spec/dcl.type/dcl.spec.auto/p5.cpp | 6 +-- clang/test/CXX/dcl/dcl.fct/p17.cpp | 42 ++++++++------- clang/test/CXX/drs/cwg6xx.cpp | 3 +- clang/test/Parser/cxx1z-decomposition.cpp | 2 +- clang/test/SemaCXX/crash-GH173943.cpp | 4 +- .../SemaCXX/deduced-return-type-cxx14.cpp | 51 +++++++++---------- 8 files changed, 67 insertions(+), 57 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 077aace321264..6d566d40d3b41 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -2667,6 +2667,9 @@ def err_auto_not_allowed : Error< "|in declaration of conversion function template" "|in lambda parameter before C++14}1">; +def ext_auto_arg : ExtWarn< + "'auto' parameters are a C++20 extension">, InGroup<CXX20>; + def err_dependent_deduced_tst : Error< "typename specifier refers to " "%select{class template|function template|variable template|alias template|" diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 44ac4f6630690..5ec96aa1bfba4 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -3262,6 +3262,10 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state, (Auto && Auto->getKeyword() != AutoTypeKeyword::GNUAutoType); bool IsDeducedReturnType = false; + SourceRange AutoRange = D.getDeclSpec().getTypeSpecTypeLoc(); + if (D.getName().getKind() == UnqualifiedIdKind::IK_ConversionFunctionId) + AutoRange = D.getName().getSourceRange(); + switch (D.getContext()) { case DeclaratorContext::LambdaExpr: // Declared return type of a lambda-declarator is implicit and is always @@ -3279,7 +3283,7 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state, InventedTemplateParameterInfo *Info = nullptr; if (D.getContext() == DeclaratorContext::Prototype) { // With concepts we allow 'auto' in function parameters. - if (!SemaRef.getLangOpts().CPlusPlus20 || !Auto || + if (!SemaRef.getLangOpts().CPlusPlus || !Auto || Auto->getKeyword() != AutoTypeKeyword::Auto) { Error = 0; break; @@ -3288,6 +3292,9 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state, break; } + if (!SemaRef.getLangOpts().CPlusPlus20) + SemaRef.Diag(AutoRange.getBegin(), diag::ext_auto_arg); + Info = &SemaRef.InventedParameterInfos.back(); } else { // In C++14, generic lambdas allow 'auto' in their parameters. @@ -3419,10 +3426,6 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state, (!SemaRef.getLangOpts().CPlusPlus11 || !IsCXXAutoType)) Error = 13; - SourceRange AutoRange = D.getDeclSpec().getTypeSpecTypeLoc(); - if (D.getName().getKind() == UnqualifiedIdKind::IK_ConversionFunctionId) - AutoRange = D.getName().getSourceRange(); - if (Error != -1) { unsigned Kind; if (Auto) { diff --git a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp index 9571d6670e70d..3c5490605e19f 100644 --- a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp +++ b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp @@ -19,17 +19,17 @@ typedef auto *AutoPtr; // expected-error{{'auto' not allowed in typedef}} typedef auto (*PFun)(int a); // expected-error{{'auto' not allowed in typedef}} typedef auto Fun(int a) -> decltype(a + a); -void g(auto a) { // expected-error{{'auto' not allowed in function prototype}} +void g(auto a) { // expected-warning{{'auto' parameters are a C++20 extension}} try { } catch (auto &a) { } // expected-error{{'auto' not allowed in exception declaration}} catch (const auto a) { } // expected-error{{'auto' not allowed in exception declaration}} try { } catch (auto a) { } // expected-error{{'auto' not allowed in exception declaration}} } -void h(auto a[10]) { // expected-error{{'auto' not allowed in function prototype}} +void h(auto a[10]) { // expected-warning{{'auto' parameters are a C++20 extension}} } -void i(const auto a) { // expected-error{{'auto' not allowed in function prototype}} +void i(const auto a) { // expected-warning{{'auto' parameters are a C++20 extension}} } namespace std { diff --git a/clang/test/CXX/dcl/dcl.fct/p17.cpp b/clang/test/CXX/dcl/dcl.fct/p17.cpp index 431a8fbdf38a0..703a058d9d905 100644 --- a/clang/test/CXX/dcl/dcl.fct/p17.cpp +++ b/clang/test/CXX/dcl/dcl.fct/p17.cpp @@ -1,4 +1,6 @@ -// RUN: %clang_cc1 -std=c++2a -verify %s +// RUN: %clang_cc1 -std=c++17 -verify=expected,ext %s +// RUN: %clang_cc1 -std=c++20 -verify %s + template<typename T, typename U> constexpr bool is_same_v = false; template<typename T> constexpr bool is_same_v<T, T> = true; @@ -6,27 +8,27 @@ template<typename... T> struct type_list; namespace unconstrained { - decltype(auto) f1(auto x) { return x; } + decltype(auto) f1(auto x) { return x; } // ext-warning {{'auto' parameters are a C++20 extension}} static_assert(is_same_v<decltype(f1(1)), int>); static_assert(is_same_v<decltype(f1('c')), char>); - decltype(auto) f2(auto &x) { return x; } + decltype(auto) f2(auto &x) { return x; } // ext-warning {{'auto' parameters are a C++20 extension}} // expected-note@-1{{candidate function [with x:auto = int] not viable: expects an lvalue for 1st argument}} // expected-note@-2{{candidate function [with x:auto = char] not viable: expects an lvalue for 1st argument}} static_assert(is_same_v<decltype(f2(1)), int &>); // expected-error{{no matching}} static_assert(is_same_v<decltype(f2('c')), char &>); // expected-error{{no matching}} - decltype(auto) f3(const auto &x) { return x; } + decltype(auto) f3(const auto &x) { return x; } // ext-warning {{'auto' parameters are a C++20 extension}} static_assert(is_same_v<decltype(f3(1)), const int &>); static_assert(is_same_v<decltype(f3('c')), const char &>); - decltype(auto) f4(auto (*x)(auto y)) { return x; } // expected-error{{'auto' not allowed in function prototype}} + decltype(auto) f4(auto (*x)(auto y)) { return x; } // expected-error{{'auto' not allowed in function prototype}} ext-warning {{'auto' parameters are a C++20 extension}} decltype(auto) f5(void (*x)(decltype(auto) y)) { return x; } // expected-error{{'decltype(auto)' not allowed in function prototype}} int return_int(); void return_void(); int foo(int); - decltype(auto) f6(auto (*x)()) { return x; } + decltype(auto) f6(auto (*x)()) { return x; } // ext-warning {{'auto' parameters are a C++20 extension}} // expected-note@-1{{candidate template ignored: failed template argument deduction}} static_assert(is_same_v<decltype(f6(return_int)), int (*)()>); static_assert(is_same_v<decltype(f6(return_void)), void (*)()>); @@ -40,42 +42,43 @@ namespace unconstrained { using f7c2 = decltype(f7(foo)); // expected-error{{no matching}} static_assert(is_same_v<decltype(&f7), int (*(*)(int (*x)()))()>); - decltype(auto) f8(auto... x) { return (x + ...); } + decltype(auto) f8(auto... x) { return (x + ...); } // ext-warning {{'auto' parameters are a C++20 extension}} static_assert(is_same_v<decltype(f8(1, 2, 3)), int>); static_assert(is_same_v<decltype(f8('c', 'd')), int>); static_assert(is_same_v<decltype(f8('c', 1)), int>); - decltype(auto) f9(auto &... x) { return (x, ...); } + decltype(auto) f9(auto &... x) { return (x, ...); } // ext-warning {{'auto' parameters are a C++20 extension}} // expected-note@-1{{candidate function [with x:auto = <int (), int>] not viable: expects an lvalue for 2nd argument}} using f9c1 = decltype(f9(return_int, 1)); // expected-error{{no matching}} decltype(auto) f11(decltype(auto) x) { return x; } // expected-error{{'decltype(auto)' not allowed in function prototype}} template<typename T> - auto f12(auto x, T y) -> type_list<T, decltype(x)>; + auto f12(auto x, T y) -> type_list<T, decltype(x)>; // ext-warning {{'auto' parameters are a C++20 extension}} static_assert(is_same_v<decltype(f12(1, 'c')), type_list<char, int>>); static_assert(is_same_v<decltype(f12<char>(1, 'c')), type_list<char, int>>); template<typename T> - auto f13(T x, auto y) -> type_list<T, decltype(y)>; + auto f13(T x, auto y) -> type_list<T, decltype(y)>; // ext-warning {{'auto' parameters are a C++20 extension}} static_assert(is_same_v<decltype(f13(1, 'c')), type_list<int, char>>); static_assert(is_same_v<decltype(f13<char>(1, 'c')), type_list<char, char>>); template<typename T> - auto f14(auto y) -> type_list<T, decltype(y)>; + auto f14(auto y) -> type_list<T, decltype(y)>; // ext-warning {{'auto' parameters are a C++20 extension}} static_assert(is_same_v<decltype(f14<int>('c')), type_list<int, char>>); static_assert(is_same_v<decltype(f14<int, char>('c')), type_list<int, char>>); template<typename T, typename U> - auto f15(auto y, U u) -> type_list<T, U, decltype(y)>; + auto f15(auto y, U u) -> type_list<T, U, decltype(y)>; // ext-warning {{'auto' parameters are a C++20 extension}} static_assert(is_same_v<decltype(f15<int>('c', nullptr)), type_list<int, decltype(nullptr), char>>); static_assert(is_same_v<decltype(f15<int, decltype(nullptr)>('c', nullptr)), type_list<int, decltype(nullptr), char>>); - auto f16(auto x, auto y) -> type_list<decltype(x), decltype(y)>; + auto f16(auto x, auto y) -> type_list<decltype(x), decltype(y)>; // ext-warning {{'auto' parameters are a C++20 extension}} ext-warning {{'auto' parameters are a C++20 extension}} static_assert(is_same_v<decltype(f16('c', 1)), type_list<char, int>>); static_assert(is_same_v<decltype(f16<int>('c', 1)), type_list<int, int>>); static_assert(is_same_v<decltype(f16<int, char>('c', 1)), type_list<int, char>>); +#if __cplusplus >= 202002L void f17(auto x, auto y) requires (sizeof(x) > 1); // expected-note@-1{{candidate template ignored: constraints not satisfied [with x:auto = char, y:auto = int]}} // expected-note@-2{{because 'sizeof (x) > 1' (1 > 1) evaluated to false}} @@ -94,27 +97,28 @@ namespace unconstrained { static_assert(is_same_v<decltype(f18('c', 1)), void>); static_assert(is_same_v<decltype(f18('c', 1, 2)), void>); // expected-error@-1{{no matching}} +#endif template<typename T> struct S { // #defined-here - constexpr auto f1(auto x, T t) -> decltype(x + t); + constexpr auto f1(auto x, T t) -> decltype(x + t); // ext-warning {{'auto' parameters are a C++20 extension}} template<typename U> - constexpr auto f2(U u, auto x, T t) -> decltype(x + u + t); + constexpr auto f2(U u, auto x, T t) -> decltype(x + u + t); // ext-warning {{'auto' parameters are a C++20 extension}} }; template<typename T> - constexpr auto S<T>::f1(auto x, T t) -> decltype(x + t) { return x + t; } + constexpr auto S<T>::f1(auto x, T t) -> decltype(x + t) { return x + t; } // ext-warning {{'auto' parameters are a C++20 extension}} template<typename T> template<typename U> - constexpr auto S<T>::f2(auto x, U u, T t) -> decltype(x + u + t) { return x + u + t; } + constexpr auto S<T>::f2(auto x, U u, T t) -> decltype(x + u + t) { return x + u + t; } // ext-warning {{'auto' parameters are a C++20 extension}} // expected-error@-1 {{out-of-line definition of 'f2' does not match any declaration in 'unconstrained::S<T>'}} // expected-note@#defined-here {{S defined here}} template<typename T> template<typename U> - constexpr auto S<T>::f2(U u, auto x, T t) -> decltype(x + u + t) { return x + u + t; } + constexpr auto S<T>::f2(U u, auto x, T t) -> decltype(x + u + t) { return x + u + t; } // ext-warning {{'auto' parameters are a C++20 extension}} template<> template<> @@ -126,6 +130,7 @@ namespace unconstrained { static_assert(S<int>{}.f2<double>(1, '2', '\x00') == 42); } +#if __cplusplus >= 202002L namespace constrained { template<typename T> concept C = is_same_v<T, int>; @@ -259,3 +264,4 @@ namespace constrained { // expected-error@-1{{no matching}} static_assert(is_same_v<decltype(S2('a')), S2>); } +#endif // __cplusplus >= 202002L diff --git a/clang/test/CXX/drs/cwg6xx.cpp b/clang/test/CXX/drs/cwg6xx.cpp index b7b2ebf700375..4df56ccb41079 100644 --- a/clang/test/CXX/drs/cwg6xx.cpp +++ b/clang/test/CXX/drs/cwg6xx.cpp @@ -269,8 +269,7 @@ namespace cwg625 { // cwg625: 2.9 void f(int); void (*p)(auto) = f; // cxx98-error@-1 {{'auto' type specifier is a C++11 extension}} - // cxx98-17-error@-2 {{'auto' not allowed in function prototype}} - // since-cxx20-error@-3 {{'auto' not allowed in function prototype that is not a function declaration}} + // expected-error@-2 {{'auto' not allowed in function prototype that is not a function declaration}} } // namespace cwg625 namespace cwg626 { // cwg626: 2.7 diff --git a/clang/test/Parser/cxx1z-decomposition.cpp b/clang/test/Parser/cxx1z-decomposition.cpp index 21c9419e8f413..10f0c07766ccf 100644 --- a/clang/test/Parser/cxx1z-decomposition.cpp +++ b/clang/test/Parser/cxx1z-decomposition.cpp @@ -32,7 +32,7 @@ namespace ForRangeDecl { namespace OtherDecl { // A parameter-declaration is not a simple-declaration. // This parses as an array declaration. - void f(auto [a, b, c]); // cxx17-error {{'auto' not allowed in function prototype}} expected-error 1+{{'a'}} + void f(auto [a, b, c]); // cxx17-warning {{'auto' parameters are a C++20 extension}} expected-error 1+{{'a'}} void g() { // A condition is allowed as a Clang extension. diff --git a/clang/test/SemaCXX/crash-GH173943.cpp b/clang/test/SemaCXX/crash-GH173943.cpp index e00a0f2fb12c9..f4033d80457eb 100644 --- a/clang/test/SemaCXX/crash-GH173943.cpp +++ b/clang/test/SemaCXX/crash-GH173943.cpp @@ -3,9 +3,9 @@ // https://github.com/llvm/llvm-project/issues/173943 -constexpr void f(this auto& self) // expected-note {{candidate function}} +constexpr void f(this auto& self) // expected-error@-1 {{unknown type name 'constexpr'}} - // expected-error@-2 {{'auto' not allowed in function prototype}} + // expected-warning@-2 {{'auto' parameters are a C++20 extension}} // expected-error@-3 {{explicit object parameters are incompatible with C++ standards before C++2b}} // expected-error@-4 {{expected ';' after top level declarator}} // expected-error@-5 {{an explicit object parameter cannot appear in a non-member function}} diff --git a/clang/test/SemaCXX/deduced-return-type-cxx14.cpp b/clang/test/SemaCXX/deduced-return-type-cxx14.cpp index aa62c4a57a636..bef460c6c7d6c 100644 --- a/clang/test/SemaCXX/deduced-return-type-cxx14.cpp +++ b/clang/test/SemaCXX/deduced-return-type-cxx14.cpp @@ -1,11 +1,11 @@ -// RUN: %clang_cc1 -std=c++23 -fsyntax-only -verify=expected,since-cxx20,since-cxx14,cxx20_23,cxx23 %s -// RUN: %clang_cc1 -std=c++23 -fsyntax-only -verify=expected,since-cxx20,since-cxx14,cxx20_23,cxx23 %s -fdelayed-template-parsing -DDELAYED_TEMPLATE_PARSING +// RUN: %clang_cc1 -std=c++23 -fsyntax-only -verify=expected,cxx20_23,cxx23 %s +// RUN: %clang_cc1 -std=c++23 -fsyntax-only -verify=expected,cxx20_23,cxx23 %s -fdelayed-template-parsing -DDELAYED_TEMPLATE_PARSING -// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify=expected,cxx20,since-cxx20,since-cxx14,cxx14_20,cxx20_23 %s -// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify=expected,cxx20,since-cxx20,since-cxx14,cxx14_20,cxx20_23 %s -fdelayed-template-parsing -DDELAYED_TEMPLATE_PARSING +// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify=expected,cxx20,cxx14_20,cxx20_23 %s +// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify=expected,cxx20,cxx14_20,cxx20_23 %s -fdelayed-template-parsing -DDELAYED_TEMPLATE_PARSING -// RUN: %clang_cc1 -std=c++14 -fsyntax-only -verify=expected,since-cxx14,cxx14_20,cxx14 %s -// RUN: %clang_cc1 -std=c++14 -fsyntax-only -verify=expected,since-cxx14,cxx14_20,cxx14 %s -fdelayed-template-parsing -DDELAYED_TEMPLATE_PARSING +// RUN: %clang_cc1 -std=c++14 -fsyntax-only -verify=expected,cxx14_20,cxx14 %s +// RUN: %clang_cc1 -std=c++14 -fsyntax-only -verify=expected,cxx14_20,cxx14 %s -fdelayed-template-parsing -DDELAYED_TEMPLATE_PARSING auto f(); // expected-note {{previous}} int f(); // expected-error {{differ only in their return type}} @@ -672,8 +672,7 @@ struct Node { bool parse(const char*); Node* parsePrimaryExpr(); -auto parseMulExpr(auto node) { // cxx14-error {{'auto' not allowed in function prototype}} \ - // cxx14-note {{not viable}} +auto parseMulExpr(auto node) { // cxx14-warning {{'auto' parameters are a C++20 extension}} if (node == nullptr) node = parsePrimaryExpr(); if (!parse("*")) return node; return parseMulExpr(new Node{.left = node, .right = parsePrimaryExpr()}); @@ -693,12 +692,12 @@ auto parseMulExpr3(T node) { // expected-note {{declared here}} } void foo() { - parseMulExpr(new Node{}); // cxx14-error {{no matching function}} + parseMulExpr(new Node{}); parseMulExpr2(new Node{}); parseMulExpr3(new Node{}); // expected-note {{in instantiation}} } -auto f(auto x) { // cxx14-error {{'auto' not allowed in function prototype}} +auto f(auto x) { // cxx14-warning {{'auto' parameters are a C++20 extension}} if (x == 0) return 0; return f(1) + 1; } @@ -706,15 +705,15 @@ auto f(auto x) { // cxx14-error {{'auto' not allowed in function prototype}} namespace GH122892 { struct NonTemplate { void caller() { - c1(int{}); // since-cxx20-error {{cannot be used before it is defined}} - c2(int{}); // since-cxx14-error {{cannot be used before it is defined}} + c1(int{}); // expected-error {{cannot be used before it is defined}} + c2(int{}); // expected-error {{cannot be used before it is defined}} } - static auto c1(auto x) { // since-cxx20-note {{declared here}} // cxx14-error {{'auto' not allowed in function prototype}} + static auto c1(auto x) { // expected-note {{declared here}} cxx14-warning {{'auto' parameters are a C++20 extension}} } template <typename T> - static auto c2(T x) { // since-cxx14-note {{declared here}} + static auto c2(T x) { // expected-note {{declared here}} return x; } }; @@ -725,23 +724,23 @@ namespace GH122892 { template <> void specialized<int>() { - c1(int{}); // since-cxx20-error {{cannot be used before it is defined}} - c2(int{}); // since-cxx14-error {{cannot be used before it is defined}} + c1(int{}); // expected-error {{cannot be used before it is defined}} + c2(int{}); // expected-error {{cannot be used before it is defined}} } - static auto c1(auto x) { // since-cxx20-note {{declared here}} // cxx14-error {{'auto' not allowed in function prototype}} + static auto c1(auto x) { // expected-note {{declared here}} cxx14-warning {{'auto' parameters are a C++20 extension}} } template <typename T> - static auto c2(T x) { // since-cxx14-note {{declared here}} + static auto c2(T x) { // expected-note {{declared here}} return x; } }; struct MemberInit { - int x1 = c1(int{}); // since-cxx20-error {{cannot be used before it is defined}} + int x1 = c1(int{}); // expected-error {{cannot be used before it is defined}} - static auto c1(auto x) { return x; } // since-cxx20-note {{declared here}} // cxx14-error {{'auto' not allowed in function prototype}} + static auto c1(auto x) { return x; } // expected-note {{declared here}} cxx14-warning {{'auto' parameters are a C++20 extension}} }; } @@ -765,23 +764,23 @@ struct DeducedTargetTypeOfConversionFunction { template <typename T> operator auto() const { return short(); } - // since-cxx14-error@-1 {{'auto' not allowed in declaration of conversion function template}} + // expected-error@-1 {{'auto' not allowed in declaration of conversion function template}} template <typename T> operator const auto() const { return int(); } - // since-cxx14-error@-1 {{'auto' not allowed in declaration of conversion function template}} + // expected-error@-1 {{'auto' not allowed in declaration of conversion function template}} template <typename T> operator const auto&() const { return char(); } - // since-cxx14-error@-1 {{'auto' not allowed in declaration of conversion function template}} + // expected-error@-1 {{'auto' not allowed in declaration of conversion function template}} template <typename T> operator decltype(auto)() const { return unsigned(); } - // since-cxx14-error@-1 {{'decltype(auto)' not allowed in declaration of conversion function template}} + // expected-error@-1 {{'decltype(auto)' not allowed in declaration of conversion function template}} #if __cplusplus >= 202002L template <typename T> operator C auto() const { return float(); } - // since-cxx20-error@-1 {{'auto' not allowed in declaration of conversion function template}} + // expected-error@-1 {{'auto' not allowed in declaration of conversion function template}} template <typename T> operator C decltype(auto)() const { return double(); } - // since-cxx20-error@-1 {{'decltype(auto)' not allowed in declaration of conversion function template}} + // expected-error@-1 {{'decltype(auto)' not allowed in declaration of conversion function template}} #endif }; >From 5619f57acc3c290007b17198df4d5dfc887e77fc Mon Sep 17 00:00:00 2001 From: Nikolas Klauser <[email protected]> Date: Mon, 1 Jun 2026 11:16:20 +0200 Subject: [PATCH 2/4] Address comments --- clang/lib/Sema/SemaType.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 5ec96aa1bfba4..d35663bc4decc 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -3287,14 +3287,16 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state, Auto->getKeyword() != AutoTypeKeyword::Auto) { Error = 0; break; - } else if (!SemaRef.getCurScope()->isFunctionDeclarationScope()) { - Error = 21; - break; } if (!SemaRef.getLangOpts().CPlusPlus20) SemaRef.Diag(AutoRange.getBegin(), diag::ext_auto_arg); + if (!SemaRef.getCurScope()->isFunctionDeclarationScope()) { + Error = 21; + break; + } + Info = &SemaRef.InventedParameterInfos.back(); } else { // In C++14, generic lambdas allow 'auto' in their parameters. >From 0e3c8448131dcb5155e056211a82b87058f4d470 Mon Sep 17 00:00:00 2001 From: Nikolas Klauser <[email protected]> Date: Mon, 1 Jun 2026 11:25:00 +0200 Subject: [PATCH 3/4] Address comments --- clang/test/CXX/drs/cwg6xx.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/clang/test/CXX/drs/cwg6xx.cpp b/clang/test/CXX/drs/cwg6xx.cpp index 4df56ccb41079..3ba2b372cb715 100644 --- a/clang/test/CXX/drs/cwg6xx.cpp +++ b/clang/test/CXX/drs/cwg6xx.cpp @@ -269,7 +269,8 @@ namespace cwg625 { // cwg625: 2.9 void f(int); void (*p)(auto) = f; // cxx98-error@-1 {{'auto' type specifier is a C++11 extension}} - // expected-error@-2 {{'auto' not allowed in function prototype that is not a function declaration}} + // cxx98-17-error@-2 {{'auto' parameters are a C++20 extension}} + // expected-error@-3 {{'auto' not allowed in function prototype that is not a function declaration}} } // namespace cwg625 namespace cwg626 { // cwg626: 2.7 >From cc586b2ae21a85c1b602653d65460a6bef7474b5 Mon Sep 17 00:00:00 2001 From: Nikolas Klauser <[email protected]> Date: Tue, 2 Jun 2026 10:49:40 +0200 Subject: [PATCH 4/4] Address comments --- clang/docs/LanguageExtensions.rst | 1 + clang/docs/ReleaseNotes.rst | 13 +++++----- .../clang/Basic/DiagnosticSemaKinds.td | 5 ++-- clang/lib/Sema/SemaType.cpp | 2 +- .../dcl.spec.auto/p3-generic-lambda-1y.cpp | 24 +++++++++---------- clang/test/CXX/dcl/dcl.fct/p17.cpp | 2 +- 6 files changed, 24 insertions(+), 23 deletions(-) diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst index fbb9947f39d3e..83bc2aac23d07 100644 --- a/clang/docs/LanguageExtensions.rst +++ b/clang/docs/LanguageExtensions.rst @@ -1967,6 +1967,7 @@ Familiar template syntax for generic lambdas __cpp_generic_lambdas C Designated initializers __cpp_designated_initializers C++20 C++03 Conditional ``explicit`` __cpp_conditional_explicit C++20 C++03 ``using enum`` __cpp_using_enum C++20 C++03 +``auto`` parameters C++20 C++03 ``if consteval`` __cpp_if_consteval C++23 C++20 ``static operator()`` __cpp_static_call_operator C++23 C++03 Attributes on Lambda-Expressions C++23 C++11 diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index fc0a1d2d4c926..7a61754b985f4 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -191,6 +191,7 @@ C++ Language Changes -------------------- - ``__is_trivially_equality_comparable`` no longer returns false for all enum types. (#GH132672) +- ``auto`` parameters are now available in all C++ language modes as an extension. C++2c Feature Support ^^^^^^^^^^^^^^^^^^^^^ @@ -363,7 +364,7 @@ Modified Compiler Flags - The `-mno-outline` flag will now add the `nooutline` IR attribute, so that `-mno-outline` and `-moutline` objects can be mixed correctly during LTO. -- Slightly changed hash id generation to get the unique linkage symbols names +- Slightly changed hash id generation to get the unique linkage symbols names by ``-unique-internal-linkage-names`` option. Now it uses a path that normalized in favor of the target system (same as the preprocessor does for the file macros) and allows the reproducable IDs on any build system. @@ -414,7 +415,7 @@ Attribute Changes in Clang - The ``[[clang::unsafe_buffer_usage]]`` attribute is now supported in API notes. For example: - + .. code-block:: yaml Functions: @@ -866,10 +867,10 @@ clang-format ------------ - Add ``ObjCSpaceAfterMethodDeclarationPrefix`` option to control space between the '-'/'+' and the return type in Objective-C method declarations -- Deprecate the ``BinPackParameters`` and ``BinPackArguments`` options and replace - them with the ``PackParameters`` and ``PackArguments`` structs (respectively) to - unify packing behavior. Add the ``BreakAfter`` option to the structs, allowing - parameter and argument lists to be formatted with one parameter/argument on each +- Deprecate the ``BinPackParameters`` and ``BinPackArguments`` options and replace + them with the ``PackParameters`` and ``PackArguments`` structs (respectively) to + unify packing behavior. Add the ``BreakAfter`` option to the structs, allowing + parameter and argument lists to be formatted with one parameter/argument on each line if they exceed the specified count. - Add ``AfterComma`` value to ``BreakConstructorInitializers`` to allow breaking constructor initializers after commas, keeping the colon on the same line. diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 6d566d40d3b41..0580d3c441c43 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -53,6 +53,8 @@ defm ctad_for_alias_templates defm implicit_typename : CXX20Compat<"missing 'typename' prior to dependent type name %0 is">; +defm auto_param : CXX20Compat<"'auto' parameters are">; + // C++23 compatibility with C++20 and earlier. defm constexpr_static_var : CXX23Compat< "definition of a %select{static|thread_local}1 variable " @@ -2667,9 +2669,6 @@ def err_auto_not_allowed : Error< "|in declaration of conversion function template" "|in lambda parameter before C++14}1">; -def ext_auto_arg : ExtWarn< - "'auto' parameters are a C++20 extension">, InGroup<CXX20>; - def err_dependent_deduced_tst : Error< "typename specifier refers to " "%select{class template|function template|variable template|alias template|" diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index d35663bc4decc..c030e2c18242f 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -3290,7 +3290,7 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state, } if (!SemaRef.getLangOpts().CPlusPlus20) - SemaRef.Diag(AutoRange.getBegin(), diag::ext_auto_arg); + SemaRef.DiagCompat(AutoRange.getBegin(), diag_compat::auto_param); if (!SemaRef.getCurScope()->isFunctionDeclarationScope()) { Error = 21; diff --git a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3-generic-lambda-1y.cpp b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3-generic-lambda-1y.cpp index ca8d50fe22728..5b041169af85b 100644 --- a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3-generic-lambda-1y.cpp +++ b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3-generic-lambda-1y.cpp @@ -22,20 +22,20 @@ int main() { auto l1 = [](auto a) -> int { return a + 5; }; auto l2 = [](auto *p) -> int { return p + 5; }; - + struct A { int i; char f(int) { return 'c'; } }; - auto l3 = [](auto &&ur, - auto &lr, - auto v, - int i, + auto l3 = [](auto &&ur, + auto &lr, + auto v, + int i, auto* p, auto A::*memvar, auto (A::*memfun)(int), char c, decltype (v)* pv - , auto (&array)[5] + , auto (&array)[5] ) -> int { return v + i + c - + array[0]; + + array[0]; }; int arr[5] = {0, 1, 2, 3, 4 }; int lval = 0; @@ -49,24 +49,24 @@ int main() static double dfi(int i) { return i + 3.14; } static Local localfi(int) { return Local{}; } }; - auto l4 = [](auto (*fp)(int)) -> int { return fp(3); }; //expected-error{{no viable conversion from returned value of type 'Local' to function return type 'int'}} + auto l4 = [](auto (*fp)(int)) -> int { return fp(3); }; //expected-error{{no viable conversion from returned value of type 'Local' to function return type 'int'}} l4(&Local::ifi); l4(&Local::cfi); l4(&Local::dfi); - l4(&Local::localfi); //expected-note{{in instantiation of function template specialization}} + l4(&Local::localfi); //expected-note{{in instantiation of function template specialization}} } { auto unnamed_parameter = [](auto, auto) -> void { }; unnamed_parameter(3, '4'); } { - auto l = [](auto - (*)(auto)) { }; //expected-error{{'auto' not allowed}} + auto l = [](auto (*)(auto)) { }; //expected-error{{'auto' not allowed}} expected-warning {{'auto' parameters are a C++20 extension}} //FIXME: These diagnostics might need some work. auto l2 = [](char auto::*pm) { }; // expected-error {{cannot combine with previous 'char' declaration specifier}} \ expected-error{{'pm' does not point into a class}} auto l3 = [](char (auto::*pmf)()) { }; // expected-error{{'auto' not allowed}}\ expected-error{{'pmf' does not point into a class}}\ - expected-error{{function cannot return function type 'char ()'}} + expected-error{{function cannot return function type 'char ()'}} \ + expected-warning {{'auto' parameters are a C++20 extension}} } } diff --git a/clang/test/CXX/dcl/dcl.fct/p17.cpp b/clang/test/CXX/dcl/dcl.fct/p17.cpp index 703a058d9d905..33b5b688ded64 100644 --- a/clang/test/CXX/dcl/dcl.fct/p17.cpp +++ b/clang/test/CXX/dcl/dcl.fct/p17.cpp @@ -22,7 +22,7 @@ namespace unconstrained { static_assert(is_same_v<decltype(f3(1)), const int &>); static_assert(is_same_v<decltype(f3('c')), const char &>); - decltype(auto) f4(auto (*x)(auto y)) { return x; } // expected-error{{'auto' not allowed in function prototype}} ext-warning {{'auto' parameters are a C++20 extension}} + decltype(auto) f4(auto (*x)(auto y)) { return x; } // expected-error{{'auto' not allowed in function prototype}} ext-warning 2 {{'auto' parameters are a C++20 extension}} decltype(auto) f5(void (*x)(decltype(auto) y)) { return x; } // expected-error{{'decltype(auto)' not allowed in function prototype}} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
