Index: clang/lib/AST/ODRHash.cpp =================================================================== --- clang/lib/AST/ODRHash.cpp +++ clang/lib/AST/ODRHash.cpp @@ -295,9 +295,9 @@ } void VisitValueDecl(const ValueDecl *D) { - if (!isa(D)) { - AddQualType(D->getType()); - } + if (auto *DD = dyn_cast(D); DD && DD->getTypeSourceInfo()) + AddQualType(DD->getTypeSourceInfo()->getType()); + Inherited::VisitValueDecl(D); } @@ -351,7 +351,7 @@ void VisitObjCPropertyDecl(const ObjCPropertyDecl *D) { ID.AddInteger(D->getPropertyAttributes()); ID.AddInteger(D->getPropertyImplementation()); - AddQualType(D->getType()); + AddQualType(D->getTypeSourceInfo()->getType()); AddDecl(D); Inherited::VisitObjCPropertyDecl(D); @@ -394,7 +394,9 @@ AddDecl(Method); - AddQualType(Method->getReturnType()); + if (Method->getReturnTypeSourceInfo()) + AddQualType(Method->getReturnTypeSourceInfo()->getType()); + ID.AddInteger(Method->param_size()); for (auto Param : Method->parameters()) Hash.AddSubDecl(Param); @@ -593,7 +595,7 @@ ID.AddInteger(Record->getNumBases()); auto Bases = Record->bases(); for (const auto &Base : Bases) { - AddQualType(Base.getType()); + AddQualType(Base.getTypeSourceInfo()->getType()); ID.AddInteger(Base.isVirtual()); ID.AddInteger(Base.getAccessSpecifierAsWritten()); } @@ -859,52 +861,8 @@ ID.AddInteger(Quals.getAsOpaqueValue()); } - // Return the RecordType if the typedef only strips away a keyword. - // Otherwise, return the original type. - static const Type *RemoveTypedef(const Type *T) { - const auto *TypedefT = dyn_cast(T); - if (!TypedefT) { - return T; - } - - const TypedefNameDecl *D = TypedefT->getDecl(); - QualType UnderlyingType = D->getUnderlyingType(); - - if (UnderlyingType.hasLocalQualifiers()) { - return T; - } - - const auto *ElaboratedT = dyn_cast(UnderlyingType); - if (!ElaboratedT) { - return T; - } - - if (ElaboratedT->getQualifier() != nullptr) { - return T; - } - - QualType NamedType = ElaboratedT->getNamedType(); - if (NamedType.hasLocalQualifiers()) { - return T; - } - - const auto *RecordT = dyn_cast(NamedType); - if (!RecordT) { - return T; - } - - const IdentifierInfo *TypedefII = TypedefT->getDecl()->getIdentifier(); - const IdentifierInfo *RecordII = RecordT->getDecl()->getIdentifier(); - if (!TypedefII || !RecordII || - TypedefII->getName() != RecordII->getName()) { - return T; - } - - return RecordT; - } - void Visit(const Type *T) { - T = RemoveTypedef(T); + // T = RemoveTypedef(T); ID.AddInteger(T->getTypeClass()); Inherited::Visit(T); } @@ -912,29 +870,7 @@ void VisitType(const Type *T) {} void VisitAdjustedType(const AdjustedType *T) { - QualType Original = T->getOriginalType(); - QualType Adjusted = T->getAdjustedType(); - - // The original type and pointee type can be the same, as in the case of - // function pointers decaying to themselves. Set a bool and only process - // the type once, to prevent doubling the work. - SplitQualType split = Adjusted.split(); - if (auto Pointer = dyn_cast(split.Ty)) { - if (Pointer->getPointeeType() == Original) { - Hash.AddBoolean(true); - ID.AddInteger(split.Quals.getAsOpaqueValue()); - AddQualType(Original); - VisitType(T); - return; - } - } - - // The original type and pointee type are different, such as in the case - // of a array decaying to an element pointer. Set a bool to false and - // process both types. - Hash.AddBoolean(false); - AddQualType(Original); - AddQualType(Adjusted); + AddQualType(T->getOriginalType()); VisitType(T); } @@ -973,7 +909,6 @@ void VisitAttributedType(const AttributedType *T) { ID.AddInteger(T->getAttrKind()); AddQualType(T->getModifiedType()); - AddQualType(T->getEquivalentType()); VisitType(T); } @@ -995,7 +930,6 @@ void VisitDecltypeType(const DecltypeType *T) { AddStmt(T->getUnderlyingExpr()); - AddQualType(T->getUnderlyingType()); VisitType(T); } @@ -1184,31 +1118,12 @@ void VisitTypedefType(const TypedefType *T) { AddDecl(T->getDecl()); - QualType UnderlyingType = T->getDecl()->getUnderlyingType(); - VisitQualifiers(UnderlyingType.getQualifiers()); - while (true) { - if (const TypedefType *Underlying = - dyn_cast(UnderlyingType.getTypePtr())) { - UnderlyingType = Underlying->getDecl()->getUnderlyingType(); - continue; - } - if (const ElaboratedType *Underlying = - dyn_cast(UnderlyingType.getTypePtr())) { - UnderlyingType = Underlying->getNamedType(); - continue; - } - - break; - } - AddType(UnderlyingType.getTypePtr()); VisitType(T); } void VisitTypeOfExprType(const TypeOfExprType *T) { AddStmt(T->getUnderlyingExpr()); Hash.AddBoolean(T->isSugared()); - if (T->isSugared()) - AddQualType(T->desugar()); VisitType(T); } Index: clang/test/Modules/odr_hash-gnu.cpp =================================================================== --- clang/test/Modules/odr_hash-gnu.cpp +++ clang/test/Modules/odr_hash-gnu.cpp @@ -65,8 +65,7 @@ // expected-error@first.h:* {{'Types::TypeOfExpr::Invalid1' has different definitions in different modules; first difference is definition in module 'FirstModule' found field 'x' with type 'typeof (1 + 2)' (aka 'int')}} // expected-note@second.h:* {{but in 'SecondModule' found field 'x' with type 'typeof (3)' (aka 'int')}} Invalid2 i2; -// expected-error@second.h:* {{'Types::TypeOfExpr::Invalid2::x' from module 'SecondModule' is not present in definition of 'Types::TypeOfExpr::Invalid2' in module 'FirstModule'}} -// expected-note@first.h:* {{declaration of 'x' does not match}} +// FIXME: Valid v; #endif } // namespace TypeOfExpr @@ -113,8 +112,7 @@ // expected-error@first.h:* {{'Types::TypeOf::Invalid2' has different definitions in different modules; first difference is definition in module 'FirstModule' found field 'x' with type 'typeof(int)' (aka 'int')}} // expected-note@second.h:* {{but in 'SecondModule' found field 'x' with type 'typeof(I)' (aka 'int')}} Invalid3 i3; -// expected-error@second.h:* {{'Types::TypeOf::Invalid3::x' from module 'SecondModule' is not present in definition of 'Types::TypeOf::Invalid3' in module 'FirstModule'}} -// expected-note@first.h:* {{declaration of 'x' does not match}} +// FIXME: Valid v; #endif } // namespace TypeOf Index: clang/test/Modules/odr_hash.cpp =================================================================== --- clang/test/Modules/odr_hash.cpp +++ clang/test/Modules/odr_hash.cpp @@ -1046,8 +1046,7 @@ }; #else 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}} +// FIXME: Shouldn't we diagnose on this? #endif #if defined(FIRST) @@ -1172,8 +1171,7 @@ }; #else 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}} +// FIXME: #endif #if defined(FIRST) @@ -1361,8 +1359,7 @@ }; #else S1 s1; -// expected-error@first.h:* {{'ElaboratedType::S1::x' from module 'FirstModule' is not present in definition of 'ElaboratedType::S1' in module 'SecondModule'}} -// expected-note@second.h:* {{declaration of 'x' does not match}} +// FIXME: #endif #define DECLS \ @@ -3616,8 +3613,7 @@ // expected-error@second.h:* {{'Types::Decltype::invalid1' has different definitions in different modules; definition in module 'SecondModule' first difference is function body}} // expected-note@first.h:* {{but in 'FirstModule' found a different body}} auto function2 = invalid2; -// expected-error@second.h:* {{'Types::Decltype::invalid2' has different definitions in different modules; definition in module 'SecondModule' first difference is function body}} -// expected-note@first.h:* {{but in 'FirstModule' found a different body}} +// FIXME: auto function3 = valid; #endif } // namespace Decltype @@ -3700,8 +3696,7 @@ } #else auto function1 = invalid1; -// expected-error@second.h:* {{'Types::DeducedTemplateSpecialization::invalid1' has different definitions in different modules; definition in module 'SecondModule' first difference is function body}} -// expected-note@first.h:* {{but in 'FirstModule' found a different body}} +// FIXME: auto function2 = invalid2; // expected-error@second.h:* {{'Types::DeducedTemplateSpecialization::invalid2' has different definitions in different modules; definition in module 'SecondModule' first difference is function body}} // expected-note@first.h:* {{but in 'FirstModule' found a different body}} @@ -4899,6 +4894,8 @@ }; #else S1 s1; +// expected-error@second.h:* {{'TypedefStruct::S1' has different definitions in different modules;}} +// expected-note@first.h:* {{but in 'FirstModule' found field 't' with type 'T1 *'}} #endif #if defined(FIRST) @@ -4913,6 +4910,8 @@ }; #else S2 s2; +// expected-error@second.h:* {{'TypedefStruct::S2' has different definitions in different modules;}} +// expected-note@first.h:* {{but in 'FirstModule' found field 't' with type 'const T2 *'}} #endif #if defined(FIRST) @@ -4927,6 +4926,8 @@ }; #else S3 s3; +// expected-error@second.h:* {{'TypedefStruct::S3' has different definitions in different modules;}} +// expected-note@first.h:* {{but in 'FirstModule' found field 't' with type 'T3 *const'}} #endif #if defined(FIRST) @@ -4945,6 +4946,8 @@ }; #else S4 s4; +// expected-error@second.h:* {{'TypedefStruct::S4' has different definitions in different modules;}} +// expected-note@first.h:* {{but in 'FirstModule' found field 't' with type 'NS4::T4 *'}} #endif } // namespace TypedefStruct Index: clang/test/Modules/odr_hash.mm =================================================================== --- clang/test/Modules/odr_hash.mm +++ clang/test/Modules/odr_hash.mm @@ -112,8 +112,7 @@ // expected-error@second.h:* {{Types::Attributed::invalid1' has different definitions in different modules; definition in module 'SecondModule' first difference is function body}} // expected-note@first.h:* {{but in 'FirstModule' found a different body}} auto function2 = invalid2; -// expected-error@second.h:* {{'Types::Attributed::invalid2' has different definitions in different modules; definition in module 'SecondModule' first difference is function body}} -// expected-note@first.h:* {{but in 'FirstModule' found a different body}} +// FIXME: auto function3 = valid; #endif } // namespace Attributed @@ -266,12 +265,7 @@ } @end #else -// expected-error@first.h:* {{'Interface4::x' from module 'FirstModule' is not present in definition of 'Interface4' in module 'SecondModule'}} -// expected-note@second.h:* {{declaration of 'x' does not match}} -// expected-error@first.h:* {{'Interface5::y' from module 'FirstModule' is not present in definition of 'Interface5' in module 'SecondModule'}} -// expected-note@second.h:* {{declaration of 'y' does not match}} -// expected-error@first.h:* {{'Interface6::z' from module 'FirstModule' is not present in definition of 'Interface6' in module 'SecondModule'}} -// expected-note@second.h:* {{declaration of 'z' does not match}} +// FIXME: #endif namespace Types { @@ -291,14 +285,11 @@ }; #else Invalid1 i1; -// expected-error@first.h:* {{'Types::ObjCTypeParam::Invalid1::x' from module 'FirstModule' is not present in definition of 'Types::ObjCTypeParam::Invalid1' in module 'SecondModule'}} -// expected-note@second.h:* {{declaration of 'x' does not match}} + Invalid2 i2; -// expected-error@first.h:* {{'Types::ObjCTypeParam::Invalid2::y' from module 'FirstModule' is not present in definition of 'Types::ObjCTypeParam::Invalid2' in module 'SecondModule'}} -// expected-note@second.h:* {{declaration of 'y' does not match}} + Invalid3 i3; -// expected-error@first.h:* {{'Types::ObjCTypeParam::Invalid3::z' from module 'FirstModule' is not present in definition of 'Types::ObjCTypeParam::Invalid3' in module 'SecondModule'}} -// expected-note@second.h:* {{declaration of 'z' does not match}} +// FIXME: #endif } // namespace ObjCTypeParam Index: clang/test/Modules/pr63595.cppm =================================================================== --- /dev/null +++ clang/test/Modules/pr63595.cppm @@ -0,0 +1,56 @@ +// RUN: rm -rf %t +// RUN: mkdir %t +// RUN: split-file %s %t +// +// RUN: %clang_cc1 -std=c++20 -emit-module-interface -I%t %t/module1.cppm -o %t/module1.pcm +// RUN: %clang_cc1 -std=c++20 -emit-module-interface -I%t %t/module2.cppm -o %t/module2.pcm +// RUN: %clang_cc1 -std=c++20 -fprebuilt-module-path=%t %t/merge.cpp -verify -fsyntax-only + +//--- header.h +namespace NS { +template +class A { +}; + +template