forked from OSchip/llvm-project
[ODRHash] Add support for array and decayed types, and parameter names and types.
llvm-svn: 301989
This commit is contained in:
parent
d919115983
commit
0255227a58
|
@ -146,7 +146,10 @@ def err_module_odr_violation_mismatch_decl_diff : Error<
|
|||
"method %4 is %select{not static|static}5|"
|
||||
"method %4 is %select{not volatile|volatile}5|"
|
||||
"method %4 is %select{not const|const}5|"
|
||||
"method %4 is %select{not inline|inline}5}3">;
|
||||
"method %4 is %select{not inline|inline}5|"
|
||||
"method %4 that has %5 parameter%s5|"
|
||||
"method %4 with %ordinal5 parameter of type %6%select{| decayed from %8}7|"
|
||||
"method %4 with %ordinal5 parameter named %6}3">;
|
||||
|
||||
def note_module_odr_violation_mismatch_decl_diff : Note<"but in '%0' found "
|
||||
"%select{"
|
||||
|
@ -166,7 +169,10 @@ def note_module_odr_violation_mismatch_decl_diff : Note<"but in '%0' found "
|
|||
"method %2 is %select{not static|static}3|"
|
||||
"method %2 is %select{not volatile|volatile}3|"
|
||||
"method %2 is %select{not const|const}3|"
|
||||
"method %2 is %select{not inline|inline}3}1">;
|
||||
"method %2 is %select{not inline|inline}3|"
|
||||
"method %2 that has %3 parameter%s3|"
|
||||
"method %2 with %ordinal3 parameter of type %4%select{| decayed from %6}5|"
|
||||
"method %2 with %ordinal3 parameter named %4}1">;
|
||||
|
||||
def warn_module_uses_date_time : Warning<
|
||||
"%select{precompiled header|module}0 uses __DATE__ or __TIME__">,
|
||||
|
|
|
@ -169,6 +169,11 @@ public:
|
|||
Inherited::VisitValueDecl(D);
|
||||
}
|
||||
|
||||
void VisitParmVarDecl(const ParmVarDecl *D) {
|
||||
// TODO: Handle default arguments.
|
||||
Inherited::VisitParmVarDecl(D);
|
||||
}
|
||||
|
||||
void VisitAccessSpecDecl(const AccessSpecDecl *D) {
|
||||
ID.AddInteger(D->getAccess());
|
||||
Inherited::VisitAccessSpecDecl(D);
|
||||
|
@ -202,6 +207,12 @@ public:
|
|||
Hash.AddBoolean(D->isPure());
|
||||
Hash.AddBoolean(D->isDeletedAsWritten());
|
||||
|
||||
ID.AddInteger(D->param_size());
|
||||
|
||||
for (auto *Param : D->parameters()) {
|
||||
Hash.AddSubDecl(Param);
|
||||
}
|
||||
|
||||
Inherited::VisitFunctionDecl(D);
|
||||
}
|
||||
|
||||
|
@ -256,6 +267,11 @@ void ODRHash::AddSubDecl(const Decl *D) {
|
|||
void ODRHash::AddCXXRecordDecl(const CXXRecordDecl *Record) {
|
||||
assert(Record && Record->hasDefinition() &&
|
||||
"Expected non-null record to be a definition.");
|
||||
|
||||
if (isa<ClassTemplateSpecializationDecl>(Record)) {
|
||||
return;
|
||||
}
|
||||
|
||||
AddDecl(Record);
|
||||
|
||||
// Filter out sub-Decls which will not be processed in order to get an
|
||||
|
@ -315,6 +331,14 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
void AddQualType(QualType T) {
|
||||
Hash.AddQualType(T);
|
||||
}
|
||||
|
||||
void VisitQualifiers(Qualifiers Quals) {
|
||||
ID.AddInteger(Quals.getAsOpaqueValue());
|
||||
}
|
||||
|
||||
void Visit(const Type *T) {
|
||||
ID.AddInteger(T->getTypeClass());
|
||||
Inherited::Visit(T);
|
||||
|
@ -322,11 +346,69 @@ public:
|
|||
|
||||
void VisitType(const Type *T) {}
|
||||
|
||||
void VisitAdjustedType(const AdjustedType *T) {
|
||||
AddQualType(T->getOriginalType());
|
||||
AddQualType(T->getAdjustedType());
|
||||
VisitType(T);
|
||||
}
|
||||
|
||||
void VisitDecayedType(const DecayedType *T) {
|
||||
AddQualType(T->getDecayedType());
|
||||
AddQualType(T->getPointeeType());
|
||||
VisitAdjustedType(T);
|
||||
}
|
||||
|
||||
void VisitArrayType(const ArrayType *T) {
|
||||
AddQualType(T->getElementType());
|
||||
ID.AddInteger(T->getSizeModifier());
|
||||
VisitQualifiers(T->getIndexTypeQualifiers());
|
||||
VisitType(T);
|
||||
}
|
||||
void VisitConstantArrayType(const ConstantArrayType *T) {
|
||||
T->getSize().Profile(ID);
|
||||
VisitArrayType(T);
|
||||
}
|
||||
|
||||
void VisitDependentSizedArrayType(const DependentSizedArrayType *T) {
|
||||
AddStmt(T->getSizeExpr());
|
||||
VisitArrayType(T);
|
||||
}
|
||||
|
||||
void VisitIncompleteArrayType(const IncompleteArrayType *T) {
|
||||
VisitArrayType(T);
|
||||
}
|
||||
|
||||
void VisitVariableArrayType(const VariableArrayType *T) {
|
||||
AddStmt(T->getSizeExpr());
|
||||
VisitArrayType(T);
|
||||
}
|
||||
|
||||
void VisitBuiltinType(const BuiltinType *T) {
|
||||
ID.AddInteger(T->getKind());
|
||||
VisitType(T);
|
||||
}
|
||||
|
||||
void VisitFunctionType(const FunctionType *T) {
|
||||
AddQualType(T->getReturnType());
|
||||
T->getExtInfo().Profile(ID);
|
||||
Hash.AddBoolean(T->isConst());
|
||||
Hash.AddBoolean(T->isVolatile());
|
||||
Hash.AddBoolean(T->isRestrict());
|
||||
VisitType(T);
|
||||
}
|
||||
|
||||
void VisitFunctionNoProtoType(const FunctionNoProtoType *T) {
|
||||
VisitFunctionType(T);
|
||||
}
|
||||
|
||||
void VisitFunctionProtoType(const FunctionProtoType *T) {
|
||||
ID.AddInteger(T->getNumParams());
|
||||
for (auto ParamType : T->getParamTypes())
|
||||
AddQualType(ParamType);
|
||||
|
||||
VisitFunctionType(T);
|
||||
}
|
||||
|
||||
void VisitTypedefType(const TypedefType *T) {
|
||||
AddDecl(T->getDecl());
|
||||
Hash.AddQualType(T->getDecl()->getUnderlyingType());
|
||||
|
|
|
@ -9316,6 +9316,9 @@ void ASTReader::diagnoseOdrViolations() {
|
|||
MethodVolatile,
|
||||
MethodConst,
|
||||
MethodInline,
|
||||
MethodNumberParameters,
|
||||
MethodParameterType,
|
||||
MethodParameterName,
|
||||
};
|
||||
|
||||
// These lambdas have the common portions of the ODR diagnostics. This
|
||||
|
@ -9346,6 +9349,12 @@ void ASTReader::diagnoseOdrViolations() {
|
|||
return Hash.CalculateHash();
|
||||
};
|
||||
|
||||
auto ComputeQualTypeODRHash = [&Hash](QualType Ty) {
|
||||
Hash.clear();
|
||||
Hash.AddQualType(Ty);
|
||||
return Hash.CalculateHash();
|
||||
};
|
||||
|
||||
switch (FirstDiffType) {
|
||||
case Other:
|
||||
case EndOfClass:
|
||||
|
@ -9640,6 +9649,76 @@ void ASTReader::diagnoseOdrViolations() {
|
|||
break;
|
||||
}
|
||||
|
||||
const unsigned FirstNumParameters = FirstMethod->param_size();
|
||||
const unsigned SecondNumParameters = SecondMethod->param_size();
|
||||
if (FirstNumParameters != SecondNumParameters) {
|
||||
ODRDiagError(FirstMethod->getLocation(),
|
||||
FirstMethod->getSourceRange(), MethodNumberParameters)
|
||||
<< FirstName << FirstNumParameters;
|
||||
ODRDiagNote(SecondMethod->getLocation(),
|
||||
SecondMethod->getSourceRange(), MethodNumberParameters)
|
||||
<< SecondName << SecondNumParameters;
|
||||
Diagnosed = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// Need this status boolean to know when break out of the switch.
|
||||
bool ParameterMismatch = false;
|
||||
for (unsigned I = 0; I < FirstNumParameters; ++I) {
|
||||
const ParmVarDecl *FirstParam = FirstMethod->getParamDecl(I);
|
||||
const ParmVarDecl *SecondParam = SecondMethod->getParamDecl(I);
|
||||
|
||||
QualType FirstParamType = FirstParam->getType();
|
||||
QualType SecondParamType = SecondParam->getType();
|
||||
if (FirstParamType != SecondParamType &&
|
||||
ComputeQualTypeODRHash(FirstParamType) !=
|
||||
ComputeQualTypeODRHash(SecondParamType)) {
|
||||
if (const DecayedType *ParamDecayedType =
|
||||
FirstParamType->getAs<DecayedType>()) {
|
||||
ODRDiagError(FirstMethod->getLocation(),
|
||||
FirstMethod->getSourceRange(), MethodParameterType)
|
||||
<< FirstName << (I + 1) << FirstParamType << true
|
||||
<< ParamDecayedType->getOriginalType();
|
||||
} else {
|
||||
ODRDiagError(FirstMethod->getLocation(),
|
||||
FirstMethod->getSourceRange(), MethodParameterType)
|
||||
<< FirstName << (I + 1) << FirstParamType << false;
|
||||
}
|
||||
|
||||
if (const DecayedType *ParamDecayedType =
|
||||
SecondParamType->getAs<DecayedType>()) {
|
||||
ODRDiagNote(SecondMethod->getLocation(),
|
||||
SecondMethod->getSourceRange(), MethodParameterType)
|
||||
<< SecondName << (I + 1) << SecondParamType << true
|
||||
<< ParamDecayedType->getOriginalType();
|
||||
} else {
|
||||
ODRDiagNote(SecondMethod->getLocation(),
|
||||
SecondMethod->getSourceRange(), MethodParameterType)
|
||||
<< SecondName << (I + 1) << SecondParamType << false;
|
||||
}
|
||||
ParameterMismatch = true;
|
||||
break;
|
||||
}
|
||||
|
||||
DeclarationName FirstParamName = FirstParam->getDeclName();
|
||||
DeclarationName SecondParamName = SecondParam->getDeclName();
|
||||
if (FirstParamName != SecondParamName) {
|
||||
ODRDiagError(FirstMethod->getLocation(),
|
||||
FirstMethod->getSourceRange(), MethodParameterName)
|
||||
<< FirstName << (I + 1) << FirstParamName;
|
||||
ODRDiagNote(SecondMethod->getLocation(),
|
||||
SecondMethod->getSourceRange(), MethodParameterName)
|
||||
<< SecondName << (I + 1) << SecondParamName;
|
||||
ParameterMismatch = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ParameterMismatch) {
|
||||
Diagnosed = true;
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -275,6 +275,33 @@ S11 s11;
|
|||
// expected-note@first.h:* {{but in 'FirstModule' found field 'x' with a different initializer}}
|
||||
#endif
|
||||
|
||||
#if defined(FIRST)
|
||||
struct S12 {
|
||||
unsigned x[5];
|
||||
};
|
||||
#elif defined(SECOND)
|
||||
struct S12 {
|
||||
unsigned x[7];
|
||||
};
|
||||
#else
|
||||
S12 s12;
|
||||
// expected-error@first.h:* {{'Field::S12::x' from module 'FirstModule' is not present in definition of 'Field::S12' in module 'SecondModule'}}
|
||||
// expected-note@second.h:* {{declaration of 'x' does not match}}
|
||||
#endif
|
||||
|
||||
#if defined(FIRST)
|
||||
struct S13 {
|
||||
unsigned x[7];
|
||||
};
|
||||
#elif defined(SECOND)
|
||||
struct S13 {
|
||||
double x[7];
|
||||
};
|
||||
#else
|
||||
S13 s13;
|
||||
// expected-error@first.h:* {{'Field::S13::x' from module 'FirstModule' is not present in definition of 'Field::S13' in module 'SecondModule'}}
|
||||
// expected-note@second.h:* {{declaration of 'x' does not match}}
|
||||
#endif
|
||||
} // namespace Field
|
||||
|
||||
namespace Method {
|
||||
|
@ -403,6 +430,91 @@ S8 s8;
|
|||
// expected-note@first.h:* {{but in 'FirstModule' found method 'A' is const}}
|
||||
#endif
|
||||
|
||||
#if defined(FIRST)
|
||||
struct S9 {
|
||||
void A(int x) {}
|
||||
void A(int x, int y) {}
|
||||
};
|
||||
#elif defined(SECOND)
|
||||
struct S9 {
|
||||
void A(int x, int y) {}
|
||||
void A(int x) {}
|
||||
};
|
||||
#else
|
||||
S9 s9;
|
||||
// expected-error@second.h:* {{'Method::S9' has different definitions in different modules; first difference is definition in module 'SecondModule' found method 'A' that has 2 parameters}}
|
||||
// expected-note@first.h:* {{but in 'FirstModule' found method 'A' that has 1 parameter}}
|
||||
#endif
|
||||
|
||||
#if defined(FIRST)
|
||||
struct S10 {
|
||||
void A(int x) {}
|
||||
void A(float x) {}
|
||||
};
|
||||
#elif defined(SECOND)
|
||||
struct S10 {
|
||||
void A(float x) {}
|
||||
void A(int x) {}
|
||||
};
|
||||
#else
|
||||
S10 s10;
|
||||
// expected-error@second.h:* {{'Method::S10' has different definitions in different modules; first difference is definition in module 'SecondModule' found method 'A' with 1st parameter of type 'float'}}
|
||||
// expected-note@first.h:* {{but in 'FirstModule' found method 'A' with 1st parameter of type 'int'}}
|
||||
#endif
|
||||
|
||||
#if defined(FIRST)
|
||||
struct S11 {
|
||||
void A(int x) {}
|
||||
};
|
||||
#elif defined(SECOND)
|
||||
struct S11 {
|
||||
void A(int y) {}
|
||||
};
|
||||
#else
|
||||
S11 s11;
|
||||
// expected-error@second.h:* {{'Method::S11' has different definitions in different modules; first difference is definition in module 'SecondModule' found method 'A' with 1st parameter named 'y'}}
|
||||
// expected-note@first.h:* {{but in 'FirstModule' found method 'A' with 1st parameter named 'x'}}
|
||||
#endif
|
||||
|
||||
#if defined(FIRST)
|
||||
struct S12 {
|
||||
void A(int x) {}
|
||||
};
|
||||
#elif defined(SECOND)
|
||||
struct S12 {
|
||||
void A(int x = 1) {}
|
||||
};
|
||||
#else
|
||||
S12 s12;
|
||||
// TODO: This should produce an error.
|
||||
#endif
|
||||
|
||||
#if defined(FIRST)
|
||||
struct S13 {
|
||||
void A(int x = 1 + 0) {}
|
||||
};
|
||||
#elif defined(SECOND)
|
||||
struct S13 {
|
||||
void A(int x = 1) {}
|
||||
};
|
||||
#else
|
||||
S13 s13;
|
||||
// TODO: This should produce an error.
|
||||
#endif
|
||||
|
||||
#if defined(FIRST)
|
||||
struct S14 {
|
||||
void A(int x[2]) {}
|
||||
};
|
||||
#elif defined(SECOND)
|
||||
struct S14 {
|
||||
void A(int x[3]) {}
|
||||
};
|
||||
#else
|
||||
S14 s14;
|
||||
// expected-error@second.h:* {{'Method::S14' has different definitions in different modules; first difference is definition in module 'SecondModule' found method 'A' with 1st parameter of type 'int *' decayed from 'int [3]'}}
|
||||
// expected-note@first.h:* {{but in 'FirstModule' found method 'A' with 1st parameter of type 'int *' decayed from 'int [2]'}}
|
||||
#endif
|
||||
} // namespace Method
|
||||
|
||||
// Naive parsing of AST can lead to cycles in processing. Ensure
|
||||
|
@ -526,37 +638,43 @@ S3 s3;
|
|||
// Interesting cases that should not cause errors. struct S should not error
|
||||
// while struct T should error at the access specifier mismatch at the end.
|
||||
namespace AllDecls {
|
||||
#define CREATE_ALL_DECL_STRUCT(NAME, ACCESS) \
|
||||
typedef int INT; \
|
||||
struct NAME { \
|
||||
public: \
|
||||
private: \
|
||||
protected: \
|
||||
static_assert(1 == 1, "Message"); \
|
||||
static_assert(2 == 2); \
|
||||
\
|
||||
int x; \
|
||||
double y; \
|
||||
\
|
||||
INT z; \
|
||||
\
|
||||
unsigned a : 1; \
|
||||
unsigned b : 2 * 2 + 5 / 2; \
|
||||
\
|
||||
mutable int c = sizeof(x + y); \
|
||||
\
|
||||
void method() {} \
|
||||
static void static_method() {} \
|
||||
virtual void virtual_method() {} \
|
||||
virtual void pure_virtual_method() = 0; \
|
||||
inline void inline_method() {} \
|
||||
void volatile_method() volatile {} \
|
||||
void const_method() const {} \
|
||||
\
|
||||
typedef int typedef_int; \
|
||||
using using_int = int; \
|
||||
\
|
||||
ACCESS: \
|
||||
#define CREATE_ALL_DECL_STRUCT(NAME, ACCESS) \
|
||||
typedef int INT; \
|
||||
struct NAME { \
|
||||
public: \
|
||||
private: \
|
||||
protected: \
|
||||
static_assert(1 == 1, "Message"); \
|
||||
static_assert(2 == 2); \
|
||||
\
|
||||
int x; \
|
||||
double y; \
|
||||
\
|
||||
INT z; \
|
||||
\
|
||||
unsigned a : 1; \
|
||||
unsigned b : 2 * 2 + 5 / 2; \
|
||||
\
|
||||
mutable int c = sizeof(x + y); \
|
||||
\
|
||||
void method() {} \
|
||||
static void static_method() {} \
|
||||
virtual void virtual_method() {} \
|
||||
virtual void pure_virtual_method() = 0; \
|
||||
inline void inline_method() {} \
|
||||
void volatile_method() volatile {} \
|
||||
void const_method() const {} \
|
||||
\
|
||||
typedef int typedef_int; \
|
||||
using using_int = int; \
|
||||
\
|
||||
void method_one_arg(int x) {} \
|
||||
void method_one_arg_default_argument(int x = 5 + 5) {} \
|
||||
void method_decayed_type(int x[5]) {} \
|
||||
\
|
||||
int constant_arr[5]; \
|
||||
\
|
||||
ACCESS: \
|
||||
};
|
||||
|
||||
#if defined(FIRST)
|
||||
|
@ -933,6 +1051,34 @@ Alpha::Alpha() {}
|
|||
#endif
|
||||
}
|
||||
|
||||
namespace ParameterTest {
|
||||
#if defined(FIRST)
|
||||
class X {};
|
||||
template <typename G>
|
||||
class S {
|
||||
public:
|
||||
typedef G Type;
|
||||
static inline G *Foo(const G *a, int * = nullptr);
|
||||
};
|
||||
|
||||
template<typename G>
|
||||
G* S<G>::Foo(const G* aaaa, int*) {}
|
||||
#elif defined(SECOND)
|
||||
template <typename G>
|
||||
class S {
|
||||
public:
|
||||
typedef G Type;
|
||||
static inline G *Foo(const G *a, int * = nullptr);
|
||||
};
|
||||
|
||||
template<typename G>
|
||||
G* S<G>::Foo(const G* asdf, int*) {}
|
||||
#else
|
||||
S<X> s;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
// Keep macros contained to one file.
|
||||
#ifdef FIRST
|
||||
#undef FIRST
|
||||
|
|
Loading…
Reference in New Issue