diff --git a/clang/include/clang/Basic/DiagnosticSerializationKinds.td b/clang/include/clang/Basic/DiagnosticSerializationKinds.td index 7c9e8c8980aa..5d286ee83a31 100644 --- a/clang/include/clang/Basic/DiagnosticSerializationKinds.td +++ b/clang/include/clang/Basic/DiagnosticSerializationKinds.td @@ -121,10 +121,10 @@ 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}3">; + "protected access specifier|static assert|field|method|type alias|typedef}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}1">; + "protected access specifier|static assert|field|method|type alias|typedef}1">; def err_module_odr_violation_mismatch_decl_diff : Error< "%q0 has different definitions in different modules; first difference is " @@ -149,7 +149,9 @@ def err_module_odr_violation_mismatch_decl_diff : Error< "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">; + "method %4 with %ordinal5 parameter named %6|" + "%select{typedef|type alias}4 name %5|" + "%select{typedef|type alias}4 %5 with underlying type %6}3">; def note_module_odr_violation_mismatch_decl_diff : Note<"but in '%0' found " "%select{" @@ -172,15 +174,19 @@ def note_module_odr_violation_mismatch_decl_diff : Note<"but in '%0' found " "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">; + "method %2 with %ordinal3 parameter named %4|" + "%select{typedef|type alias}2 name %3|" + "%select{typedef|type alias}2 %3 with different underlying type %4}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|unexpected decl}3">; + "%select{||||static assert|field|method|type alias|typedef|" + "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|" "another unexpected decl}1">; def warn_duplicate_module_file_extension : Warning< diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index 94a8f609f57c..5bef65fc8900 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -9242,6 +9242,7 @@ void ASTReader::diagnoseOdrViolations() { // Used with err_module_odr_violation_mismatch_decl and // note_module_odr_violation_mismatch_decl + // This list should be the same Decl's as in ODRHash::isWhiteListedDecl enum { EndOfClass, PublicSpecifer, @@ -9250,6 +9251,8 @@ void ASTReader::diagnoseOdrViolations() { StaticAssert, Field, CXXMethod, + TypeAlias, + TypeDef, Other } FirstDiffType = Other, SecondDiffType = Other; @@ -9277,6 +9280,10 @@ void ASTReader::diagnoseOdrViolations() { return Field; case Decl::CXXMethod: return CXXMethod; + case Decl::TypeAlias: + return TypeAlias; + case Decl::Typedef: + return TypeDef; } }; @@ -9373,6 +9380,8 @@ void ASTReader::diagnoseOdrViolations() { MethodNumberParameters, MethodParameterType, MethodParameterName, + TypedefName, + TypedefType, }; // These lambdas have the common portions of the ODR diagnostics. This @@ -9748,6 +9757,38 @@ void ASTReader::diagnoseOdrViolations() { break; } + case TypeAlias: + case TypeDef: { + TypedefNameDecl *FirstTD = cast(FirstDecl); + TypedefNameDecl *SecondTD = cast(SecondDecl); + auto FirstName = FirstTD->getDeclName(); + auto SecondName = SecondTD->getDeclName(); + if (FirstName != SecondName) { + ODRDiagError(FirstTD->getLocation(), FirstTD->getSourceRange(), + TypedefName) + << (FirstDiffType == TypeAlias) << FirstName; + ODRDiagNote(SecondTD->getLocation(), SecondTD->getSourceRange(), + TypedefName) + << (FirstDiffType == TypeAlias) << SecondName; + Diagnosed = true; + break; + } + + QualType FirstType = FirstTD->getUnderlyingType(); + QualType SecondType = SecondTD->getUnderlyingType(); + if (ComputeQualTypeODRHash(FirstType) != + ComputeQualTypeODRHash(SecondType)) { + ODRDiagError(FirstTD->getLocation(), FirstTD->getSourceRange(), + TypedefType) + << (FirstDiffType == TypeAlias) << FirstName << FirstType; + ODRDiagNote(SecondTD->getLocation(), SecondTD->getSourceRange(), + TypedefType) + << (FirstDiffType == TypeAlias) << SecondName << SecondType; + Diagnosed = true; + break; + } + break; + } } if (Diagnosed == true) diff --git a/clang/test/Modules/odr_hash.cpp b/clang/test/Modules/odr_hash.cpp index a6a0b74743aa..cc953d0c0546 100644 --- a/clang/test/Modules/odr_hash.cpp +++ b/clang/test/Modules/odr_hash.cpp @@ -586,6 +586,57 @@ S3 s3; // expected-error@first.h:* {{'TypeDef::S3::a' from module 'FirstModule' is not present in definition of 'TypeDef::S3' in module 'SecondModule'}} // expected-note@second.h:* {{declaration of 'a' does not match}} #endif + +#if defined(FIRST) +struct S4 { + typedef int a; + typedef int b; +}; +#elif defined(SECOND) +struct S4 { + typedef int b; + typedef int a; +}; +#else +S4 s4; +// expected-error@second.h:* {{'TypeDef::S4' has different definitions in different modules; first difference is definition in module 'SecondModule' found typedef name 'b'}} +// expected-note@first.h:* {{but in 'FirstModule' found typedef name 'a'}} +#endif + +#if defined(FIRST) +struct S5 { + typedef int a; + typedef int b; + int x; +}; +#elif defined(SECOND) +struct S5 { + int x; + typedef int b; + typedef int a; +}; +#else +S5 s5; +// expected-error@second.h:* {{'TypeDef::S5' has different definitions in different modules; first difference is definition in module 'SecondModule' found field}} +// expected-note@first.h:* {{but in 'FirstModule' found typedef}} +#endif + +#if defined(FIRST) +typedef float F; +struct S6 { + typedef int a; + typedef F b; +}; +#elif defined(SECOND) +struct S6 { + typedef int a; + typedef float b; +}; +#else +S6 s6; +// expected-error@second.h:* {{'TypeDef::S6' has different definitions in different modules; first difference is definition in module 'SecondModule' found typedef 'b' with underlying type 'float'}} +// expected-note@first.h:* {{but in 'FirstModule' found typedef 'b' with different underlying type 'TypeDef::F' (aka 'float')}} +#endif } // namespace TypeDef namespace Using { @@ -632,6 +683,57 @@ S3 s3; // expected-error@first.h:* {{'Using::S3::a' from module 'FirstModule' is not present in definition of 'Using::S3' in module 'SecondModule'}} // expected-note@second.h:* {{declaration of 'a' does not match}} #endif + +#if defined(FIRST) +struct S4 { + using a = int; + using b = int; +}; +#elif defined(SECOND) +struct S4 { + using b = int; + using a = int; +}; +#else +S4 s4; +// expected-error@second.h:* {{'Using::S4' has different definitions in different modules; first difference is definition in module 'SecondModule' found type alias name 'b'}} +// expected-note@first.h:* {{but in 'FirstModule' found type alias name 'a'}} +#endif + +#if defined(FIRST) +struct S5 { + using a = int; + using b = int; + int x; +}; +#elif defined(SECOND) +struct S5 { + int x; + using b = int; + using a = int; +}; +#else +S5 s5; +// expected-error@second.h:* {{'Using::S5' has different definitions in different modules; first difference is definition in module 'SecondModule' found field}} +// expected-note@first.h:* {{but in 'FirstModule' found type alias}} +#endif + +#if defined(FIRST) +typedef float F; +struct S6 { + using a = int; + using b = F; +}; +#elif defined(SECOND) +struct S6 { + using a = int; + using b = float; +}; +#else +S6 s6; +// expected-error@second.h:* {{'Using::S6' has different definitions in different modules; first difference is definition in module 'SecondModule' found type alias 'b' with underlying type 'float'}} +// expected-note@first.h:* {{but in 'FirstModule' found type alias 'b' with different underlying type 'Using::F' (aka 'float')}} +#endif } // namespace Using namespace RecordType {