]> granicus.if.org Git - clang/commitdiff
Fix a long standard problem with clang retaining "too much" sugar
authorChris Lattner <sabre@nondot.org>
Thu, 19 Feb 2009 23:45:49 +0000 (23:45 +0000)
committerChris Lattner <sabre@nondot.org>
Thu, 19 Feb 2009 23:45:49 +0000 (23:45 +0000)
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

12 files changed:
lib/Basic/Diagnostic.cpp
lib/Sema/Sema.cpp
test/Sema/declspec.c
test/Sema/exprs.c
test/Sema/types.c
test/SemaCXX/const-cast.cpp
test/SemaCXX/constructor-initializer.cpp
test/SemaCXX/destructor.cpp
test/SemaCXX/inherit.cpp
test/SemaCXX/overloaded-operator-decl.cpp
test/SemaCXX/typedef-redecl.cpp
test/SemaTemplate/class-template-decl.cpp

index 3f94a03347502854e3a9a43bc5604bb5f4c6c9ad..83ccd22e2843b287b60fdd03898acd62c5237c3b 100644 (file)
@@ -648,9 +648,9 @@ FormatDiagnostic(llvm::SmallVectorImpl<char> &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<char> &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;
     }
   }
index 539457f8a6bd487ad1bfa39022d2403cd4b47737..1ffaf939eff11550cf05b885cb0973e80fcf2cb3 100644 (file)
@@ -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<char> &Output) {
+                                 const char *Modifier, unsigned ModLen,
+                                 const char *Argument, unsigned ArgLen,
+                                 llvm::SmallVectorImpl<char> &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<void*>(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<VectorType>(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<NamedDecl*>(Val)->getNameAsString();
     }
   }
+  
+  Output.push_back('\'');
   Output.append(S.begin(), S.end());
+  Output.push_back('\'');
 }
 
 
index 6e29625792d0d106dee2dae65226ec3dc1528568..0207b4aacc56b2968eec39b06579bfcf9c90665b 100644 (file)
@@ -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}}
 
index 4ddb976eb2e0bd8a04c94f40c9033b91487313ec..ba411c528da44ee16a8ed9470a70511a90979bbf 100644 (file)
@@ -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'))}}
+}
+
index 208abce3d9642fbfaea170b03310147d6b4078eb..da02588461353ee3f38a7809b430ff9d701ffb95 100644 (file)
@@ -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)}}
 
 
index 0c334bf9faa51fa807e43039405cfdb5ef2bfa9e..8424cf28d98db05833533e8c59100ee51c785f1c 100644 (file)
@@ -29,7 +29,7 @@ char ***good_const_cast_test(ccvpcvpp var)
   // Drop reference. Intentionally without qualifier change.
   char *** var5 = const_cast<cppp>(var4);
   const int ar[100] = {0};
-  int (&rar)[100] = const_cast<iarr>(ar); // expected-error {{const_cast from 'int const [100]' to 'iarr' is not allowed}}
+  int (&rar)[100] = const_cast<iarr>(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<int*>(ar);
   f fp = 0;
@@ -56,7 +56,7 @@ short *bad_const_cast_test(char const *volatile *const volatile *var)
   int *(*rar)[100] = const_cast<int *(*)[100]>(&ar); // expected-error {{const_cast from 'int const *(*)[100]' to 'int *(*)[100]' is not allowed}}
   f fp1 = 0;
   // Function pointers.
-  f fp2 = const_cast<f>(fp1); // expected-error {{const_cast to 'f', which is not a reference, pointer-to-object, or pointer-to-data-member}}
+  f fp2 = const_cast<f>(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<void (A::*)()>(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;
index a79b6caac983f28d03b2fd2a675bb159e8ce16b0..ded901074958b1de2be5ac2100c35e6f8cb78e0d 100644 (file)
@@ -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}}
   { 
   }
 };
index 2134f4ec5c757d78280122736e4cd5ed1f7e7eb2..f5b35cbfd39a31e62beaedc7f7430931f6f5bd2d 100644 (file)
@@ -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 {
index 6c00218039eafb29eb22789aef8ed5883f485a3a..7e04052c4021d6e657a0ad756a9213cd55b43a8e 100644 (file)
@@ -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}}
index 812ac7ff8b932667d692384fb54f158405d4c009..8008b20007448dfb1e4a0539523f3c28a6b30a6a 100644 (file)
@@ -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}}
index 016882feb2bef4559de3b4f0b5f83c625d7450f7..c7e7d45284c0f3e72eff6bbdb05d9e1fede99c75 100644 (file)
@@ -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}}
index 3978e1f04a1dd238b3660c60937fc04361d31df4..ff381329283ea11574d319c286a5a4ee21a6c1f5 100644 (file)
@@ -25,7 +25,7 @@ template<int N> class NonTypeTemplateParm;
 
 typedef int INT;
 
-template<INT M> class NonTypeTemplateParm; // expected-note{{previous non-type template parameter with type 'INT' is here}}
+template<INT M> class NonTypeTemplateParm; // expected-note{{previous non-type template parameter with type 'INT' (aka 'int') is here}}
 
 template<long> class NonTypeTemplateParm; // expected-error{{template non-type parameter has a different type 'long' in template redeclaration}}