forked from OSchip/llvm-project
[ODRHash] Hash VarDecl members.
These VarDecl's are static data members of classes. Since the initializers are also hashed, this also provides checking for default arguments to methods. llvm-svn: 305543
This commit is contained in:
parent
af0f33a853
commit
6e13ff33c8
|
@ -121,10 +121,12 @@ def err_module_odr_violation_mismatch_decl : Error<
|
|||
"%q0 has different definitions in different modules; first difference is "
|
||||
"%select{definition in module '%2'|defined here}1 found "
|
||||
"%select{end of class|public access specifier|private access specifier|"
|
||||
"protected access specifier|static assert|field|method|type alias|typedef}3">;
|
||||
"protected access specifier|static assert|field|method|type alias|typedef|"
|
||||
"data member}3">;
|
||||
def note_module_odr_violation_mismatch_decl : Note<"but in '%0' found "
|
||||
"%select{end of class|public access specifier|private access specifier|"
|
||||
"protected access specifier|static assert|field|method|type alias|typedef}1">;
|
||||
"protected access specifier|static assert|field|method|type alias|typedef|"
|
||||
"data member}1">;
|
||||
|
||||
def err_module_odr_violation_mismatch_decl_diff : Error<
|
||||
"%q0 has different definitions in different modules; first difference is "
|
||||
|
@ -150,8 +152,16 @@ def err_module_odr_violation_mismatch_decl_diff : Error<
|
|||
"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|"
|
||||
"method %4 with %ordinal5 parameter with%select{out|}6 a default argument|"
|
||||
"method %4 with %ordinal5 parameter with a default argument|"
|
||||
"%select{typedef|type alias}4 name %5|"
|
||||
"%select{typedef|type alias}4 %5 with underlying type %6}3">;
|
||||
"%select{typedef|type alias}4 %5 with underlying type %6|"
|
||||
"data member with name %4|"
|
||||
"data member %4 with type %5|"
|
||||
"data member %4 with%select{out|}5 an initializer|"
|
||||
"data member %4 with an initializer|"
|
||||
"data member %4 %select{is constexpr|is not constexpr}5|"
|
||||
"}3">;
|
||||
|
||||
def note_module_odr_violation_mismatch_decl_diff : Note<"but in '%0' found "
|
||||
"%select{"
|
||||
|
@ -175,18 +185,26 @@ def note_module_odr_violation_mismatch_decl_diff : Note<"but in '%0' found "
|
|||
"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|"
|
||||
"method %2 with %ordinal3 parameter with%select{out|}4 a default argument|"
|
||||
"method %2 with %ordinal3 parameter with a different default argument|"
|
||||
"%select{typedef|type alias}2 name %3|"
|
||||
"%select{typedef|type alias}2 %3 with different underlying type %4}1">;
|
||||
"%select{typedef|type alias}2 %3 with different underlying type %4|"
|
||||
"data member with name %2|"
|
||||
"data member %2 with different type %3|"
|
||||
"data member %2 with%select{out|}3 an initializer|"
|
||||
"data member %2 with a different initializer|"
|
||||
"data member %2 %select{is constexpr|is not constexpr}3|"
|
||||
"}1">;
|
||||
|
||||
def err_module_odr_violation_mismatch_decl_unknown : Error<
|
||||
"%q0 %select{with definition in module '%2'|defined here}1 has different "
|
||||
"definitions in different modules; first difference is this "
|
||||
"%select{||||static assert|field|method|type alias|typedef|"
|
||||
"%select{||||static assert|field|method|type alias|typedef|data member|"
|
||||
"unexpected decl}3">;
|
||||
def note_module_odr_violation_mismatch_decl_unknown : Note<
|
||||
"but in '%0' found "
|
||||
"%select{||||different static assert|different field|different method|"
|
||||
"different type alias|different typedef|"
|
||||
"different type alias|different typedef|different data member|"
|
||||
"another unexpected decl}1">;
|
||||
|
||||
def warn_duplicate_module_file_extension : Warning<
|
||||
|
|
|
@ -252,6 +252,17 @@ public:
|
|||
Inherited::VisitValueDecl(D);
|
||||
}
|
||||
|
||||
void VisitVarDecl(const VarDecl *D) {
|
||||
Hash.AddBoolean(D->isStaticLocal());
|
||||
Hash.AddBoolean(D->isConstexpr());
|
||||
const bool HasInit = D->hasInit();
|
||||
Hash.AddBoolean(HasInit);
|
||||
if (HasInit) {
|
||||
AddStmt(D->getInit());
|
||||
}
|
||||
Inherited::VisitVarDecl(D);
|
||||
}
|
||||
|
||||
void VisitParmVarDecl(const ParmVarDecl *D) {
|
||||
// TODO: Handle default arguments.
|
||||
Inherited::VisitParmVarDecl(D);
|
||||
|
@ -336,6 +347,7 @@ bool ODRHash::isWhitelistedDecl(const Decl *D, const CXXRecordDecl *Parent) {
|
|||
case Decl::StaticAssert:
|
||||
case Decl::TypeAlias:
|
||||
case Decl::Typedef:
|
||||
case Decl::Var:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9253,6 +9253,7 @@ void ASTReader::diagnoseOdrViolations() {
|
|||
CXXMethod,
|
||||
TypeAlias,
|
||||
TypeDef,
|
||||
Var,
|
||||
Other
|
||||
} FirstDiffType = Other,
|
||||
SecondDiffType = Other;
|
||||
|
@ -9284,6 +9285,8 @@ void ASTReader::diagnoseOdrViolations() {
|
|||
return TypeAlias;
|
||||
case Decl::Typedef:
|
||||
return TypeDef;
|
||||
case Decl::Var:
|
||||
return Var;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -9380,8 +9383,15 @@ void ASTReader::diagnoseOdrViolations() {
|
|||
MethodNumberParameters,
|
||||
MethodParameterType,
|
||||
MethodParameterName,
|
||||
MethodParameterSingleDefaultArgument,
|
||||
MethodParameterDifferentDefaultArgument,
|
||||
TypedefName,
|
||||
TypedefType,
|
||||
VarName,
|
||||
VarType,
|
||||
VarSingleInitializer,
|
||||
VarDifferentInitializer,
|
||||
VarConstexpr,
|
||||
};
|
||||
|
||||
// These lambdas have the common portions of the ODR diagnostics. This
|
||||
|
@ -9748,6 +9758,38 @@ void ASTReader::diagnoseOdrViolations() {
|
|||
ParameterMismatch = true;
|
||||
break;
|
||||
}
|
||||
|
||||
const Expr *FirstInit = FirstParam->getInit();
|
||||
const Expr *SecondInit = SecondParam->getInit();
|
||||
if ((FirstInit == nullptr) != (SecondInit == nullptr)) {
|
||||
ODRDiagError(FirstMethod->getLocation(),
|
||||
FirstMethod->getSourceRange(),
|
||||
MethodParameterSingleDefaultArgument)
|
||||
<< FirstName << (I + 1) << (FirstInit == nullptr)
|
||||
<< (FirstInit ? FirstInit->getSourceRange() : SourceRange());
|
||||
ODRDiagNote(SecondMethod->getLocation(),
|
||||
SecondMethod->getSourceRange(),
|
||||
MethodParameterSingleDefaultArgument)
|
||||
<< SecondName << (I + 1) << (SecondInit == nullptr)
|
||||
<< (SecondInit ? SecondInit->getSourceRange() : SourceRange());
|
||||
ParameterMismatch = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (FirstInit && SecondInit &&
|
||||
ComputeODRHash(FirstInit) != ComputeODRHash(SecondInit)) {
|
||||
ODRDiagError(FirstMethod->getLocation(),
|
||||
FirstMethod->getSourceRange(),
|
||||
MethodParameterDifferentDefaultArgument)
|
||||
<< FirstName << (I + 1) << FirstInit->getSourceRange();
|
||||
ODRDiagNote(SecondMethod->getLocation(),
|
||||
SecondMethod->getSourceRange(),
|
||||
MethodParameterDifferentDefaultArgument)
|
||||
<< SecondName << (I + 1) << SecondInit->getSourceRange();
|
||||
ParameterMismatch = true;
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (ParameterMismatch) {
|
||||
|
@ -9789,6 +9831,77 @@ void ASTReader::diagnoseOdrViolations() {
|
|||
}
|
||||
break;
|
||||
}
|
||||
case Var: {
|
||||
VarDecl *FirstVD = cast<VarDecl>(FirstDecl);
|
||||
VarDecl *SecondVD = cast<VarDecl>(SecondDecl);
|
||||
auto FirstName = FirstVD->getDeclName();
|
||||
auto SecondName = SecondVD->getDeclName();
|
||||
if (FirstName != SecondName) {
|
||||
ODRDiagError(FirstVD->getLocation(), FirstVD->getSourceRange(),
|
||||
VarName)
|
||||
<< FirstName;
|
||||
ODRDiagNote(SecondVD->getLocation(), SecondVD->getSourceRange(),
|
||||
VarName)
|
||||
<< SecondName;
|
||||
Diagnosed = true;
|
||||
break;
|
||||
}
|
||||
|
||||
QualType FirstType = FirstVD->getType();
|
||||
QualType SecondType = SecondVD->getType();
|
||||
if (ComputeQualTypeODRHash(FirstType) !=
|
||||
ComputeQualTypeODRHash(SecondType)) {
|
||||
ODRDiagError(FirstVD->getLocation(), FirstVD->getSourceRange(),
|
||||
VarType)
|
||||
<< FirstName << FirstType;
|
||||
ODRDiagNote(SecondVD->getLocation(), SecondVD->getSourceRange(),
|
||||
VarType)
|
||||
<< SecondName << SecondType;
|
||||
Diagnosed = true;
|
||||
break;
|
||||
}
|
||||
|
||||
const Expr *FirstInit = FirstVD->getInit();
|
||||
const Expr *SecondInit = SecondVD->getInit();
|
||||
if ((FirstInit == nullptr) != (SecondInit == nullptr)) {
|
||||
ODRDiagError(FirstVD->getLocation(), FirstVD->getSourceRange(),
|
||||
VarSingleInitializer)
|
||||
<< FirstName << (FirstInit == nullptr)
|
||||
<< (FirstInit ? FirstInit->getSourceRange(): SourceRange());
|
||||
ODRDiagNote(SecondVD->getLocation(), SecondVD->getSourceRange(),
|
||||
VarSingleInitializer)
|
||||
<< SecondName << (SecondInit == nullptr)
|
||||
<< (SecondInit ? SecondInit->getSourceRange() : SourceRange());
|
||||
Diagnosed = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (FirstInit && SecondInit &&
|
||||
ComputeODRHash(FirstInit) != ComputeODRHash(SecondInit)) {
|
||||
ODRDiagError(FirstVD->getLocation(), FirstVD->getSourceRange(),
|
||||
VarDifferentInitializer)
|
||||
<< FirstName << FirstInit->getSourceRange();
|
||||
ODRDiagNote(SecondVD->getLocation(), SecondVD->getSourceRange(),
|
||||
VarDifferentInitializer)
|
||||
<< SecondName << SecondInit->getSourceRange();
|
||||
Diagnosed = true;
|
||||
break;
|
||||
}
|
||||
|
||||
const bool FirstIsConstexpr = FirstVD->isConstexpr();
|
||||
const bool SecondIsConstexpr = SecondVD->isConstexpr();
|
||||
if (FirstIsConstexpr != SecondIsConstexpr) {
|
||||
ODRDiagError(FirstVD->getLocation(), FirstVD->getSourceRange(),
|
||||
VarConstexpr)
|
||||
<< FirstName << FirstIsConstexpr;
|
||||
ODRDiagNote(SecondVD->getLocation(), SecondVD->getSourceRange(),
|
||||
VarConstexpr)
|
||||
<< SecondName << SecondIsConstexpr;
|
||||
Diagnosed = true;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (Diagnosed == true)
|
||||
|
|
|
@ -486,7 +486,8 @@ struct S12 {
|
|||
};
|
||||
#else
|
||||
S12 s12;
|
||||
// TODO: This should produce an error.
|
||||
// expected-error@second.h:* {{'Method::S12' has different definitions in different modules; first difference is definition in module 'SecondModule' found method 'A' with 1st parameter without a default argument}}
|
||||
// expected-note@first.h:* {{but in 'FirstModule' found method 'A' with 1st parameter with a default argument}}
|
||||
#endif
|
||||
|
||||
#if defined(FIRST)
|
||||
|
@ -499,7 +500,8 @@ struct S13 {
|
|||
};
|
||||
#else
|
||||
S13 s13;
|
||||
// TODO: This should produce an error.
|
||||
// expected-error@second.h:* {{'Method::S13' has different definitions in different modules; first difference is definition in module 'SecondModule' found method 'A' with 1st parameter with a default argument}}
|
||||
// expected-note@first.h:* {{but in 'FirstModule' found method 'A' with 1st parameter with a different default argument}}
|
||||
#endif
|
||||
|
||||
#if defined(FIRST)
|
||||
|
@ -1112,6 +1114,179 @@ using TemplateTypeParmType::S2;
|
|||
#endif
|
||||
}
|
||||
|
||||
namespace VarDecl {
|
||||
#if defined(FIRST)
|
||||
struct S1 {
|
||||
static int x;
|
||||
static int y;
|
||||
};
|
||||
#elif defined(SECOND)
|
||||
struct S1 {
|
||||
static int y;
|
||||
static int x;
|
||||
};
|
||||
#else
|
||||
S1 s1;
|
||||
// expected-error@second.h:* {{'VarDecl::S1' has different definitions in different modules; first difference is definition in module 'SecondModule' found data member with name 'y'}}
|
||||
// expected-note@first.h:* {{but in 'FirstModule' found data member with name 'x'}}
|
||||
#endif
|
||||
|
||||
#if defined(FIRST)
|
||||
struct S2 {
|
||||
static int x;
|
||||
};
|
||||
#elif defined(SECOND)
|
||||
using I = int;
|
||||
struct S2 {
|
||||
static I x;
|
||||
};
|
||||
#else
|
||||
S2 s2;
|
||||
// expected-error@second.h:* {{'VarDecl::S2' has different definitions in different modules; first difference is definition in module 'SecondModule' found data member 'x' with type 'VarDecl::I' (aka 'int')}}
|
||||
// expected-note@first.h:* {{but in 'FirstModule' found data member 'x' with different type 'int'}}
|
||||
#endif
|
||||
|
||||
#if defined(FIRST)
|
||||
struct S3 {
|
||||
static const int x = 1;
|
||||
};
|
||||
#elif defined(SECOND)
|
||||
struct S3 {
|
||||
static const int x;
|
||||
};
|
||||
#else
|
||||
S3 s3;
|
||||
// expected-error@second.h:* {{'VarDecl::S3' has different definitions in different modules; first difference is definition in module 'SecondModule' found data member 'x' with an initializer}}
|
||||
// expected-note@first.h:* {{but in 'FirstModule' found data member 'x' without an initializer}}
|
||||
#endif
|
||||
|
||||
#if defined(FIRST)
|
||||
struct S4 {
|
||||
static const int x = 1;
|
||||
};
|
||||
#elif defined(SECOND)
|
||||
struct S4 {
|
||||
static const int x = 2;
|
||||
};
|
||||
#else
|
||||
S4 s4;
|
||||
// expected-error@second.h:* {{'VarDecl::S4' has different definitions in different modules; first difference is definition in module 'SecondModule' found data member 'x' with an initializer}}
|
||||
// expected-note@first.h:* {{but in 'FirstModule' found data member 'x' with a different initializer}}
|
||||
#endif
|
||||
|
||||
#if defined(FIRST)
|
||||
struct S5 {
|
||||
static const int x = 1;
|
||||
};
|
||||
#elif defined(SECOND)
|
||||
struct S5 {
|
||||
static constexpr int x = 1;
|
||||
};
|
||||
#else
|
||||
S5 s5;
|
||||
// expected-error@second.h:* {{'VarDecl::S5' has different definitions in different modules; first difference is definition in module 'SecondModule' found data member 'x' is not constexpr}}
|
||||
// expected-note@first.h:* {{but in 'FirstModule' found data member 'x' is constexpr}}
|
||||
#endif
|
||||
|
||||
#if defined(FIRST)
|
||||
struct S6 {
|
||||
static const int x = 1;
|
||||
};
|
||||
#elif defined(SECOND)
|
||||
struct S6 {
|
||||
static const int y = 1;
|
||||
};
|
||||
#else
|
||||
S6 s6;
|
||||
// expected-error@first.h:* {{'VarDecl::S6::x' from module 'FirstModule' is not present in definition of 'VarDecl::S6' in module 'SecondModule'}}
|
||||
// expected-note@second.h:* {{definition has no member 'x'}}
|
||||
#endif
|
||||
|
||||
#if defined(FIRST)
|
||||
struct S7 {
|
||||
static const int x = 1;
|
||||
};
|
||||
#elif defined(SECOND)
|
||||
struct S7 {
|
||||
static const unsigned x = 1;
|
||||
};
|
||||
#else
|
||||
S7 s7;
|
||||
// expected-error@first.h:* {{'VarDecl::S7::x' from module 'FirstModule' is not present in definition of 'VarDecl::S7' in module 'SecondModule'}}
|
||||
// expected-note@second.h:* {{declaration of 'x' does not match}}
|
||||
#endif
|
||||
|
||||
#if defined(FIRST)
|
||||
struct S8 {
|
||||
public:
|
||||
static const int x = 1;
|
||||
};
|
||||
#elif defined(SECOND)
|
||||
struct S8 {
|
||||
static const int x = 1;
|
||||
public:
|
||||
};
|
||||
#else
|
||||
S8 s8;
|
||||
// expected-error@second.h:* {{'VarDecl::S8' has different definitions in different modules; first difference is definition in module 'SecondModule' found data member}}
|
||||
// expected-note@first.h:* {{but in 'FirstModule' found public access specifier}}
|
||||
#endif
|
||||
|
||||
#if defined(FIRST)
|
||||
struct S9 {
|
||||
static const int x = 1;
|
||||
};
|
||||
#elif defined(SECOND)
|
||||
struct S9 {
|
||||
static int x;
|
||||
};
|
||||
#else
|
||||
S9 s9;
|
||||
// expected-error@first.h:* {{'VarDecl::S9::x' from module 'FirstModule' is not present in definition of 'VarDecl::S9' in module 'SecondModule'}}
|
||||
// expected-note@second.h:* {{declaration of 'x' does not match}}
|
||||
#endif
|
||||
|
||||
#if defined(FIRST)
|
||||
template <typename T>
|
||||
struct S {
|
||||
struct R {
|
||||
void foo(T x = 0) {}
|
||||
};
|
||||
};
|
||||
#elif defined(SECOND)
|
||||
template <typename T>
|
||||
struct S {
|
||||
struct R {
|
||||
void foo(T x = 1) {}
|
||||
};
|
||||
};
|
||||
#else
|
||||
void run() {
|
||||
S<int>::R().foo();
|
||||
}
|
||||
// expected-error@second.h:* {{'VarDecl::S::R' has different definitions in different modules; first difference is definition in module 'SecondModule' found method 'foo' with 1st parameter with a default argument}}
|
||||
// expected-note@first.h:* {{but in 'FirstModule' found method 'foo' with 1st parameter with a different default argument}}
|
||||
#endif
|
||||
|
||||
#if defined(FIRST)
|
||||
template <typename alpha> struct Bravo {
|
||||
void charlie(bool delta = false) {}
|
||||
};
|
||||
typedef Bravo<char> echo;
|
||||
echo foxtrot;
|
||||
#elif defined(SECOND)
|
||||
template <typename alpha> struct Bravo {
|
||||
void charlie(bool delta = (false)) {}
|
||||
};
|
||||
typedef Bravo<char> echo;
|
||||
echo foxtrot;
|
||||
#else
|
||||
Bravo<char> golf;
|
||||
// expected-error@second.h:* {{'VarDecl::Bravo' has different definitions in different modules; first difference is definition in module 'SecondModule' found method 'charlie' with 1st parameter with a default argument}}
|
||||
// expected-note@first.h:* {{but in 'FirstModule' found method 'charlie' with 1st parameter with a different default argument}}
|
||||
#endif
|
||||
}
|
||||
|
||||
// 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 {
|
||||
|
|
Loading…
Reference in New Issue