[ODRHash] Extend hash to support all Type's.

llvm-svn: 341421
This commit is contained in:
Richard Trieu 2018-09-04 22:53:19 +00:00
parent 470db78115
commit 22ddc282b5
9 changed files with 1362 additions and 29 deletions

View File

@ -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);

View File

@ -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<const Decl *, 16> 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<NamedDecl>(D)) {
AddDeclarationName(ND->getDeclName());
const NamedDecl *ND = dyn_cast<NamedDecl>(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<ClassTemplateSpecializationDecl>(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

View File

@ -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);

View File

@ -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 \

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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<typename T> struct A {};
A() -> A<int>;
template<typename T> struct B {};
B() -> B<int>;
void invalid1() {
A a{};
}
void invalid2() {
A a{};
}
void valid() {
B b{};
}
#elif defined(SECOND)
template<typename T> struct A {};
A() -> A<float>;
template<typename T> struct B {};
B() -> B<int>;
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 <int A1, int A2>
void invalid1() {
using type = int __attribute__((address_space(A1)));
}
template <int A1>
void invalid2() {
using type = float __attribute__((address_space(A1)));
}
template <int A1, int A2>
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 <int A1, int A2>
void invalid1() {
using type = int __attribute__((address_space(A2)));
}
template <int A1>
void invalid2() {
using type = int __attribute__((address_space(A1)));
}
template <int A1, int A2>
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 <int A, int B>
class S {
static auto function1 = invalid1<A, B>;
// 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<B>;
// 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<A, B>;
};
#endif
} // namespace DependentAddressSpace
namespace DependentSizedExtVector {
#if defined(FIRST)
template<int Size>
void invalid1() {
typedef int __attribute__((ext_vector_type(Size))) type;
}
template<int Size>
void invalid2() {
typedef int __attribute__((ext_vector_type(Size + 0))) type;
}
template<int Size>
void valid() {
typedef int __attribute__((ext_vector_type(Size))) type;
}
#elif defined(SECOND)
template<int Size>
void invalid1() {
typedef float __attribute__((ext_vector_type(Size))) type;
}
template<int Size>
void invalid2() {
typedef int __attribute__((ext_vector_type(Size + 1))) type;
}
template<int Size>
void valid() {
typedef int __attribute__((ext_vector_type(Size))) type;
}
#else
template <int Num>
class S {
static auto Function1 = invalid1<Num>;
// 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<Num>;
// 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<Num>;
};
#endif
} // namespace DependentSizedExtVector
namespace InjectedClassName {
#if defined(FIRST)
struct Invalid {
template <int>
struct L2 {
template <int>
struct L3 {
L3 *x;
};
};
};
struct Valid {
template <int>
struct L2 {
template <int>
struct L3 {
L2 *x;
L3 *y;
};
};
};
#elif defined(SECOND)
struct Invalid {
template <int>
struct L2 {
template <int>
struct L3 {
L2 *x;
};
};
};
struct Valid {
template <int>
struct L2 {
template <int>
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 <class... A>
struct L2 {
template <class... B>
struct L3 {
void run(A...);
void run(B...);
};
};
};
struct Valid {
template <class... A>
struct L2 {
template <class... B>
struct L3 {
void run(A...);
void run(B...);
};
};
};
#elif defined(SECOND)
struct Invalid {
template <class... A>
struct L2 {
template <class... B>
struct L3 {
void run(B...);
void run(A...);
};
};
};
struct Valid {
template <class... A>
struct L2 {
template <class... B>
struct L3 {
void run(A...);
void run(B...);
};
};
};
#else
Invalid::L2<int>::L3<short, bool> 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<int>::L3<short, bool> 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 <class> struct wrapper {};
template <class, class, class> struct triple {};
struct Valid {
template <class T,
template <class _T, class _U, class = wrapper<_T>> class A = triple>
struct L2 {
A<T, T> x;
};
};
#elif defined(SECOND)
template <class> struct wrapper {};
template <class, class, class> struct triple {};
struct Valid {
template <class T,
template <class _T, class _U, class = wrapper<_T>> class A = triple>
struct L2 {
A<T, T> x;
};
};
#else
template <class T,
template <class _T, class _U, class = wrapper<_T>> class A = triple>
using V = Valid::L2<T, A>;
#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 <class T> struct wrapper {};
template <class T>
struct Invalid {
using typename wrapper<T>::T1;
using typename wrapper<T>::T2;
T1 x;
};
template <class T>
struct Valid {
using typename wrapper<T>::T1;
using typename wrapper<T>::T2;
T1 x;
T2 y;
};
#elif defined(SECOND)
template <class T> struct wrapper {};
template <class T>
struct Invalid {
using typename wrapper<T>::T1;
using typename wrapper<T>::T2;
T2 x;
};
template <class T>
struct Valid {
using typename wrapper<T>::T1;
using typename wrapper<T>::T2;
T1 x;
T2 y;
};
#else
template <class T> using I = Invalid<T>;
// expected-error@first.h:* {{'Types::UnresolvedUsing::Invalid::x' from module 'FirstModule' is not present in definition of 'Invalid<T>' in module 'SecondModule'}}
// expected-note@second.h:* {{declaration of 'x' does not match}}
template <class T> using V = Valid<T>;
#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

View File

@ -36,14 +36,27 @@
@protocol P1
@end
@protocol P2
@end
@interface I1
@end
@interface I2 : I1
@end
@interface Interface1 <T : I1 *> {
@public
T<P1> x;
}
@end
@interface Interface2 <T : I1 *>
@end
@interface Interface3 <T : I1 *>
@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<I1*>;
};
struct Invalid2 {
using T = Interface2<I1*>;
};
struct Invalid3 {
using T = Interface2<P1, P1>;
};
struct Invalid4 {
using T = Interface2<P1>;
};
struct Valid {
using T1 = Interface2<I1*>;
using T2 = Interface3<I1*>;
using T3 = Interface2<P1>;
using T4 = Interface3<P1, P2>;
using T5 = __kindof Interface2;
};
#elif defined(SECOND)
struct Invalid1 {
using T = Interface3<I1*>;
};
struct Invalid2 {
using T = Interface2<I2*>;
};
struct Invalid3 {
using T = Interface2<P1>;
};
struct Invalid4 {
using T = Interface2<P2>;
};
struct Valid {
using T1 = Interface2<I1*>;
using T2 = Interface3<I1*>;
using T3 = Interface2<P1>;
using T4 = Interface3<P1, P2>;
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<P1>'}}
// expected-note@first.h:* {{but in 'FirstModule' found type alias 'T' with different underlying type 'Interface2<P1,P1>'}}
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 <T : I1 *> {
@public
T<P1> x;
}
@end
@interface Interface5 <T : I1 *> {
@public
T<P1> x;
}
@end
@interface Interface6 <T1 : I1 *, T2 : I2 *> {
@public
T1 x;
}
@end
#elif defined(SECOND)
@interface Interface4 <T : I1 *> {
@public
T<P2> x;
}
@end
@interface Interface5 <T : I1 *> {
@public
T<P1, P2> x;
}
@end
@interface Interface6 <T1 : I1 *, T2 : I2 *> {
@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