r305543 - [ODRHash] Hash VarDecl members.
Richard Trieu via cfe-commits
cfe-commits at lists.llvm.org
Thu Jun 15 19:44:29 PDT 2017
Author: rtrieu
Date: Thu Jun 15 21:44:29 2017
New Revision: 305543
URL: http://llvm.org/viewvc/llvm-project?rev=305543&view=rev
Log:
[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.
Modified:
cfe/trunk/include/clang/Basic/DiagnosticSerializationKinds.td
cfe/trunk/lib/AST/ODRHash.cpp
cfe/trunk/lib/Serialization/ASTReader.cpp
cfe/trunk/test/Modules/odr_hash.cpp
Modified: cfe/trunk/include/clang/Basic/DiagnosticSerializationKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSerializationKinds.td?rev=305543&r1=305542&r2=305543&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSerializationKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSerializationKinds.td Thu Jun 15 21:44:29 2017
@@ -121,10 +121,12 @@ def err_module_odr_violation_mismatch_de
"%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_de
"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_d
"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<
Modified: cfe/trunk/lib/AST/ODRHash.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ODRHash.cpp?rev=305543&r1=305542&r2=305543&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ODRHash.cpp (original)
+++ cfe/trunk/lib/AST/ODRHash.cpp Thu Jun 15 21:44:29 2017
@@ -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 De
case Decl::StaticAssert:
case Decl::TypeAlias:
case Decl::Typedef:
+ case Decl::Var:
return true;
}
}
Modified: cfe/trunk/lib/Serialization/ASTReader.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReader.cpp?rev=305543&r1=305542&r2=305543&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTReader.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTReader.cpp Thu Jun 15 21:44:29 2017
@@ -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) {
@@ -9787,6 +9829,77 @@ void ASTReader::diagnoseOdrViolations()
Diagnosed = true;
break;
}
+ 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;
}
}
Modified: cfe/trunk/test/Modules/odr_hash.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/odr_hash.cpp?rev=305543&r1=305542&r2=305543&view=diff
==============================================================================
--- cfe/trunk/test/Modules/odr_hash.cpp (original)
+++ cfe/trunk/test/Modules/odr_hash.cpp Thu Jun 15 21:44:29 2017
@@ -486,7 +486,8 @@ struct S12 {
};
#else
S12 s12;
-// TODO: This should produce an error.
+// expected-error at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at first.h:* {{'VarDecl::S6::x' from module 'FirstModule' is not present in definition of 'VarDecl::S6' in module 'SecondModule'}}
+// expected-note at 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 at first.h:* {{'VarDecl::S7::x' from module 'FirstModule' is not present in definition of 'VarDecl::S7' in module 'SecondModule'}}
+// expected-note at 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 at second.h:* {{'VarDecl::S8' has different definitions in different modules; first difference is definition in module 'SecondModule' found data member}}
+// expected-note at 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 at first.h:* {{'VarDecl::S9::x' from module 'FirstModule' is not present in definition of 'VarDecl::S9' in module 'SecondModule'}}
+// expected-note at 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 at 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 at 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 at 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 at 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 {
More information about the cfe-commits
mailing list