From a9d72d6c527602c8495cf972bafec7a54f67df05 Mon Sep 17 00:00:00 2001 From: Richard Trieu Date: Tue, 4 Sep 2018 22:53:19 +0000 Subject: [PATCH] [ODRHash] Extend hash to support all Type's. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@341421 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/ODRHash.h | 2 +- lib/AST/ODRHash.cpp | 256 ++++++++++++-- lib/AST/StmtProfile.cpp | 2 +- test/Modules/odr_hash-blocks.cpp | 4 +- test/Modules/odr_hash-gnu.cpp | 130 +++++++ test/Modules/odr_hash-vector.cpp | 128 +++++++ test/Modules/odr_hash.cl | 80 +++++ test/Modules/odr_hash.cpp | 564 ++++++++++++++++++++++++++++++- test/Modules/odr_hash.mm | 225 ++++++++++++ 9 files changed, 1362 insertions(+), 29 deletions(-) create mode 100644 test/Modules/odr_hash-gnu.cpp create mode 100644 test/Modules/odr_hash-vector.cpp create mode 100644 test/Modules/odr_hash.cl diff --git a/include/clang/AST/ODRHash.h b/include/clang/AST/ODRHash.h index 0e52d3d854..0298887d1b 100644 --- a/include/clang/AST/ODRHash.h +++ b/include/clang/AST/ODRHash.h @@ -83,7 +83,7 @@ public: void AddIdentifierInfo(const IdentifierInfo *II); void AddNestedNameSpecifier(const NestedNameSpecifier *NNS); void AddTemplateName(TemplateName Name); - void AddDeclarationName(DeclarationName Name); + void AddDeclarationName(DeclarationName Name, bool TreatAsDecl = false); void AddTemplateArgument(TemplateArgument TA); void AddTemplateParameterList(const TemplateParameterList *TPL); diff --git a/lib/AST/ODRHash.cpp b/lib/AST/ODRHash.cpp index e710d37803..1624468079 100644 --- a/lib/AST/ODRHash.cpp +++ b/lib/AST/ODRHash.cpp @@ -32,7 +32,10 @@ void ODRHash::AddIdentifierInfo(const IdentifierInfo *II) { ID.AddString(II->getName()); } -void ODRHash::AddDeclarationName(DeclarationName Name) { +void ODRHash::AddDeclarationName(DeclarationName Name, bool TreatAsDecl) { + if (TreatAsDecl) + AddBoolean(true); + // Index all DeclarationName and use index numbers to refer to them. auto Result = DeclNameMap.insert(std::make_pair(Name, DeclNameMap.size())); ID.AddInteger(Result.first->second); @@ -88,6 +91,9 @@ void ODRHash::AddDeclarationName(DeclarationName Name) { } } } + + if (TreatAsDecl) + AddBoolean(false); } void ODRHash::AddNestedNameSpecifier(const NestedNameSpecifier *NNS) { @@ -405,6 +411,7 @@ public: void VisitFunctionTemplateDecl(const FunctionTemplateDecl *D) { AddDecl(D->getTemplatedDecl()); + ID.AddInteger(D->getTemplatedDecl()->getODRHash()); Inherited::VisitFunctionTemplateDecl(D); } @@ -552,11 +559,27 @@ void ODRHash::AddFunctionDecl(const FunctionDecl *Function, !Function->isDefaulted() && !Function->isDeleted() && !Function->isLateTemplateParsed(); AddBoolean(HasBody); - if (HasBody) { - auto *Body = Function->getBody(); - AddBoolean(Body); - if (Body) - AddStmt(Body); + if (!HasBody) { + return; + } + + auto *Body = Function->getBody(); + AddBoolean(Body); + if (Body) + AddStmt(Body); + + // Filter out sub-Decls which will not be processed in order to get an + // accurate count of Decl's. + llvm::SmallVector Decls; + for (Decl *SubDecl : Function->decls()) { + if (isWhitelistedDecl(SubDecl, Function)) { + Decls.push_back(SubDecl); + } + } + + ID.AddInteger(Decls.size()); + for (auto SubDecl : Decls) { + AddSubDecl(SubDecl); } } @@ -592,13 +615,24 @@ void ODRHash::AddDecl(const Decl *D) { assert(D && "Expecting non-null pointer."); D = D->getCanonicalDecl(); - if (const NamedDecl *ND = dyn_cast(D)) { - AddDeclarationName(ND->getDeclName()); + const NamedDecl *ND = dyn_cast(D); + AddBoolean(ND); + if (!ND) { + ID.AddInteger(D->getKind()); return; } - ID.AddInteger(D->getKind()); - // TODO: Handle non-NamedDecl here. + AddDeclarationName(ND->getDeclName()); + + const auto *Specialization = + dyn_cast(D); + AddBoolean(Specialization); + if (Specialization) { + const TemplateArgumentList &List = Specialization->getTemplateArgs(); + ID.AddInteger(List.size()); + for (const TemplateArgument &TA : List.asArray()) + AddTemplateArgument(TA); + } } namespace { @@ -700,11 +734,67 @@ public: VisitArrayType(T); } + void VisitAttributedType(const AttributedType *T) { + ID.AddInteger(T->getAttrKind()); + AddQualType(T->getModifiedType()); + AddQualType(T->getEquivalentType()); + + VisitType(T); + } + + void VisitBlockPointerType(const BlockPointerType *T) { + AddQualType(T->getPointeeType()); + VisitType(T); + } + void VisitBuiltinType(const BuiltinType *T) { ID.AddInteger(T->getKind()); VisitType(T); } + void VisitComplexType(const ComplexType *T) { + AddQualType(T->getElementType()); + VisitType(T); + } + + void VisitDecltypeType(const DecltypeType *T) { + AddStmt(T->getUnderlyingExpr()); + AddQualType(T->getUnderlyingType()); + VisitType(T); + } + + void VisitDependentDecltypeType(const DependentDecltypeType *T) { + VisitDecltypeType(T); + } + + void VisitDeducedType(const DeducedType *T) { + AddQualType(T->getDeducedType()); + VisitType(T); + } + + void VisitAutoType(const AutoType *T) { + ID.AddInteger((unsigned)T->getKeyword()); + VisitDeducedType(T); + } + + void VisitDeducedTemplateSpecializationType( + const DeducedTemplateSpecializationType *T) { + Hash.AddTemplateName(T->getTemplateName()); + VisitDeducedType(T); + } + + void VisitDependentAddressSpaceType(const DependentAddressSpaceType *T) { + AddQualType(T->getPointeeType()); + AddStmt(T->getAddrSpaceExpr()); + VisitType(T); + } + + void VisitDependentSizedExtVectorType(const DependentSizedExtVectorType *T) { + AddQualType(T->getElementType()); + AddStmt(T->getSizeExpr()); + VisitType(T); + } + void VisitFunctionType(const FunctionType *T) { AddQualType(T->getReturnType()); T->getExtInfo().Profile(ID); @@ -726,6 +816,74 @@ public: VisitFunctionType(T); } + void VisitInjectedClassNameType(const InjectedClassNameType *T) { + AddDecl(T->getDecl()); + VisitType(T); + } + + void VisitMemberPointerType(const MemberPointerType *T) { + AddQualType(T->getPointeeType()); + AddType(T->getClass()); + VisitType(T); + } + + void VisitObjCObjectPointerType(const ObjCObjectPointerType *T) { + AddQualType(T->getPointeeType()); + VisitType(T); + } + + void VisitObjCObjectType(const ObjCObjectType *T) { + AddDecl(T->getInterface()); + + auto TypeArgs = T->getTypeArgsAsWritten(); + ID.AddInteger(TypeArgs.size()); + for (auto Arg : TypeArgs) { + AddQualType(Arg); + } + + auto Protocols = T->getProtocols(); + ID.AddInteger(Protocols.size()); + for (auto Protocol : Protocols) { + AddDecl(Protocol); + } + + Hash.AddBoolean(T->isKindOfType()); + + VisitType(T); + } + + void VisitObjCInterfaceType(const ObjCInterfaceType *T) { + // This type is handled by the parent type ObjCObjectType. + VisitObjCObjectType(T); + } + + void VisitObjCTypeParamType(const ObjCTypeParamType *T) { + AddDecl(T->getDecl()); + auto Protocols = T->getProtocols(); + ID.AddInteger(Protocols.size()); + for (auto Protocol : Protocols) { + AddDecl(Protocol); + } + + VisitType(T); + } + + void VisitPackExpansionType(const PackExpansionType *T) { + AddQualType(T->getPattern()); + VisitType(T); + } + + void VisitParenType(const ParenType *T) { + AddQualType(T->getInnerType()); + VisitType(T); + } + + void VisitPipeType(const PipeType *T) { + AddQualType(T->getElementType()); + Hash.AddBoolean(T->isReadOnly()); + VisitType(T); + } + void VisitPointerType(const PointerType *T) { AddQualType(T->getPointeeType()); VisitType(T); @@ -744,6 +902,43 @@ public: VisitReferenceType(T); } + void + VisitSubstTemplateTypeParmPackType(const SubstTemplateTypeParmPackType *T) { + AddType(T->getReplacedParameter()); + Hash.AddTemplateArgument(T->getArgumentPack()); + VisitType(T); + } + + void VisitSubstTemplateTypeParmType(const SubstTemplateTypeParmType *T) { + AddType(T->getReplacedParameter()); + AddQualType(T->getReplacementType()); + VisitType(T); + } + + void VisitTagType(const TagType *T) { + AddDecl(T->getDecl()); + VisitType(T); + } + + void VisitRecordType(const RecordType *T) { VisitTagType(T); } + void VisitEnumType(const EnumType *T) { VisitTagType(T); } + + void VisitTemplateSpecializationType(const TemplateSpecializationType *T) { + ID.AddInteger(T->getNumArgs()); + for (const auto &TA : T->template_arguments()) { + Hash.AddTemplateArgument(TA); + } + Hash.AddTemplateName(T->getTemplateName()); + VisitType(T); + } + + void VisitTemplateTypeParmType(const TemplateTypeParmType *T) { + ID.AddInteger(T->getDepth()); + ID.AddInteger(T->getIndex()); + Hash.AddBoolean(T->isParameterPack()); + AddDecl(T->getDecl()); + } + void VisitTypedefType(const TypedefType *T) { AddDecl(T->getDecl()); QualType UnderlyingType = T->getDecl()->getUnderlyingType(); @@ -766,13 +961,18 @@ public: VisitType(T); } - void VisitTagType(const TagType *T) { - AddDecl(T->getDecl()); + void VisitTypeOfExprType(const TypeOfExprType *T) { + AddStmt(T->getUnderlyingExpr()); + Hash.AddBoolean(T->isSugared()); + if (T->isSugared()) + AddQualType(T->desugar()); + + VisitType(T); + } + void VisitTypeOfType(const TypeOfType *T) { + AddQualType(T->getUnderlyingType()); VisitType(T); } - - void VisitRecordType(const RecordType *T) { VisitTagType(T); } - void VisitEnumType(const EnumType *T) { VisitTagType(T); } void VisitTypeWithKeyword(const TypeWithKeyword *T) { ID.AddInteger(T->getKeyword()); @@ -802,20 +1002,26 @@ public: VisitTypeWithKeyword(T); } - void VisitTemplateSpecializationType(const TemplateSpecializationType *T) { - ID.AddInteger(T->getNumArgs()); - for (const auto &TA : T->template_arguments()) { - Hash.AddTemplateArgument(TA); - } - Hash.AddTemplateName(T->getTemplateName()); + void VisitUnaryTransformType(const UnaryTransformType *T) { + AddQualType(T->getUnderlyingType()); + AddQualType(T->getBaseType()); VisitType(T); } - void VisitTemplateTypeParmType(const TemplateTypeParmType *T) { - ID.AddInteger(T->getDepth()); - ID.AddInteger(T->getIndex()); - Hash.AddBoolean(T->isParameterPack()); + void VisitUnresolvedUsingType(const UnresolvedUsingType *T) { AddDecl(T->getDecl()); + VisitType(T); + } + + void VisitVectorType(const VectorType *T) { + AddQualType(T->getElementType()); + ID.AddInteger(T->getNumElements()); + ID.AddInteger(T->getVectorKind()); + VisitType(T); + } + + void VisitExtVectorType(const ExtVectorType * T) { + VisitVectorType(T); } }; } // namespace diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp index 15653c4fd8..133ecf7cdc 100644 --- a/lib/AST/StmtProfile.cpp +++ b/lib/AST/StmtProfile.cpp @@ -189,7 +189,7 @@ namespace { // store its nullness. Add a boolean here to match. ID.AddBoolean(true); } - Hash.AddDeclarationName(Name); + Hash.AddDeclarationName(Name, TreatAsDecl); } void VisitIdentifierInfo(IdentifierInfo *II) override { ID.AddBoolean(II); diff --git a/test/Modules/odr_hash-blocks.cpp b/test/Modules/odr_hash-blocks.cpp index 07dfa4ce2a..512c659f84 100644 --- a/test/Modules/odr_hash-blocks.cpp +++ b/test/Modules/odr_hash-blocks.cpp @@ -41,7 +41,7 @@ #define ACCESS private: #endif -// TODO: S1, S2, and S3 should generate errors. +// TODO: S1 and S2 should generate errors. namespace Blocks { #if defined(FIRST) struct S1 { @@ -77,6 +77,8 @@ struct S3 { }; #else S3 s3; +// expected-error@first.h:* {{'Blocks::S3::run' from module 'FirstModule' is not present in definition of 'Blocks::S3' in module 'SecondModule'}} +// expected-note@second.h:* {{declaration of 'run' does not match}} #endif #define DECLS \ diff --git a/test/Modules/odr_hash-gnu.cpp b/test/Modules/odr_hash-gnu.cpp new file mode 100644 index 0000000000..584c24d561 --- /dev/null +++ b/test/Modules/odr_hash-gnu.cpp @@ -0,0 +1,130 @@ +// Clear and create directories +// RUN: rm -rf %t +// RUN: mkdir %t +// RUN: mkdir %t/cache +// RUN: mkdir %t/Inputs + +// Build first header file +// RUN: echo "#define FIRST" >> %t/Inputs/first.h +// RUN: cat %s >> %t/Inputs/first.h + +// Build second header file +// RUN: echo "#define SECOND" >> %t/Inputs/second.h +// RUN: cat %s >> %t/Inputs/second.h + +// Test that each header can compile +// RUN: %clang_cc1 -fsyntax-only -x c++ -std=gnu++11 %t/Inputs/first.h +// RUN: %clang_cc1 -fsyntax-only -x c++ -std=gnu++11 %t/Inputs/second.h + +// Build module map file +// RUN: echo "module FirstModule {" >> %t/Inputs/module.map +// RUN: echo " header \"first.h\"" >> %t/Inputs/module.map +// RUN: echo "}" >> %t/Inputs/module.map +// RUN: echo "module SecondModule {" >> %t/Inputs/module.map +// RUN: echo " header \"second.h\"" >> %t/Inputs/module.map +// RUN: echo "}" >> %t/Inputs/module.map + +// Run test +// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/cache -x c++ -I%t/Inputs -verify %s -std=gnu++11 -fcolor-diagnostics + +#if !defined(FIRST) && !defined(SECOND) +#include "first.h" +#include "second.h" +#endif + +namespace Types { +namespace TypeOfExpr { +#if defined(FIRST) +struct Invalid1 { + typeof(1 + 2) x; +}; +double global; +struct Invalid2 { + typeof(global) x; +}; +struct Valid { + typeof(3) x; + typeof(x) y; + typeof(Valid*) self; +}; +#elif defined(SECOND) +struct Invalid1 { + typeof(3) x; +}; +int global; +struct Invalid2 { + typeof(global) x; +}; +struct Valid { + typeof(3) x; + typeof(x) y; + typeof(Valid*) self; +}; +#else +Invalid1 i1; +// 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}} +Valid v; +#endif +} // namespace TypeOfExpr + +namespace TypeOf { +#if defined(FIRST) +struct Invalid1 { + typeof(int) x; +}; +struct Invalid2 { + typeof(int) x; +}; +using T = int; +struct Invalid3 { + typeof(T) x; +}; +struct Valid { + typeof(int) x; + using T = typeof(double); + typeof(T) y; +}; +#elif defined(SECOND) +struct Invalid1 { + typeof(double) x; +}; +using I = int; +struct Invalid2 { + typeof(I) x; +}; +using T = short; +struct Invalid3 { + typeof(T) x; +}; +struct Valid { + typeof(int) x; + using T = typeof(double); + typeof(T) y; +}; +#else +Invalid1 i1; +// expected-error@second.h:* {{'Types::TypeOf::Invalid1::x' from module 'SecondModule' is not present in definition of 'Types::TypeOf::Invalid1' in module 'FirstModule'}} +// expected-note@first.h:* {{declaration of 'x' does not match}} +Invalid2 i2; +// 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(Types::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}} +Valid v; +#endif +} // namespace TypeOf +} // namespace Types + +// Keep macros contained to one file. +#ifdef FIRST +#undef FIRST +#endif + +#ifdef SECOND +#undef SECOND +#endif diff --git a/test/Modules/odr_hash-vector.cpp b/test/Modules/odr_hash-vector.cpp new file mode 100644 index 0000000000..ee59cb617c --- /dev/null +++ b/test/Modules/odr_hash-vector.cpp @@ -0,0 +1,128 @@ +// Clear and create directories +// RUN: rm -rf %t +// RUN: mkdir %t +// RUN: mkdir %t/cache +// RUN: mkdir %t/Inputs + +// Build first header file +// RUN: echo "#define FIRST" >> %t/Inputs/first.h +// RUN: cat %s >> %t/Inputs/first.h + +// Build second header file +// RUN: echo "#define SECOND" >> %t/Inputs/second.h +// RUN: cat %s >> %t/Inputs/second.h + +// Test that each header can compile +// RUN: %clang_cc1 -fsyntax-only -x c++ -std=c++11 %t/Inputs/first.h -fzvector +// RUN: %clang_cc1 -fsyntax-only -x c++ -std=c++11 %t/Inputs/second.h -fzvector + +// Build module map file +// RUN: echo "module FirstModule {" >> %t/Inputs/module.map +// RUN: echo " header \"first.h\"" >> %t/Inputs/module.map +// RUN: echo "}" >> %t/Inputs/module.map +// RUN: echo "module SecondModule {" >> %t/Inputs/module.map +// RUN: echo " header \"second.h\"" >> %t/Inputs/module.map +// RUN: echo "}" >> %t/Inputs/module.map + +// Run test +// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/cache -x c++ -I%t/Inputs -verify %s -std=c++11 -fzvector + +#if !defined(FIRST) && !defined(SECOND) +#include "first.h" +#include "second.h" +#endif + +namespace Types { +namespace Vector { +#if defined(FIRST) +struct Invalid1 { + __attribute((vector_size(8))) int x; +}; +struct Invalid2 { + __attribute((vector_size(8))) int x; +}; +struct Invalid3 { + __attribute((vector_size(16))) int x; +}; +struct Valid { + __attribute((vector_size(8))) int x1; + __attribute((vector_size(16))) int x2; + __attribute((vector_size(8))) unsigned x3; + __attribute((vector_size(16))) long x4; + vector unsigned x5; + vector int x6; +}; +#elif defined(SECOND) +struct Invalid1 { + __attribute((vector_size(16))) int x; +}; +struct Invalid2 { + __attribute((vector_size(8))) unsigned x; +}; +struct Invalid3 { + vector unsigned x; +}; +struct Valid { + __attribute((vector_size(8))) int x1; + __attribute((vector_size(16))) int x2; + __attribute((vector_size(8))) unsigned x3; + __attribute((vector_size(16))) long x4; + vector unsigned x5; + vector int x6; +}; +#else +Invalid1 i1; +// expected-error@second.h:* {{'Types::Vector::Invalid1::x' from module 'SecondModule' is not present in definition of 'Types::Vector::Invalid1' in module 'FirstModule'}} +// expected-note@first.h:* {{declaration of 'x' does not match}} +Invalid2 i2; +// expected-error@second.h:* {{'Types::Vector::Invalid2::x' from module 'SecondModule' is not present in definition of 'Types::Vector::Invalid2' in module 'FirstModule'}} +// expected-note@first.h:* {{declaration of 'x' does not match}} +Invalid3 i3; +// expected-error@second.h:* {{'Types::Vector::Invalid3::x' from module 'SecondModule' is not present in definition of 'Types::Vector::Invalid3' in module 'FirstModule'}} +// expected-note@first.h:* {{declaration of 'x' does not match}} + +Valid v; +#endif +} // namespace Vector + + + +namespace ExtVector { +} // namespace ExtVector +#if defined(FIRST) +struct Invalid { + using f = __attribute__((ext_vector_type(4))) float; +}; +struct Valid { + using f = __attribute__((ext_vector_type(8))) float; +}; +#elif defined(SECOND) +struct Invalid { + using f = __attribute__((ext_vector_type(8))) float; +}; +struct Valid { + using f = __attribute__((ext_vector_type(8))) float; +}; +#else +Invalid i; +// expected-error@first.h:* {{'Types::Invalid::f' from module 'FirstModule' is not present in definition of 'Types::Invalid' in module 'SecondModule'}} +// expected-note@second.h:* {{declaration of 'f' does not match}} + +Valid v; +#endif + +} // namespace Types + + +// Keep macros contained to one file. +#ifdef FIRST +#undef FIRST +#endif + +#ifdef SECOND +#undef SECOND +#endif + +#ifdef ACCESS +#undef ACCESS +#endif diff --git a/test/Modules/odr_hash.cl b/test/Modules/odr_hash.cl new file mode 100644 index 0000000000..d4af1cea6e --- /dev/null +++ b/test/Modules/odr_hash.cl @@ -0,0 +1,80 @@ +// Clear and create directories +// RUN: rm -rf %t +// RUN: mkdir %t +// RUN: mkdir %t/cache +// RUN: mkdir %t/Inputs + +// Build first header file +// RUN: echo "#define FIRST" >> %t/Inputs/first.h +// RUN: cat %s >> %t/Inputs/first.h + +// Build second header file +// RUN: echo "#define SECOND" >> %t/Inputs/second.h +// RUN: cat %s >> %t/Inputs/second.h + +// Test that each header can compile +// RUN: %clang_cc1 -fsyntax-only -x c++ %t/Inputs/first.h -cl-std=CL2.0 +// RUN: %clang_cc1 -fsyntax-only -x c++ %t/Inputs/second.h -cl-std=CL2.0 + +// Build module map file +// RUN: echo "module FirstModule {" >> %t/Inputs/module.map +// RUN: echo " header \"first.h\"" >> %t/Inputs/module.map +// RUN: echo "}" >> %t/Inputs/module.map +// RUN: echo "module SecondModule {" >> %t/Inputs/module.map +// RUN: echo " header \"second.h\"" >> %t/Inputs/module.map +// RUN: echo "}" >> %t/Inputs/module.map + +// Run test +// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/cache -x c++ -I%t/Inputs -verify %s -cl-std=CL2.0 + +#if !defined(FIRST) && !defined(SECOND) +#include "first.h" +#include "second.h" +#endif + + +#if defined(FIRST) +void invalid1() { + typedef read_only pipe int x; +} +void invalid2() { + typedef read_only pipe int x; +} +void valid() { + typedef read_only pipe int x; + typedef write_only pipe int y; + typedef read_write pipe int z; +} +#elif defined(SECOND) +void invalid1() { + typedef write_only pipe int x; +} +void invalid2() { + typedef read_only pipe float x; +} +void valid() { + typedef read_only pipe int x; + typedef write_only pipe int y; + typedef read_write pipe int z; +} +#else +void run() { + invalid1(); +// expected-error@second.h:* {{'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}} + invalid2(); +// expected-error@second.h:* {{'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}} + valid(); +} +#endif + + +// Keep macros contained to one file. +#ifdef FIRST +#undef FIRST +#endif + +#ifdef SECOND +#undef SECOND +#endif diff --git a/test/Modules/odr_hash.cpp b/test/Modules/odr_hash.cpp index 117029405e..3cfda89d16 100644 --- a/test/Modules/odr_hash.cpp +++ b/test/Modules/odr_hash.cpp @@ -25,7 +25,7 @@ // RUN: echo "}" >> %t/Inputs/module.map // Run test -// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/cache -x c++ -I%t/Inputs -verify %s -std=c++1z +// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/cache -x c++ -I%t/Inputs -verify %s -std=c++1z -fcolor-diagnostics #if !defined(FIRST) && !defined(SECOND) #include "first.h" @@ -3299,6 +3299,568 @@ Valid V; #endif } // namespace Enums +namespace Types { +namespace Complex { +#if defined(FIRST) +void invalid() { + _Complex float x; +} +void valid() { + _Complex float x; +} +#elif defined(SECOND) +void invalid() { + _Complex double x; +} +void valid() { + _Complex float x; +} +#else +auto function1 = invalid; +// expected-error@second.h:* {{'Types::Complex::invalid' 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 = valid; +#endif +} // namespace Complex + +namespace Decltype { +#if defined(FIRST) +void invalid1() { + decltype(1 + 1) x; +} +int global; +void invalid2() { + decltype(global) x; +} +void valid() { + decltype(1.5) x; + decltype(x) y; +} +#elif defined(SECOND) +void invalid1() { + decltype(2) x; +} +float global; +void invalid2() { + decltype(global) x; +} +void valid() { + decltype(1.5) x; + decltype(x) y; +} +#else +auto function1 = invalid1; +// 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}} +auto function3 = valid; +#endif +} // namespace Decltype + +namespace Auto { +#if defined(FIRST) +void invalid1() { + decltype(auto) x = 1; +} +void invalid2() { + auto x = 1; +} +void invalid3() { + __auto_type x = 1; +} +void valid() { + decltype(auto) x = 1; + auto y = 1; + __auto_type z = 1; +} +#elif defined(SECOND) +void invalid1() { + auto x = 1; +} +void invalid2() { + __auto_type x = 1; +} +void invalid3() { + decltype(auto) x = 1; +} +void valid() { + decltype(auto) x = 1; + auto y = 1; + __auto_type z = 1; +} +#else +auto function1 = invalid1; +// expected-error@second.h:* {{'Types::Auto::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 = invalid3; +// expected-error@second.h:* {{'Types::Auto::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}} +auto function3 = invalid2; +// expected-error@second.h:* {{'Types::Auto::invalid3' 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 function4 = valid; +#endif +} // namespace Auto + +namespace DeducedTemplateSpecialization { +#if defined(FIRST) +template struct A {}; +A() -> A; +template struct B {}; +B() -> B; + +void invalid1() { + A a{}; +} +void invalid2() { + A a{}; +} +void valid() { + B b{}; +} +#elif defined(SECOND) +template struct A {}; +A() -> A; +template struct B {}; +B() -> B; + +void invalid1() { + A a{}; +} +void invalid2() { + B a{}; +} +void valid() { + B b{}; +} +#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}} +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}} +auto function3 = valid; +#endif +} // namespace DeducedTemplateSpecialization + +namespace DependentAddressSpace { +#if defined(FIRST) +template +void invalid1() { + using type = int __attribute__((address_space(A1))); +} +template +void invalid2() { + using type = float __attribute__((address_space(A1))); +} +template +void valid() { + using type1 = float __attribute__((address_space(A1))); + using type2 = int __attribute__((address_space(A2))); + using type3 = int __attribute__((address_space(A1 + A2))); +} +#elif defined(SECOND) +template +void invalid1() { + using type = int __attribute__((address_space(A2))); +} +template +void invalid2() { + using type = int __attribute__((address_space(A1))); +} +template +void valid() { + using type1 = float __attribute__((address_space(A1))); + using type2 = int __attribute__((address_space(A2))); + using type3 = int __attribute__((address_space(A1 + A2))); +} +#else +template +class S { + static auto function1 = invalid1; + // expected-error@first.h:* {{'Types::DependentAddressSpace::invalid1' has different definitions in different modules; definition in module 'FirstModule' first difference is function body}} + // expected-note@second.h:* {{but in 'SecondModule' found a different body}} + static auto function2 = invalid2; + // expected-error@first.h:* {{'Types::DependentAddressSpace::invalid2' has different definitions in different modules; definition in module 'FirstModule' first difference is function body}} + // expected-note@second.h:* {{but in 'SecondModule' found a different body}} + static auto function3 = valid; +}; +#endif +} // namespace DependentAddressSpace + +namespace DependentSizedExtVector { +#if defined(FIRST) +template +void invalid1() { + typedef int __attribute__((ext_vector_type(Size))) type; +} +template +void invalid2() { + typedef int __attribute__((ext_vector_type(Size + 0))) type; +} +template +void valid() { + typedef int __attribute__((ext_vector_type(Size))) type; +} +#elif defined(SECOND) +template +void invalid1() { + typedef float __attribute__((ext_vector_type(Size))) type; +} +template +void invalid2() { + typedef int __attribute__((ext_vector_type(Size + 1))) type; +} +template +void valid() { + typedef int __attribute__((ext_vector_type(Size))) type; +} +#else +template +class S { + static auto Function1 = invalid1; + // expected-error@first.h:* {{'Types::DependentSizedExtVector::invalid1' has different definitions in different modules; definition in module 'FirstModule' first difference is function body}} + // expected-note@second.h:* {{but in 'SecondModule' found a different body}} + static auto Function2 = invalid2; + // expected-error@first.h:* {{'Types::DependentSizedExtVector::invalid2' has different definitions in different modules; definition in module 'FirstModule' first difference is function body}} + // expected-note@second.h:* {{but in 'SecondModule' found a different body}} + static auto Function3 = valid; +}; +#endif +} // namespace DependentSizedExtVector + +namespace InjectedClassName { +#if defined(FIRST) +struct Invalid { + template + struct L2 { + template + struct L3 { + L3 *x; + }; + }; +}; +struct Valid { + template + struct L2 { + template + struct L3 { + L2 *x; + L3 *y; + }; + }; +}; +#elif defined(SECOND) +struct Invalid { + template + struct L2 { + template + struct L3 { + L2 *x; + }; + }; +}; +struct Valid { + template + struct L2 { + template + struct L3 { + L2 *x; + L3 *y; + }; + }; +}; +#else +Invalid::L2<1>::L3<1> invalid; +// expected-error@second.h:* {{'Types::InjectedClassName::Invalid::L2::L3::x' from module 'SecondModule' is not present in definition of 'L3<>' in module 'FirstModule'}} +// expected-note@first.h:* {{declaration of 'x' does not match}} +Valid::L2<1>::L3<1> valid; +#endif +} // namespace InjectedClassName + +namespace MemberPointer { +#if defined(FIRST) +struct A {}; +struct B {}; + +void Invalid1() { + int A::*x; +}; +void Invalid2() { + int A::*x; +} +void Invalid3() { + int (A::*x)(int); +} +void Valid() { + int A::*x; + float A::*y; + bool B::*z; + void (A::*fun1)(); + int (A::*fun2)(); + void (B::*fun3)(int); + void (B::*fun4)(bool*, int); +} +#elif defined(SECOND) +struct A {}; +struct B {}; + +void Invalid1() { + float A::*x; +}; +void Invalid2() { + int B::*x; +} +void Invalid3() { + int (A::*x)(int, int); +} +void Valid() { + int A::*x; + float A::*y; + bool B::*z; + void (A::*fun1)(); + int (A::*fun2)(); + void (B::*fun3)(int); + void (B::*fun4)(bool*, int); +} +#else +auto function1 = Invalid1; +// expected-error@second.h:* {{'Types::MemberPointer::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::MemberPointer::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}} +auto function3 = Invalid3; +// expected-error@second.h:* {{'Types::MemberPointer::Invalid3' 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 function4 = Valid; +#endif + +} // namespace MemberPointer + +namespace PackExpansion { +#if defined(FIRST) +struct Invalid { + template + struct L2 { + template + struct L3 { + void run(A...); + void run(B...); + }; + }; +}; +struct Valid { + template + struct L2 { + template + struct L3 { + void run(A...); + void run(B...); + }; + }; +}; +#elif defined(SECOND) +struct Invalid { + template + struct L2 { + template + struct L3 { + void run(B...); + void run(A...); + }; + }; +}; +struct Valid { + template + struct L2 { + template + struct L3 { + void run(A...); + void run(B...); + }; + }; +}; +#else +Invalid::L2::L3 invalid; +// expected-error@first.h:* {{'Types::PackExpansion::Invalid::L2::L3' has different definitions in different modules; first difference is definition in module 'FirstModule' found method 'run' with 1st parameter of type 'A...'}} +// expected-note@second.h:* {{but in 'SecondModule' found method 'run' with 1st parameter of type 'B...'}} +Valid::L2::L3 valid; +#endif + +} // namespace PackExpansion + +namespace Paren { +#if defined(FIRST) +void invalid() { + int (*x); +} +void valid() { + int (*x); +} +#elif defined(SECOND) +void invalid() { + float (*x); +} +void valid() { + int (*x); +} +#else +auto function1 = invalid; +// expected-error@second.h:* {{'Types::Paren::invalid' 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 = valid; +#endif +} // namespace Paren + +namespace SubstTemplateTypeParm { +#if defined(FIRST) +template struct wrapper {}; +template struct triple {}; +struct Valid { + template > class A = triple> + struct L2 { + A x; + }; +}; +#elif defined(SECOND) +template struct wrapper {}; +template struct triple {}; +struct Valid { + template > class A = triple> + struct L2 { + A x; + }; +}; +#else +template > class A = triple> +using V = Valid::L2; +#endif +} // namespace SubstTemplateTypeParm + +namespace SubstTemplateTypeParmPack { +} // namespace SubstTemplateTypeParmPack + +namespace UnaryTransform { +#if defined(FIRST) +enum class E1a : unsigned {}; +struct Invalid1 { + __underlying_type(E1a) x; +}; +enum E2a : unsigned {}; +struct Invalid2 { + __underlying_type(E2a) x; +}; +enum E3a {}; +struct Invalid3 { + __underlying_type(E3a) x; +}; +enum E4a {}; +struct Invalid4 { + __underlying_type(E4a) x; +}; +enum E1 {}; +struct Valid1 { + __underlying_type(E1) x; +}; +enum E2 : unsigned {}; +struct Valid2 { + __underlying_type(E2) x; +}; +enum class E3 {}; +struct Valid3 { + __underlying_type(E3) x; +}; +#elif defined(SECOND) +enum class E1b : signed {}; +struct Invalid1 { + __underlying_type(E1b) x; +}; +enum class E2b : unsigned {}; +struct Invalid2 { + __underlying_type(E2b) x; +}; +enum E3b : int {}; +struct Invalid3 { + __underlying_type(E3b) x; +}; +enum E4b {}; +struct Invalid4 { + __underlying_type(E4b) x; +}; +#else +Invalid1 i1; +// expected-error@first.h:* {{'Types::UnaryTransform::Invalid1::x' from module 'FirstModule' is not present in definition of 'Types::UnaryTransform::Invalid1' in module 'SecondModule'}} +// expected-note@second.h:* {{declaration of 'x' does not match}} +Invalid2 i2; +// expected-error@second.h:* {{'Types::UnaryTransform::Invalid2' has different definitions in different modules; first difference is definition in module 'SecondModule' found field 'x' with type '__underlying_type(Types::UnaryTransform::E2b)' (aka 'unsigned int')}} +// expected-note@first.h:* {{but in 'FirstModule' found field 'x' with type '__underlying_type(Types::UnaryTransform::E2a)' (aka 'unsigned int')}} +Invalid3 i3; +// expected-error@first.h:* {{'Types::UnaryTransform::Invalid3::x' from module 'FirstModule' is not present in definition of 'Types::UnaryTransform::Invalid3' in module 'SecondModule'}} +// expected-note@second.h:* {{declaration of 'x' does not match}} +Invalid4 i4; +// expected-error@second.h:* {{'Types::UnaryTransform::Invalid4' has different definitions in different modules; first difference is definition in module 'SecondModule' found field 'x' with type '__underlying_type(Types::UnaryTransform::E4b)' (aka 'unsigned int')}} +// expected-note@first.h:* {{but in 'FirstModule' found field 'x' with type '__underlying_type(Types::UnaryTransform::E4a)' (aka 'unsigned int')}} +Valid1 v1; +Valid2 v2; +Valid3 v3; +#endif +} // namespace UnaryTransform + +namespace UnresolvedUsing { +#if defined(FIRST) +template struct wrapper {}; +template +struct Invalid { + using typename wrapper::T1; + using typename wrapper::T2; + T1 x; +}; +template +struct Valid { + using typename wrapper::T1; + using typename wrapper::T2; + T1 x; + T2 y; +}; +#elif defined(SECOND) +template struct wrapper {}; +template +struct Invalid { + using typename wrapper::T1; + using typename wrapper::T2; + T2 x; +}; +template +struct Valid { + using typename wrapper::T1; + using typename wrapper::T2; + T1 x; + T2 y; +}; +#else +template using I = Invalid; +// expected-error@first.h:* {{'Types::UnresolvedUsing::Invalid::x' from module 'FirstModule' is not present in definition of 'Invalid' in module 'SecondModule'}} +// expected-note@second.h:* {{declaration of 'x' does not match}} + +template using V = Valid; +#endif + +} // namespace UnresolvedUsing + +// Vector +// void invalid1() { +// __attribute((vector_size(8))) int *x1; +//} + +} // namespace Types + // Collection of interesting cases below. // Naive parsing of AST can lead to cycles in processing. Ensure diff --git a/test/Modules/odr_hash.mm b/test/Modules/odr_hash.mm index 724ed95dc1..f04fb7eb5e 100644 --- a/test/Modules/odr_hash.mm +++ b/test/Modules/odr_hash.mm @@ -36,14 +36,27 @@ @protocol P1 @end +@protocol P2 +@end + @interface I1 @end +@interface I2 : I1 +@end + @interface Interface1 { @public T x; } @end + +@interface Interface2 +@end + +@interface Interface3 +@end + #endif #if defined(FIRST) @@ -64,6 +77,218 @@ S s; // expected-note@first.h:* {{declaration of 'y' does not match}} #endif +namespace Types { +namespace Attributed { +#if defined(FIRST) +void invalid1() { + static double __attribute((objc_gc(strong))) *x; +} +void invalid2() { + static int __attribute((objc_gc(strong))) *x; +} +void valid() { + static int __attribute((objc_gc(strong))) *x; +} +#elif defined(SECOND) +void invalid1() { + static int __attribute((objc_gc(strong))) *x; +} +void invalid2() { + static int __attribute((objc_gc(weak))) *x; +} +void valid() { + static int __attribute((objc_gc(strong))) *x; +} +#else +auto function1 = invalid1; +// 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}} +auto function3 = valid; +#endif +} // namespace Attributed + +namespace BlockPointer { +#if defined(FIRST) +void invalid1() { + void (^x)(int); +} +void invalid2() { + void (^x)(int); +} +void invalid3() { + void (^x)(int); +} +void invalid4() { + void (^x)(int); +} +void valid() { + void (^x1)(int); + int (^x2)(int); + void (^x3)(int, int); + void (^x4)(short); +} +#elif defined(SECOND) +void invalid1() { + void (^x)(); +} +void invalid2() { + void (^x)(int, int); +} +void invalid3() { + int (^x)(int); +} +void invalid4() { + void (^x)(float); +} +void valid() { + void (^x1)(int); + int (^x2)(int); + void (^x3)(int, int); + void (^x4)(short); +} +#else +auto function1 = invalid1; +// expected-error@second.h:* {{'Types::BlockPointer::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::BlockPointer::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}} +auto function3 = invalid3; +// expected-error@second.h:* {{'Types::BlockPointer::invalid3' 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 function4 = invalid4; +// expected-error@second.h:* {{'Types::BlockPointer::invalid4' 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 function5 = valid; +#endif +} // namespace BlockPointer + +namespace ObjCObject { +#if defined(FIRST) +struct Invalid1 { + using T = Interface2; +}; +struct Invalid2 { + using T = Interface2; +}; +struct Invalid3 { + using T = Interface2; +}; +struct Invalid4 { + using T = Interface2; +}; +struct Valid { + using T1 = Interface2; + using T2 = Interface3; + using T3 = Interface2; + using T4 = Interface3; + using T5 = __kindof Interface2; +}; +#elif defined(SECOND) +struct Invalid1 { + using T = Interface3; +}; +struct Invalid2 { + using T = Interface2; +}; +struct Invalid3 { + using T = Interface2; +}; +struct Invalid4 { + using T = Interface2; +}; +struct Valid { + using T1 = Interface2; + using T2 = Interface3; + using T3 = Interface2; + using T4 = Interface3; + using T5 = __kindof Interface2; +}; +#else +Invalid1 i1; +// expected-error@first.h:* {{'Types::ObjCObject::Invalid1::T' from module 'FirstModule' is not present in definition of 'Types::ObjCObject::Invalid1' in module 'SecondModule'}} +// expected-note@second.h:* {{declaration of 'T' does not match}} +Invalid2 i2; +// expected-error@first.h:* {{'Types::ObjCObject::Invalid2::T' from module 'FirstModule' is not present in definition of 'Types::ObjCObject::Invalid2' in module 'SecondModule'}} +// expected-note@second.h:* {{declaration of 'T' does not match}} +Invalid3 i3; +// expected-error@second.h:* {{'Types::ObjCObject::Invalid3' has different definitions in different modules; first difference is definition in module 'SecondModule' found type alias 'T' with underlying type 'Interface2'}} +// expected-note@first.h:* {{but in 'FirstModule' found type alias 'T' with different underlying type 'Interface2'}} +Invalid4 i4; +// expected-error@first.h:* {{'Types::ObjCObject::Invalid4::T' from module 'FirstModule' is not present in definition of 'Types::ObjCObject::Invalid4' in module 'SecondModule'}} +// expected-note@second.h:* {{declaration of 'T' does not match}} +Valid v; +#endif +} // namespace VisitObjCObject +} // namespace Types + +#if defined(FIRST) +@interface Interface4 { +@public + T x; +} +@end +@interface Interface5 { +@public + T x; +} +@end +@interface Interface6 { +@public + T1 x; +} +@end +#elif defined(SECOND) +@interface Interface4 { +@public + T x; +} +@end +@interface Interface5 { +@public + T x; +} +@end +@interface Interface6 { +@public + T2 x; +} +@end +#endif + +namespace Types { +namespace ObjCTypeParam { +#if defined(FIRST) || defined(SECOND) +struct Invalid1 { + Interface4 *I; + decltype(I->x) x; +}; +struct Invalid2 { + Interface5 *I; + decltype(I->x) x; +}; +struct Invalid3 { + Interface6 *I; + decltype(I->x) x; +}; +#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::x' from module 'FirstModule' is not present in definition of 'Types::ObjCTypeParam::Invalid2' in module 'SecondModule'}} +// expected-note@second.h:* {{declaration of 'x' does not match}} +Invalid3 i3; +// expected-error@first.h:* {{'Types::ObjCTypeParam::Invalid3::x' from module 'FirstModule' is not present in definition of 'Types::ObjCTypeParam::Invalid3' in module 'SecondModule'}} +// expected-note@second.h:* {{declaration of 'x' does not match}} +#endif + +} // namespace ObjCTypeParam +} // namespace Types + // Keep macros contained to one file. #ifdef FIRST #undef FIRST -- 2.40.0