From: Chris Lattner Date: Thu, 19 Feb 2009 23:45:49 +0000 (+0000) Subject: Fix a long standard problem with clang retaining "too much" sugar X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=d0344a4a6182ad704881cbbaa21cca14913d2296;p=clang Fix a long standard problem with clang retaining "too much" sugar information about types. We often print diagnostics where we say "foo_t" is bad, but the user doesn't know how foo_t is declared (because it is a typedef). Fix this by expanding sugar when present in a diagnostic (and not one of a few special cases, like vectors). Before: t.m:5:2: error: invalid operands to binary expression ('typeof(P)' and 'typeof(F)') MAX(P, F); ^~~~~~~~~ t.m:1:78: note: instantiated from: #define MAX(A,B) ({ __typeof__(A) __a = (A); __typeof__(B) __b = (B); __a < __b ? __b : __a; }) ^ After: t.m:5:2: error: invalid operands to binary expression ('typeof(P)' (aka 'struct mystruct') and 'typeof(F)' (aka 'float')) MAX(P, F); ^~~~~~~~~ t.m:1:78: note: instantiated from: #define MAX(A,B) ({ __typeof__(A) __a = (A); __typeof__(B) __b = (B); __a < __b ? __b : __a; }) ^ git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@65081 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Basic/Diagnostic.cpp b/lib/Basic/Diagnostic.cpp index 3f94a03347..83ccd22e28 100644 --- a/lib/Basic/Diagnostic.cpp +++ b/lib/Basic/Diagnostic.cpp @@ -648,9 +648,9 @@ FormatDiagnostic(llvm::SmallVectorImpl &OutStr) const { } // ---- NAMES and TYPES ---- case Diagnostic::ak_identifierinfo: { - OutStr.push_back('\''); const IdentifierInfo *II = getArgIdentifier(ArgNo); assert(ModifierLen == 0 && "No modifiers for strings yet"); + OutStr.push_back('\''); OutStr.append(II->getName(), II->getName() + II->getLength()); OutStr.push_back('\''); break; @@ -658,11 +658,9 @@ FormatDiagnostic(llvm::SmallVectorImpl &OutStr) const { case Diagnostic::ak_qualtype: case Diagnostic::ak_declarationname: case Diagnostic::ak_nameddecl: - OutStr.push_back('\''); getDiags()->ConvertArgToString(getArgKind(ArgNo), getRawArg(ArgNo), Modifier, ModifierLen, Argument, ArgumentLen, OutStr); - OutStr.push_back('\''); break; } } diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index 539457f8a6..1ffaf939ef 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -22,19 +22,39 @@ using namespace clang; /// ConvertQualTypeToStringFn - This function is used to pretty print the /// specified QualType as a string in diagnostics. static void ConvertArgToStringFn(Diagnostic::ArgumentKind Kind, intptr_t Val, - const char *Modifier, unsigned ModLen, - const char *Argument, unsigned ArgLen, - llvm::SmallVectorImpl &Output) { + const char *Modifier, unsigned ModLen, + const char *Argument, unsigned ArgLen, + llvm::SmallVectorImpl &Output) { std::string S; if (Kind == Diagnostic::ak_qualtype) { + assert(ModLen == 0 && ArgLen == 0 && + "Invalid modifier for QualType argument"); + QualType Ty(QualType::getFromOpaquePtr(reinterpret_cast(Val))); // FIXME: Playing with std::string is really slow. S = Ty.getAsString(); - - assert(ModLen == 0 && ArgLen == 0 && - "Invalid modifier for QualType argument"); + + // If this is a sugared type (like a typedef, typeof, etc), then unwrap one + // level of the sugar so that the type is more obvious to the user. + QualType DesugaredTy = Ty->getDesugaredType(); + DesugaredTy.setCVRQualifiers(DesugaredTy.getCVRQualifiers() | + Ty.getCVRQualifiers()); + + if (Ty != DesugaredTy && + // If the desugared type is a vector type, we don't want to expand it, + // it will turn into an attribute mess. People want their "vec4". + !isa(DesugaredTy) && + + // Don't desugar objc types. FIXME: THIS IS A HACK. + S != "id" && S != "Class") { + S = "'"+S+"' (aka '"; + S += DesugaredTy.getAsString(); + S += "')"; + Output.append(S.begin(), S.end()); + return; + } } else if (Kind == Diagnostic::ak_declarationname) { @@ -58,7 +78,10 @@ static void ConvertArgToStringFn(Diagnostic::ArgumentKind Kind, intptr_t Val, S = reinterpret_cast(Val)->getNameAsString(); } } + + Output.push_back('\''); Output.append(S.begin(), S.end()); + Output.push_back('\''); } diff --git a/test/Sema/declspec.c b/test/Sema/declspec.c index 6e29625792..0207b4aacc 100644 --- a/test/Sema/declspec.c +++ b/test/Sema/declspec.c @@ -16,8 +16,8 @@ static void buggy(int *x) { } // expected-error {{function definition declared ' // Type qualifiers. typedef int f(void); typedef f* fptr; -const f* v1; // expected-warning {{qualifier on function type 'f' has unspecified behavior}} -__restrict__ f* v2; // expected-error {{restrict requires a pointer or reference ('f' is invalid)}} -__restrict__ fptr v3; // expected-error {{pointer to function type 'f' may not be 'restrict' qualified}} -f *__restrict__ v4; // expected-error {{pointer to function type 'f' may not be 'restrict' qualified}} +const f* v1; // expected-warning {{qualifier on function type 'f' (aka 'int (void)') has unspecified behavior}} +__restrict__ f* v2; // expected-error {{restrict requires a pointer or reference ('f' (aka 'int (void)') is invalid)}} +__restrict__ fptr v3; // expected-error {{pointer to function type 'f' (aka 'int (void)') may not be 'restrict' qualified}} +f *__restrict__ v4; // expected-error {{pointer to function type 'f' (aka 'int (void)') may not be 'restrict' qualified}} diff --git a/test/Sema/exprs.c b/test/Sema/exprs.c index 4ddb976eb2..ba411c528d 100644 --- a/test/Sema/exprs.c +++ b/test/Sema/exprs.c @@ -64,3 +64,12 @@ void test10(int n,...) { } s; double x = s.a[0]; // should not get another error here. } + + +#define MYMAX(A,B) __extension__ ({ __typeof__(A) __a = (A); __typeof__(B) __b = (B); __a < __b ? __b : __a; }) + +struct mystruct {int A; }; +void foo(struct mystruct P, float F) { + MYMAX(P, F); // expected-error {{invalid operands to binary expression ('typeof(P)' (aka 'struct mystruct') and 'typeof(F)' (aka 'float'))}} +} + diff --git a/test/Sema/types.c b/test/Sema/types.c index 208abce3d9..da02588461 100644 --- a/test/Sema/types.c +++ b/test/Sema/types.c @@ -5,6 +5,6 @@ typedef int (*T)[2]; restrict T x; typedef int *S[2]; -restrict S y; // expected-error {{restrict requires a pointer or reference ('S' is invalid)}} +restrict S y; // expected-error {{restrict requires a pointer or reference ('S' (aka 'int *[2]') is invalid)}} diff --git a/test/SemaCXX/const-cast.cpp b/test/SemaCXX/const-cast.cpp index 0c334bf9fa..8424cf28d9 100644 --- a/test/SemaCXX/const-cast.cpp +++ b/test/SemaCXX/const-cast.cpp @@ -29,7 +29,7 @@ char ***good_const_cast_test(ccvpcvpp var) // Drop reference. Intentionally without qualifier change. char *** var5 = const_cast(var4); const int ar[100] = {0}; - int (&rar)[100] = const_cast(ar); // expected-error {{const_cast from 'int const [100]' to 'iarr' is not allowed}} + int (&rar)[100] = const_cast(ar); // expected-error {{const_cast from 'int const [100]' to 'iarr' (aka 'iar &') is not allowed}} // Array decay. Intentionally without qualifier change. int *pi = const_cast(ar); f fp = 0; @@ -56,7 +56,7 @@ short *bad_const_cast_test(char const *volatile *const volatile *var) int *(*rar)[100] = const_cast(&ar); // expected-error {{const_cast from 'int const *(*)[100]' to 'int *(*)[100]' is not allowed}} f fp1 = 0; // Function pointers. - f fp2 = const_cast(fp1); // expected-error {{const_cast to 'f', which is not a reference, pointer-to-object, or pointer-to-data-member}} + f fp2 = const_cast(fp1); // expected-error {{const_cast to 'f' (aka 'int (*)(int)'), which is not a reference, pointer-to-object, or pointer-to-data-member}} void (A::*mfn)() = 0; (void)const_cast(mfn); // expected-error {{const_cast to 'void (struct A::*)(void)', which is not a reference, pointer-to-object, or pointer-to-data-member}} return **var3; diff --git a/test/SemaCXX/constructor-initializer.cpp b/test/SemaCXX/constructor-initializer.cpp index a79b6caac9..ded9010749 100644 --- a/test/SemaCXX/constructor-initializer.cpp +++ b/test/SemaCXX/constructor-initializer.cpp @@ -37,7 +37,7 @@ public: F() : B(17), m(17), // expected-error{{member initializer 'm' does not name a non-static data member or base class}} - INT(17) // expected-error{{constructor initializer 'INT' does not name a class}} + INT(17) // expected-error{{constructor initializer 'INT' (aka 'int') does not name a class}} { } }; diff --git a/test/SemaCXX/destructor.cpp b/test/SemaCXX/destructor.cpp index 2134f4ec5c..f5b35cbfd3 100644 --- a/test/SemaCXX/destructor.cpp +++ b/test/SemaCXX/destructor.cpp @@ -27,7 +27,7 @@ struct E; typedef E E_typedef; struct E { - ~E_typedef(); // expected-error{{destructor cannot be declared using a typedef 'E_typedef' of the class name}} + ~E_typedef(); // expected-error{{destructor cannot be declared using a typedef 'E_typedef' (aka 'struct E') of the class name}} }; struct F { diff --git a/test/SemaCXX/inherit.cpp b/test/SemaCXX/inherit.cpp index 6c00218039..7e04052c40 100644 --- a/test/SemaCXX/inherit.cpp +++ b/test/SemaCXX/inherit.cpp @@ -28,5 +28,5 @@ typedef G G_copy; typedef G G_copy_2; typedef G_copy G_copy_3; -class H : G_copy, A, G_copy_2, // expected-error{{base class 'G_copy' specified more than once as a direct base class}} - public G_copy_3 { }; // expected-error{{base class 'G_copy' specified more than once as a direct base class}} +class H : G_copy, A, G_copy_2, // expected-error{{base class 'G_copy' (aka 'class G') specified more than once as a direct base class}} + public G_copy_3 { }; // expected-error{{base class 'G_copy' (aka 'class G') specified more than once as a direct base class}} diff --git a/test/SemaCXX/overloaded-operator-decl.cpp b/test/SemaCXX/overloaded-operator-decl.cpp index 812ac7ff8b..8008b20007 100644 --- a/test/SemaCXX/overloaded-operator-decl.cpp +++ b/test/SemaCXX/overloaded-operator-decl.cpp @@ -34,6 +34,6 @@ typedef int INT; typedef float FLOAT; Y& operator++(Y&); Y operator++(Y&, INT); -X operator++(X&, FLOAT); // expected-error{{parameter of overloaded post-increment operator must have type 'int' (not 'FLOAT')}} +X operator++(X&, FLOAT); // expected-error{{parameter of overloaded post-increment operator must have type 'int' (not 'FLOAT' (aka 'float'))}} int operator+; // expected-error{{'operator+' cannot be the name of a variable or data member}} diff --git a/test/SemaCXX/typedef-redecl.cpp b/test/SemaCXX/typedef-redecl.cpp index 016882feb2..c7e7d45284 100644 --- a/test/SemaCXX/typedef-redecl.cpp +++ b/test/SemaCXX/typedef-redecl.cpp @@ -3,7 +3,7 @@ typedef int INT; typedef INT REALLY_INT; // expected-note {{previous definition is here}} typedef REALLY_INT REALLY_REALLY_INT; typedef REALLY_INT BOB; -typedef float REALLY_INT; // expected-error{{typedef redefinition with different types ('float' vs 'INT')}} +typedef float REALLY_INT; // expected-error{{typedef redefinition with different types ('float' vs 'INT' (aka 'int'))}} struct X { typedef int result_type; // expected-note {{previous definition is here}} diff --git a/test/SemaTemplate/class-template-decl.cpp b/test/SemaTemplate/class-template-decl.cpp index 3978e1f04a..ff38132928 100644 --- a/test/SemaTemplate/class-template-decl.cpp +++ b/test/SemaTemplate/class-template-decl.cpp @@ -25,7 +25,7 @@ template class NonTypeTemplateParm; typedef int INT; -template class NonTypeTemplateParm; // expected-note{{previous non-type template parameter with type 'INT' is here}} +template class NonTypeTemplateParm; // expected-note{{previous non-type template parameter with type 'INT' (aka 'int') is here}} template class NonTypeTemplateParm; // expected-error{{template non-type parameter has a different type 'long' in template redeclaration}}