forked from OSchip/llvm-project
[ODRHash] Extend hash to support all Type's.
llvm-svn: 341421
This commit is contained in:
parent
470db78115
commit
22ddc282b5
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue