diff options
author | Richard Trieu <rtrieu@google.com> | 2017-06-16 02:44:29 +0000 |
---|---|---|
committer | Richard Trieu <rtrieu@google.com> | 2017-06-16 02:44:29 +0000 |
commit | 6e13ff33c89369a959eef627ae4f9acf956490ad (patch) | |
tree | 9e7688b9fc4a08fb4620b7a707a040dfe3060021 /clang | |
parent | af0f33a8532e2f28d39e92a43a59e694f20c0137 (diff) | |
download | bcm5719-llvm-6e13ff33c89369a959eef627ae4f9acf956490ad.tar.gz bcm5719-llvm-6e13ff33c89369a959eef627ae4f9acf956490ad.zip |
[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
Diffstat (limited to 'clang')
-rw-r--r-- | clang/include/clang/Basic/DiagnosticSerializationKinds.td | 30 | ||||
-rw-r--r-- | clang/lib/AST/ODRHash.cpp | 12 | ||||
-rw-r--r-- | clang/lib/Serialization/ASTReader.cpp | 113 | ||||
-rw-r--r-- | clang/test/Modules/odr_hash.cpp | 179 |
4 files changed, 326 insertions, 8 deletions
diff --git a/clang/include/clang/Basic/DiagnosticSerializationKinds.td b/clang/include/clang/Basic/DiagnosticSerializationKinds.td index 5d286ee83a3..0a59a633232 100644 --- a/clang/include/clang/Basic/DiagnosticSerializationKinds.td +++ b/clang/include/clang/Basic/DiagnosticSerializationKinds.td @@ -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< diff --git a/clang/lib/AST/ODRHash.cpp b/clang/lib/AST/ODRHash.cpp index 3bf9896985e..05bed658f3f 100644 --- a/clang/lib/AST/ODRHash.cpp +++ b/clang/lib/AST/ODRHash.cpp @@ -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; } } diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index 5bef65fc890..eeb0132c169 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -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) diff --git a/clang/test/Modules/odr_hash.cpp b/clang/test/Modules/odr_hash.cpp index 28b05a53564..c94940c73eb 100644 --- a/clang/test/Modules/odr_hash.cpp +++ b/clang/test/Modules/odr_hash.cpp @@ -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 { |