[clang] [Clang] Accept auto casts pre-C++23 as an extension (PR #200675)
Nikolas Klauser via cfe-commits
cfe-commits at lists.llvm.org
Wed Jun 10 04:05:53 PDT 2026
https://github.com/philnik777 updated https://github.com/llvm/llvm-project/pull/200675
>From 5654616dd0909975ce07fdd7db187374ff2dedd8 Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Sun, 31 May 2026 19:16:13 +0200
Subject: [PATCH 1/3] [Clang] Accept auto casts pre-C++23 as an extension
---
clang/docs/LanguageExtensions.rst | 1 +
.../clang/Basic/DiagnosticSemaKinds.td | 5 +--
clang/lib/Frontend/InitPreprocessor.cpp | 2 +-
clang/lib/Parse/ParseTentative.cpp | 2 -
clang/lib/Sema/SemaExprCXX.cpp | 7 ++-
clang/lib/Sema/SemaType.cpp | 11 +++--
.../dcl.spec/dcl.type/dcl.spec.auto/p5.cpp | 4 +-
.../dcl.type/dcl.type.auto.deduct/p2.cpp | 43 ++++++++++---------
.../expr/expr.post/expr.type.conv/p1-2b.cpp | 37 ++++++++--------
clang/test/Lexer/cxx-features.cpp | 2 +-
clang/test/Parser/cxx1z-decomposition.cpp | 5 +--
clang/test/Parser/cxx2b-auto-x.cpp | 25 +++++------
12 files changed, 68 insertions(+), 76 deletions(-)
diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst
index fbb9947f39d3e..1ecc8c01a5f8e 100644
--- a/clang/docs/LanguageExtensions.rst
+++ b/clang/docs/LanguageExtensions.rst
@@ -1978,6 +1978,7 @@ Pack Indexing __cpp_pack_indexing C
``= delete ("should have a reason");`` __cpp_deleted_function C++26 C++03
Variadic Friends __cpp_variadic_friend C++26 C++03
Trivial Relocatability __cpp_trivial_relocatability C++26 C++03
+``auto()`` cast __cpp_auto_cast C++26 C++03
--------------------------------------------- -------------------------------- ------------- -------------
Designated initializers (N494) C99 C89
``_Complex`` (N693) C99 C89, C++
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 077aace321264..859eabe97b4c4 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -59,6 +59,8 @@ defm constexpr_static_var : CXX23Compat<
"in a constexpr %select{function|constructor}0 "
"is">;
+defm auto_expr : CXX23Compat<"'auto' as a functional-style cast is">;
+
// C++26 compatibility with C++23 and earlier.
defm decomp_decl_cond : CXX26Compat<"structured binding declaration in a condition is">;
@@ -2702,9 +2704,6 @@ def err_auto_new_ctor_multiple_expressions : Error<
def err_auto_expr_init_paren_braces : Error<
"cannot deduce actual type for %1 from "
"%select{parenthesized|nested}0 initializer list">;
-def warn_cxx20_compat_auto_expr : Warning<
- "'auto' as a functional-style cast is incompatible with C++ standards "
- "before C++23">, InGroup<CXXPre23Compat>, DefaultIgnore;
def err_auto_missing_trailing_return : Error<
"'auto' return without trailing return type; deduced return types are a "
"C++14 extension">;
diff --git a/clang/lib/Frontend/InitPreprocessor.cpp b/clang/lib/Frontend/InitPreprocessor.cpp
index 3f0468a938149..448cb551cc930 100644
--- a/clang/lib/Frontend/InitPreprocessor.cpp
+++ b/clang/lib/Frontend/InitPreprocessor.cpp
@@ -735,7 +735,6 @@ static void InitializeCPlusPlusFeatureTestMacros(const LangOptions &LangOpts,
Builder.defineMacro("__cpp_size_t_suffix", "202011L");
Builder.defineMacro("__cpp_if_consteval", "202106L");
Builder.defineMacro("__cpp_multidimensional_subscript", "202211L");
- Builder.defineMacro("__cpp_auto_cast", "202110L");
Builder.defineMacro("__cpp_explicit_this_parameter", "202110L");
}
@@ -743,6 +742,7 @@ static void InitializeCPlusPlusFeatureTestMacros(const LangOptions &LangOpts,
// we also define their feature test macros.
if (LangOpts.CPlusPlus11)
Builder.defineMacro("__cpp_static_call_operator", "202207L");
+ Builder.defineMacro("__cpp_auto_cast", "202110L");
Builder.defineMacro("__cpp_named_character_escapes", "202207L");
Builder.defineMacro("__cpp_placeholder_variables", "202306L");
diff --git a/clang/lib/Parse/ParseTentative.cpp b/clang/lib/Parse/ParseTentative.cpp
index f77b1001332fe..74180cf2ddeaf 100644
--- a/clang/lib/Parse/ParseTentative.cpp
+++ b/clang/lib/Parse/ParseTentative.cpp
@@ -1143,8 +1143,6 @@ Parser::isCXXDeclarationSpecifier(ImplicitTypenameContext AllowImplicitTypename,
BracedCastResult, InvalidAsDeclSpec);
case tok::kw_auto: {
- if (!getLangOpts().CPlusPlus23)
- return TPResult::True;
if (NextToken().is(tok::l_brace))
return TPResult::False;
if (NextToken().is(tok::l_paren))
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index 00c873833c8a7..22b1d62cfaa06 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -1560,6 +1560,9 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo,
Inits = MultiExprArg(ILE->getInits(), ILE->getNumInits());
}
+ if (Ty->getAs<AutoType>())
+ DiagCompat(TyBeginLoc, diag_compat::auto_expr) << FullRange;
+
if (Inits.empty())
return ExprError(Diag(TyBeginLoc, diag::err_auto_expr_init_no_expression)
<< Ty << FullRange);
@@ -1569,10 +1572,6 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo,
diag::err_auto_expr_init_multiple_expressions)
<< Ty << FullRange);
}
- if (getLangOpts().CPlusPlus23) {
- if (Ty->getAs<AutoType>())
- Diag(TyBeginLoc, diag::warn_cxx20_compat_auto_expr) << FullRange;
- }
Expr *Deduce = Inits[0];
if (isa<InitListExpr>(Deduce))
return ExprError(
diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index 44ac4f6630690..9e8abee1e2d44 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -3251,6 +3251,10 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
DeducedIsTrailingReturnType = true;
}
+ SourceRange AutoRange = D.getDeclSpec().getTypeSpecTypeLoc();
+ if (D.getName().getKind() == UnqualifiedIdKind::IK_ConversionFunctionId)
+ AutoRange = D.getName().getSourceRange();
+
// C++11 [dcl.spec.auto]p5: reject 'auto' if it is not in an allowed context.
if (Deduced) {
AutoType *Auto = dyn_cast<AutoType>(Deduced);
@@ -3382,8 +3386,7 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
case DeclaratorContext::FunctionalCast:
if (isa<DeducedTemplateSpecializationType>(Deduced))
break;
- if (SemaRef.getLangOpts().CPlusPlus23 && IsCXXAutoType &&
- !Auto->isDecltypeAuto())
+ if (IsCXXAutoType && !Auto->isDecltypeAuto())
break; // auto(x)
[[fallthrough]];
case DeclaratorContext::TypeName:
@@ -3419,10 +3422,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..bdf3a587a7c52 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
@@ -56,8 +56,8 @@ void j() {
(void)reinterpret_cast<auto>(n); // expected-error{{'auto' not allowed here}}
(void)const_cast<auto>(n); // expected-error{{'auto' not allowed here}}
(void)(auto)(n); // expected-error{{'auto' not allowed here}}
- (void)auto(n); // expected-error{{'auto' not allowed here}}
- (void)auto{n}; // expected-error{{'auto' not allowed here}}
+ (void)auto(n); // expected-warning{{'auto' as a functional-style cast is a C++23 extension}}
+ (void)auto{n}; // expected-warning{{'auto' as a functional-style cast is a C++23 extension}}
}
template <auto a = 10> class C { }; // expected-error{{'auto' not allowed in template parameter}}
diff --git a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.auto.deduct/p2.cpp b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.auto.deduct/p2.cpp
index 1655685f44808..1c6c66882c570 100644
--- a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.auto.deduct/p2.cpp
+++ b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.auto.deduct/p2.cpp
@@ -1,37 +1,38 @@
+// RUN: %clang_cc1 -std=c++20 -verify=expected,cxx20 %s
// RUN: %clang_cc1 -std=c++23 -verify %s
// p2.3 allows only T = auto in T(x).
void test_decay() {
int v[3];
- static_assert(__is_same(decltype(auto(v)), int *));
- static_assert(__is_same(decltype(auto{v}), int *));
- static_assert(__is_same(decltype(auto("lit")), char const *));
- static_assert(__is_same(decltype(auto{"lit"}), char const *));
+ static_assert(__is_same(decltype(auto(v)), int *)); // cxx20-warning {{'auto' as a functional-style cast is a C++23 extension}}
+ static_assert(__is_same(decltype(auto{v}), int *)); // cxx20-warning {{'auto' as a functional-style cast is a C++23 extension}}
+ static_assert(__is_same(decltype(auto("lit")), char const *)); // cxx20-warning {{'auto' as a functional-style cast is a C++23 extension}}
+ static_assert(__is_same(decltype(auto{"lit"}), char const *)); // cxx20-warning {{'auto' as a functional-style cast is a C++23 extension}}
constexpr long i = 1;
static_assert(__is_same(decltype(i), long const));
- static_assert(__is_same(decltype(auto(1L)), long));
- static_assert(__is_same(decltype(auto{1L}), long));
- static_assert(__is_same(decltype(auto(i)), long));
- static_assert(__is_same(decltype(auto{i}), long));
+ static_assert(__is_same(decltype(auto(1L)), long)); // cxx20-warning {{'auto' as a functional-style cast is a C++23 extension}}
+ static_assert(__is_same(decltype(auto{1L}), long)); // cxx20-warning {{'auto' as a functional-style cast is a C++23 extension}}
+ static_assert(__is_same(decltype(auto(i)), long)); // cxx20-warning {{'auto' as a functional-style cast is a C++23 extension}}
+ static_assert(__is_same(decltype(auto{i}), long)); // cxx20-warning {{'auto' as a functional-style cast is a C++23 extension}}
class A {
} a;
A const ac;
- static_assert(__is_same(decltype(auto(a)), A));
- static_assert(__is_same(decltype(auto(ac)), A));
+ static_assert(__is_same(decltype(auto(a)), A)); // cxx20-warning {{'auto' as a functional-style cast is a C++23 extension}}
+ static_assert(__is_same(decltype(auto(ac)), A)); // cxx20-warning {{'auto' as a functional-style cast is a C++23 extension}}
A &lr = a;
A const &lrc = a;
A &&rr = static_cast<A &&>(a);
A const &&rrc = static_cast<A &&>(a);
- static_assert(__is_same(decltype(auto(lr)), A));
- static_assert(__is_same(decltype(auto(lrc)), A));
- static_assert(__is_same(decltype(auto(rr)), A));
- static_assert(__is_same(decltype(auto(rrc)), A));
+ static_assert(__is_same(decltype(auto(lr)), A)); // cxx20-warning {{'auto' as a functional-style cast is a C++23 extension}}
+ static_assert(__is_same(decltype(auto(lrc)), A)); // cxx20-warning {{'auto' as a functional-style cast is a C++23 extension}}
+ static_assert(__is_same(decltype(auto(rr)), A)); // cxx20-warning {{'auto' as a functional-style cast is a C++23 extension}}
+ static_assert(__is_same(decltype(auto(rrc)), A)); // cxx20-warning {{'auto' as a functional-style cast is a C++23 extension}}
}
class cmdline_parser {
@@ -42,7 +43,7 @@ class cmdline_parser {
void test_rvalue_fluent_interface() {
auto cmdline = cmdline_parser("driver");
- auto internal = auto{cmdline}.add_option("--dump-full", "do not minimize dump");
+ auto internal = auto{cmdline}.add_option("--dump-full", "do not minimize dump"); // cxx20-warning {{'auto' as a functional-style cast is a C++23 extension}}
}
template <class T> constexpr auto decay_copy(T &&v) { return static_cast<T &&>(v); } // expected-error {{calling a protected constructor}}
@@ -55,17 +56,17 @@ class A {
A();
auto test_access() {
- static_assert(__is_same(decltype(auto(*this)), A));
- static_assert(__is_same(decltype(auto(this)), A *));
+ static_assert(__is_same(decltype(auto(*this)), A)); // cxx20-warning {{'auto' as a functional-style cast is a C++23 extension}}
+ static_assert(__is_same(decltype(auto(this)), A *)); // cxx20-warning {{'auto' as a functional-style cast is a C++23 extension}}
f(A(*this)); // ok
- f(auto(*this)); // ok in P0849
+ f(auto(*this)); // ok in P0849 cxx20-warning {{'auto' as a functional-style cast is a C++23 extension}}
f(decay_copy(*this)); // expected-note {{in instantiation of function template specialization}}
}
auto test_access() const {
- static_assert(__is_same(decltype(auto(*this)), A)); // ditto
- static_assert(__is_same(decltype(auto(this)), A const *));
+ static_assert(__is_same(decltype(auto(*this)), A)); // ditto cxx20-warning {{'auto' as a functional-style cast is a C++23 extension}}
+ static_assert(__is_same(decltype(auto(this)), A const *)); // cxx20-warning {{'auto' as a functional-style cast is a C++23 extension}}
}
protected:
@@ -77,5 +78,5 @@ namespace auto_x {
constexpr struct Uncopyable {
constexpr explicit Uncopyable(int) {}
constexpr Uncopyable(Uncopyable &&) = delete;
-} u = auto(Uncopyable(auto(Uncopyable(42))));
+} u = auto(Uncopyable(auto(Uncopyable(42)))); // cxx20-warning 2 {{'auto' as a functional-style cast is a C++23 extension}}
} // namespace auto_x
diff --git a/clang/test/CXX/expr/expr.post/expr.type.conv/p1-2b.cpp b/clang/test/CXX/expr/expr.post/expr.type.conv/p1-2b.cpp
index bbfce5e698d15..08560ea19c9c7 100644
--- a/clang/test/CXX/expr/expr.post/expr.type.conv/p1-2b.cpp
+++ b/clang/test/CXX/expr/expr.post/expr.type.conv/p1-2b.cpp
@@ -1,3 +1,4 @@
+// RUN: %clang_cc1 -std=c++20 -verify=expected,cxx20 %s
// RUN: %clang_cc1 -std=c++23 -verify %s
template <class T>
@@ -12,28 +13,28 @@ struct A {
// C++23 [dcl.type.auto.deduct]p2.3
// For an explicit type conversion, T is the specified type, which shall be auto.
void diagnostics() {
- foo(auto()); // expected-error {{initializer for functional-style cast to 'auto' is empty}}
- foo(auto{}); // expected-error {{initializer for functional-style cast to 'auto' is empty}}
- foo(auto({})); // expected-error {{cannot deduce actual type for 'auto' from parenthesized initializer list}}
- foo(auto{{}}); // expected-error {{cannot deduce actual type for 'auto' from nested initializer list}}
+ foo(auto()); // expected-error {{initializer for functional-style cast to 'auto' is empty}} cxx20-warning {{'auto' as a functional-style cast is a C++23 extension}}
+ foo(auto{}); // expected-error {{initializer for functional-style cast to 'auto' is empty}} cxx20-warning {{'auto' as a functional-style cast is a C++23 extension}}
+ foo(auto({})); // expected-error {{cannot deduce actual type for 'auto' from parenthesized initializer list}} cxx20-warning {{'auto' as a functional-style cast is a C++23 extension}}
+ foo(auto{{}}); // expected-error {{cannot deduce actual type for 'auto' from nested initializer list}} cxx20-warning {{'auto' as a functional-style cast is a C++23 extension}}
// - If the initializer is a parenthesized expression-list, the expression-list shall be a single assignmentexpression and E is the assignment-expression.
- foo(auto(a));
+ foo(auto(a)); // cxx20-warning {{'auto' as a functional-style cast is a C++23 extension}}
// - If the initializer is a braced-init-list, it shall consist of a single brace-enclosed assignment-expression and E is the assignment-expression.
- foo(auto{a});
- foo(auto({a})); // expected-error {{cannot deduce actual type for 'auto' from parenthesized initializer list}}
- foo(auto{{a}}); // expected-error {{cannot deduce actual type for 'auto' from nested initializer list}}
+ foo(auto{a}); // cxx20-warning {{'auto' as a functional-style cast is a C++23 extension}}
+ foo(auto({a})); // expected-error {{cannot deduce actual type for 'auto' from parenthesized initializer list}} cxx20-warning {{'auto' as a functional-style cast is a C++23 extension}}
+ foo(auto{{a}}); // expected-error {{cannot deduce actual type for 'auto' from nested initializer list}} cxx20-warning {{'auto' as a functional-style cast is a C++23 extension}}
- foo(auto(&A::g)); // expected-error {{functional-style cast to 'auto' has incompatible initializer of type '<overloaded function type>'}}
+ foo(auto(&A::g)); // expected-error {{functional-style cast to 'auto' has incompatible initializer of type '<overloaded function type>'}} cxx20-warning {{'auto' as a functional-style cast is a C++23 extension}}
- foo(auto(a, 3.14)); // expected-error {{initializer for functional-style cast to 'auto' contains multiple expressions}}
- foo(auto{a, 3.14}); // expected-error {{initializer for functional-style cast to 'auto' contains multiple expressions}}
- foo(auto({a, 3.14})); // expected-error {{cannot deduce actual type for 'auto' from parenthesized initializer list}}
- foo(auto{{a, 3.14}}); // expected-error {{cannot deduce actual type for 'auto' from nested initializer list}}
- foo(auto({a}, {3.14})); // expected-error {{initializer for functional-style cast to 'auto' contains multiple expressions}}
- foo(auto{{a}, {3.14}}); // expected-error {{initializer for functional-style cast to 'auto' contains multiple expressions}}
+ foo(auto(a, 3.14)); // expected-error {{initializer for functional-style cast to 'auto' contains multiple expressions}} cxx20-warning {{'auto' as a functional-style cast is a C++23 extension}}
+ foo(auto{a, 3.14}); // expected-error {{initializer for functional-style cast to 'auto' contains multiple expressions}} cxx20-warning {{'auto' as a functional-style cast is a C++23 extension}}
+ foo(auto({a, 3.14})); // expected-error {{cannot deduce actual type for 'auto' from parenthesized initializer list}} cxx20-warning {{'auto' as a functional-style cast is a C++23 extension}}
+ foo(auto{{a, 3.14}}); // expected-error {{cannot deduce actual type for 'auto' from nested initializer list}} cxx20-warning {{'auto' as a functional-style cast is a C++23 extension}}
+ foo(auto({a}, {3.14})); // expected-error {{initializer for functional-style cast to 'auto' contains multiple expressions}} cxx20-warning {{'auto' as a functional-style cast is a C++23 extension}}
+ foo(auto{{a}, {3.14}}); // expected-error {{initializer for functional-style cast to 'auto' contains multiple expressions}} cxx20-warning {{'auto' as a functional-style cast is a C++23 extension}}
- foo(auto{1, 2}); // expected-error {{initializer for functional-style cast to 'auto' contains multiple expressions}}
- foo(auto({1, 2})); // expected-error {{cannot deduce actual type for 'auto' from parenthesized initializer list}}
- foo(auto{{1, 2}}); // expected-error {{cannot deduce actual type for 'auto' from nested initializer list}}
+ foo(auto{1, 2}); // expected-error {{initializer for functional-style cast to 'auto' contains multiple expressions}} cxx20-warning {{'auto' as a functional-style cast is a C++23 extension}}
+ foo(auto({1, 2})); // expected-error {{cannot deduce actual type for 'auto' from parenthesized initializer list}} cxx20-warning {{'auto' as a functional-style cast is a C++23 extension}}
+ foo(auto{{1, 2}}); // expected-error {{cannot deduce actual type for 'auto' from nested initializer list}} cxx20-warning {{'auto' as a functional-style cast is a C++23 extension}}s
}
diff --git a/clang/test/Lexer/cxx-features.cpp b/clang/test/Lexer/cxx-features.cpp
index 171ef99cee5b7..9e67240ee8491 100644
--- a/clang/test/Lexer/cxx-features.cpp
+++ b/clang/test/Lexer/cxx-features.cpp
@@ -60,7 +60,7 @@
// --- C++23 features ---
-#if check(auto_cast, 0, 0, 0, 0, 0, 202110, 202110)
+#if check(auto_cast, 202110, 202110, 202110, 202110, 202110, 202110, 202110)
#error "wrong value for __cpp_auto_cast"
#endif
diff --git a/clang/test/Parser/cxx1z-decomposition.cpp b/clang/test/Parser/cxx1z-decomposition.cpp
index 21c9419e8f413..c075fa3c8128e 100644
--- a/clang/test/Parser/cxx1z-decomposition.cpp
+++ b/clang/test/Parser/cxx1z-decomposition.cpp
@@ -105,9 +105,8 @@ namespace BadSpecifiers {
// defining-type-specifiers other than cv-qualifiers and 'auto'
S [a] = s; // expected-error {{cannot be declared with type 'S'}}
decltype(auto) [b] = s; // expected-error {{cannot be declared with type 'decltype(auto)'}}
- auto ([c2]) = s; // cxx17-error {{structured binding declaration cannot be declared with parenthese}} \
- // post2b-error {{use of undeclared identifier 'c2'}} \
- // post2b-error {{expected body of lambda expression}} \
+ auto ([c2]) = s; // expected-error {{use of undeclared identifier 'c2'}} \
+ // expected-error {{expected body of lambda expression}}
// FIXME: This error is not very good.
auto [d]() = s; // expected-error {{expected ';'}} expected-error {{expected expression}}
diff --git a/clang/test/Parser/cxx2b-auto-x.cpp b/clang/test/Parser/cxx2b-auto-x.cpp
index 9e0277eee76a9..fed80ace7db85 100644
--- a/clang/test/Parser/cxx2b-auto-x.cpp
+++ b/clang/test/Parser/cxx2b-auto-x.cpp
@@ -2,14 +2,15 @@
// RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx20 -std=c++20 %s
void looks_like_decltype_auto() {
- decltype(auto(42)) b = 42; // cxx20-error {{'auto' not allowed here}} \
+ decltype(auto(42)) b = 42; // cxx20-warning {{'auto' as a functional-style cast is a C++23 extension}} \
cxx23-warning {{'auto' as a functional-style cast is incompatible with C++ standards before C++23}}
decltype(long *) a = 42; // expected-error {{expected '(' for function-style cast or type construction}} \
expected-error {{expected expression}}
decltype(auto *) a = 42; // expected-error {{expected '(' for function-style cast or type construction}} \
expected-error {{expected expression}}
- decltype(auto()) c = 42; // cxx23-error {{initializer for functional-style cast to 'auto' is empty}} \
- cxx20-error {{'auto' not allowed here}}
+ decltype(auto()) c = 42; // expected-error {{initializer for functional-style cast to 'auto' is empty}} \
+ cxx20-warning {{'auto' as a functional-style cast is a C++23 extension}} \
+ cxx23-warning {{'auto' as a functional-style cast is incompatible with C++ standards before C++23}}
}
struct looks_like_declaration {
@@ -19,11 +20,9 @@ struct looks_like_declaration {
using T = looks_like_declaration *;
void f() { T(&a)->n = 1; }
void g() { auto(&a)->n = 0; } // cxx23-warning {{before C++23}} \
- // cxx20-error {{declaration of variable 'a' with deduced type 'auto (&)' requires an initializer}} \
- // cxx20-error {{expected ';' at end of declaration}}
+ // cxx20-warning {{'auto' as a functional-style cast is a C++23 extension}}
void h() { auto{&a}->n = 0; } // cxx23-warning {{before C++23}} \
- // cxx20-error {{expected unqualified-id}} \
- // cxx20-error {{expected expression}}
+ // cxx20-warning {{'auto' as a functional-style cast is a C++23 extension}}
void e(auto (*p)(int y) -> decltype(y)) {}
@@ -36,19 +35,15 @@ struct S{
} s; // expected-note {{here}}
void test() {
- auto(s)()->N; // cxx23-warning {{expression result unused}} \
+ auto(s)()->N; // expected-warning {{expression result unused}} \
// cxx23-warning {{before C++23}} \
- // cxx20-error {{unknown type name 'N'}}
+ // cxx20-warning {{'auto' as a functional-style cast is a C++23 extension}}
auto(s)()->M; // expected-error {{redefinition of 's' as different kind of symbol}}
}
void test_paren() {
int a = (auto(0)); // cxx23-warning {{before C++23}} \
- // cxx20-error {{expected expression}} \
- // cxx20-error {{expected ')'}} \
- // cxx20-note {{to match this '('}}
+ // cxx20-warning {{'auto' as a functional-style cast is a C++23 extension}}
int b = (auto{0}); // cxx23-warning {{before C++23}} \
- // cxx20-error {{expected expression}} \
- // cxx20-error {{expected ')'}} \
- // cxx20-note {{to match this '('}}
+ // cxx20-warning {{'auto' as a functional-style cast is a C++23 extension}}
}
>From 9a89414e68a4ccdcba20918ef0cab7c77b4a11cb Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Wed, 3 Jun 2026 09:41:13 +0200
Subject: [PATCH 2/3] Address comments
---
clang/docs/ReleaseNotes.rst | 13 +++++++------
clang/test/Parser/cxx1z-decomposition.cpp | 2 ++
2 files changed, 9 insertions(+), 6 deletions(-)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index fc0a1d2d4c926..8056365fcc9a7 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()`` casts are accepted as an extension pre-C++23
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/test/Parser/cxx1z-decomposition.cpp b/clang/test/Parser/cxx1z-decomposition.cpp
index c075fa3c8128e..7927748840b18 100644
--- a/clang/test/Parser/cxx1z-decomposition.cpp
+++ b/clang/test/Parser/cxx1z-decomposition.cpp
@@ -105,6 +105,8 @@ namespace BadSpecifiers {
// defining-type-specifiers other than cv-qualifiers and 'auto'
S [a] = s; // expected-error {{cannot be declared with type 'S'}}
decltype(auto) [b] = s; // expected-error {{cannot be declared with type 'decltype(auto)'}}
+
+ // FIXME: This diagnostic could be improved.
auto ([c2]) = s; // expected-error {{use of undeclared identifier 'c2'}} \
// expected-error {{expected body of lambda expression}}
>From d5876d33f0ac423b077e9d3d89d8f168790ff118 Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Wed, 10 Jun 2026 13:05:40 +0200
Subject: [PATCH 3/3] Add trailing whitespace
---
clang/docs/ReleaseNotes.rst | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 2b6dffd02e082..b536088bce1dd 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -387,7 +387,7 @@ New Compiler Flags
clang's ``-ffile-prefix-map=value`` and has known differences in behaviour
with the CL's option that do not affect the functionality: nomalizes the
macro prefix map pathes -- removes `./` and uses the target's platform-
- specific path separator character when expanding the preprocessor macros --
+ specific path separator character when expanding the preprocessor macros --
``-ffile-reproducible`` (but not the debug and coverage prefix maps);
does not require ``/experimental:deterministic`` as by MSVC. It needed for
removing a hostname from a mangling hash gen, but clang-cl does not use
@@ -761,7 +761,7 @@ Bug Fixes to C++ Support
- We no longer consider conversion operators when copy-initializing from the same type. This was non
conforming and could lead to recursive constraint satisfaction checking. (#GH149443)
- Fixed a crash in Itanium C++ name mangling for a lambda in a local class field initializer inside a constructor/destructor. (#GH176395)
-- Fixed a crash when Expr::ClassifyImpl computes a classification like CL_LValue or CL_PRValue, then asserts that this
+- Fixed a crash when Expr::ClassifyImpl computes a classification like CL_LValue or CL_PRValue, then asserts that this
agrees with the AST node's own value category. (#GH202693)
- Fixed crashes in Itanium C++ name mangling for lambdas with trailing requires-clauses involving requires-expressions. (#GH100774) (#GH123854)
- Fixed an invalid rejection and assertion failure while generating ``operator=`` for fields with the ``__restrict`` qualifier. (#GH37979)
More information about the cfe-commits
mailing list