https://github.com/adityak2006 created
https://github.com/llvm/llvm-project/pull/167224
Clang's type printer would verbosely print `decltype(T{})` in diagnostics,
even though this is equivalent to just `T`. This made error messages
unnecessarily long and harder to read.
This commit modifies `TypePrinter::printDecltypeBefore` to detect this
specific pattern. It checks if the underlying expression of a
`DecltypeType` is a default `CXXConstructExpr` (i.e., `T{}`) and, if so,
prints the constructor's type (`T`) directly instead of the full
`decltype`.
Fixes #96638.
>From 7f7220ffb01c6e8ba0349ae97693046915d14916 Mon Sep 17 00:00:00 2001
From: Aditya <[email protected]>
Date: Sat, 8 Nov 2025 17:40:00 +0000
Subject: [PATCH 1/2] [Sema] Error on 'auto' storage class in C++11
This patch changes the C-style 'auto' storage class specifier from
a warning to an error in C++11 and later modes.
This was previously allowed as an extension for C compatibility, but
it's no longer appropriate for modern C++.
Fixes #162473
---
.../clang/Basic/DiagnosticParseKinds.td | 2 ++
clang/lib/Parse/ParseDecl.cpp | 18 +++++++++++++-----
clang/test/Parser/cxx-auto-type-specifier.cpp | 13 +++++++++++++
3 files changed, 28 insertions(+), 5 deletions(-)
create mode 100644 clang/test/Parser/cxx-auto-type-specifier.cpp
diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td
b/clang/include/clang/Basic/DiagnosticParseKinds.td
index aa0ccb0c05101..d900001c8cde0 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -402,6 +402,8 @@ def
err_requires_clause_on_declarator_not_declaring_a_function : Error<
"trailing requires clause can only be used when declaring a function">;
def err_requires_clause_inside_parens : Error<
"trailing requires clause should be placed outside parentheses">;
+def err_auto_type_specifier:Error<
+ "'auto' cannot be combined with a type specifier in C++">;
def ext_auto_storage_class : ExtWarn<
"'auto' storage class specifier is not permitted in C++11, and will not "
"be supported in future releases">, InGroup<DiagGroup<"auto-storage-class">>;
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index 5fcb659768655..65ed4db468b65 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -4095,11 +4095,19 @@ void Parser::ParseDeclarationSpecifiers(
case tok::kw_auto:
if (getLangOpts().CPlusPlus11 || getLangOpts().C23) {
if (isKnownToBeTypeSpecifier(GetLookAheadToken(1))) {
- isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_auto, Loc,
- PrevSpec, DiagID, Policy);
- if (!isInvalid && !getLangOpts().C23)
- Diag(Tok, diag::ext_auto_storage_class)
- << FixItHint::CreateRemoval(DS.getStorageClassSpecLoc());
+ // auto cannot be combined with a type specifier in C++ (except C23).
+ if (getLangOpts().CPlusPlus && !getLangOpts().C23) {
+ if (!PrevSpec) {
+ PrevSpec = "";
+ }
+ isInvalid = true;
+ DiagID = diag::err_auto_type_specifier;
+ } else {
+ // In C23, 'auto' followed by a type specifier is a storage class
specifier.
+ isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_auto,
Loc, PrevSpec, DiagID, Policy);
+ }
+
+
} else
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_auto, Loc, PrevSpec,
DiagID, Policy);
diff --git a/clang/test/Parser/cxx-auto-type-specifier.cpp
b/clang/test/Parser/cxx-auto-type-specifier.cpp
new file mode 100644
index 0000000000000..d8bce4b7170cf
--- /dev/null
+++ b/clang/test/Parser/cxx-auto-type-specifier.cpp
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++14 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++17 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++20 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++23 %s
+// RUN: %clang_cc1 -fsyntax-only -verify=c23 -std=c23 -x c %s
+
+// Test that 'auto' cannot be combined with a type specifier in C++.
+void f() {
+ auto int x = 1; // expected-error {{'auto' cannot be combined with a type
specifier in C++}}
+}
+
+// c23-no-diagnostics
>From 9bbfa346aec4aeef67c976a58eafe3f7cd59c7cb Mon Sep 17 00:00:00 2001
From: Aditya <[email protected]>
Date: Sun, 9 Nov 2025 14:49:24 +0000
Subject: [PATCH 2/2] [Clang][Diagnostics] Simplify 'decltype(T{})' to 'T' in
diagnostics
Clang's type printer would verbosely print `decltype(T{})` in diagnostics,
even though this is equivalent to just `T`. This made error messages
unnecessarily long and harder to read.
This commit modifies `TypePrinter::printDecltypeBefore` to detect this
specific pattern. It checks if the underlying expression of a
`DecltypeType` is a default `CXXConstructExpr` (i.e., `T{}`) and, if so,
prints the constructor's type (`T`) directly instead of the full
`decltype`.
Fixes #96638.
---
clang/lib/AST/TypePrinter.cpp | 13 ++++++++++
.../SemaCXX/decltype-diagnostic-print.cpp | 25 +++++++++++++++++++
2 files changed, 38 insertions(+)
create mode 100644 clang/test/SemaCXX/decltype-diagnostic-print.cpp
diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp
index c18b2eafc722c..510923229ea11 100644
--- a/clang/lib/AST/TypePrinter.cpp
+++ b/clang/lib/AST/TypePrinter.cpp
@@ -18,6 +18,7 @@
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
+#include "clang/AST/ExprCXX.h"
#include "clang/AST/NestedNameSpecifier.h"
#include "clang/AST/PrettyPrinter.h"
#include "clang/AST/TemplateBase.h"
@@ -1321,6 +1322,18 @@ void TypePrinter::printTypeOfBefore(const TypeOfType *T,
raw_ostream &OS) {
void TypePrinter::printTypeOfAfter(const TypeOfType *T, raw_ostream &OS) {}
void TypePrinter::printDecltypeBefore(const DecltypeType *T, raw_ostream &OS) {
+ // Check for the 'decltype(T{})' pattern and simplify it to 'T'.
+ if (const Expr *E = T->getUnderlyingExpr()) {
+ E = E->IgnoreParenImpCasts();
+ if (const CXXConstructExpr *CE = dyn_cast<CXXConstructExpr>(E)) {
+ // Check if it's a default constructor (T{}) and not a list init (T{...})
+ if (CE->getNumArgs() == 0 && !CE->isListInitialization()) {
+ CE->getType().print(OS, Policy);
+ spaceBeforePlaceHolder(OS);
+ return; // Skip the default 'decltype(...)' printing
+ }
+ }
+ }
OS << "decltype(";
if (const Expr *E = T->getUnderlyingExpr()) {
PrintingPolicy ExprPolicy = Policy;
diff --git a/clang/test/SemaCXX/decltype-diagnostic-print.cpp
b/clang/test/SemaCXX/decltype-diagnostic-print.cpp
new file mode 100644
index 0000000000000..c4b075ef4ea33
--- /dev/null
+++ b/clang/test/SemaCXX/decltype-diagnostic-print.cpp
@@ -0,0 +1,25 @@
+// clang/test/SemaCXX/decltype-diagnostic-print.cpp
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+
+template <typename T>
+struct TestAssert {
+ // This static_assert will fail, forcing the compiler to print the name
+ // of the template instantiation in its diagnostic "note".
+ static_assert(sizeof(T) == 0, "Static assert to check type printing");
+};
+
+struct MySimpleType {};
+struct MyOtherType {};
+
+void test() {
+ // This will fail the static_assert.
+ TestAssert<decltype(MySimpleType{})> test1;
+ // expected-error@6 {{Static assert to check type printing}}
+ // expected-note@16 {{in instantiation of template class
'TestAssert<MySimpleType>' requested here}}
+ // CHECK-NOT: decltype(MySimpleType{})
+
+ TestAssert<decltype(MyOtherType{})> test2;
+ // expected-error@6 {{Static assert to check type printing}}
+ // expected-note@22 {{in instantiation of template class
'TestAssert<MyOtherType>' requested here}}
+ // CHECK-NOT: decltype(MyOtherType{})
+}
\ No newline at end of file
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits