forked from OSchip/llvm-project
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; }) ^ llvm-svn: 65081
This commit is contained in:
parent
513f0b147e
commit
810d330cd3
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
||||
// 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());
|
||||
|
||||
assert(ModLen == 0 && ArgLen == 0 &&
|
||||
"Invalid modifier for QualType argument");
|
||||
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('\'');
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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}}
|
||||
|
||||
|
|
|
@ -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'))}}
|
||||
}
|
||||
|
||||
|
|
|
@ -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)}}
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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}}
|
||||
{
|
||||
}
|
||||
};
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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}}
|
||||
|
|
|
@ -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}}
|
||||
|
|
|
@ -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}}
|
||||
|
|
|
@ -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}}
|
||||
|
||||
|
|
Loading…
Reference in New Issue