-
Notifications
You must be signed in to change notification settings - Fork 15.1k
[Clang][Diagnostics] Simplify 'decltype(T{})' to 'T' in diagnostics #167224
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
Thank you for submitting a Pull Request (PR) to the LLVM Project! This PR will be automatically labeled and the relevant teams will be notified. If you wish to, you can add reviewers by using the "Reviewers" section on this page. If this is not working for you, it is probably because you do not have write permissions for the repository. In which case you can instead tag reviewers by name in a comment by using If you have received no comments on your PR for a week, you can request a review by "ping"ing the PR by adding a comment “Ping”. The common courtesy "ping" rate is once a week. Please remember that you are asking for valuable time from other developers. If you have further questions, they may be answered by the LLVM GitHub User Guide. You can also ask questions in a comment on this PR, on the LLVM Discord or on the forums. |
|
@llvm/pr-subscribers-clang Author: Aditya Kolgane (adityak2006) ChangesClang's type printer would verbosely print This commit modifies Fixes #96638. Full diff: https://github.com/llvm/llvm-project/pull/167224.diff 5 Files Affected:
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/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/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
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
|
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 llvm#96638.
9bbfa34 to
f24e5b8
Compare
zyn0217
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This isn't a correct fix to me because there are other clients beyond diagnostics which might need the source fidelity for other purposes. E.g. when debugging we don't want unnecessary simplification because they can hide the underlying bugs.
Besides, if you are using an AI, please state it very explicitly in order to help us evaluate the review priority. Thanks!
Clang's type printer would verbosely print
decltype(T{})in diagnostics,even though this is equivalent to just
T. This made error messagesunnecessarily long and harder to read.
This commit modifies
TypePrinter::printDecltypeBeforeto detect thisspecific pattern. It checks if the underlying expression of a
DecltypeTypeis a defaultCXXConstructExpr(i.e.,T{}) and, if so,prints the constructor's type (
T) directly instead of the fulldecltype.Fixes #96638.