diff options
-rw-r--r-- | include/clang/AST/Decl.h | 6 | ||||
-rw-r--r-- | include/clang/AST/DeclBase.h | 5 | ||||
-rw-r--r-- | include/clang/AST/DeclObjC.h | 72 | ||||
-rw-r--r-- | include/clang/AST/ExternalASTSource.h | 3 | ||||
-rw-r--r-- | lib/AST/Decl.cpp | 25 | ||||
-rw-r--r-- | lib/AST/DeclBase.cpp | 4 | ||||
-rw-r--r-- | lib/AST/DeclCXX.cpp | 9 | ||||
-rw-r--r-- | lib/AST/DeclObjC.cpp | 26 | ||||
-rw-r--r-- | lib/AST/DeclTemplate.cpp | 13 | ||||
-rw-r--r-- | test/Modules/Inputs/def.h | 9 | ||||
-rw-r--r-- | test/Modules/decldef.m | 28 | ||||
-rw-r--r-- | test/Modules/decldef.mm | 19 |
12 files changed, 181 insertions, 38 deletions
diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index cfcbeb2c00..b6a650fea3 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -2496,6 +2496,12 @@ protected: /// possible in C++11 or Microsoft extensions mode. bool IsFixed : 1; + /// \brief Indicates whether it is possible for declarations of this kind + /// to have an out-of-date definition. + /// + /// This option is only enabled when modules are enabled. + bool MayHaveOutOfDateDef : 1; + private: SourceLocation RBraceLoc; diff --git a/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h index 8d9d4ded54..edacb4d31b 100644 --- a/include/clang/AST/DeclBase.h +++ b/include/clang/AST/DeclBase.h @@ -337,7 +337,10 @@ protected: static void *AllocateDeserializedDecl(const ASTContext &Context, unsigned ID, unsigned Size); - + + /// \brief Update a potentially out-of-date declaration. + void updateOutOfDate(IdentifierInfo &II) const; + public: /// \brief Source range that this declaration covers. diff --git a/include/clang/AST/DeclObjC.h b/include/clang/AST/DeclObjC.h index 54649575db..a09bcb50d7 100644 --- a/include/clang/AST/DeclObjC.h +++ b/include/clang/AST/DeclObjC.h @@ -668,11 +668,14 @@ class ObjCInterfaceDecl : public ObjCContainerDecl /// \brief Contains a pointer to the data associated with this class, /// which will be NULL if this class has not yet been defined. - DefinitionData *Data; + /// + /// The bit indicates when we don't need to check for out-of-date + /// declarations. It will be set unless modules are enabled. + llvm::PointerIntPair<DefinitionData *, 1, bool> Data; DefinitionData &data() const { - assert(Data != 0 && "Declaration has no definition!"); - return *Data; + assert(Data.getPointer() && "Declaration has no definition!"); + return *Data.getPointer(); } /// \brief Allocate the definition data for this class. @@ -680,7 +683,7 @@ class ObjCInterfaceDecl : public ObjCContainerDecl typedef Redeclarable<ObjCInterfaceDecl> redeclarable_base; virtual ObjCInterfaceDecl *getNextRedeclaration() { - return RedeclLink.getNext(); + return RedeclLink.getNext(); } virtual ObjCInterfaceDecl *getPreviousDeclImpl() { return getPreviousDecl(); @@ -853,24 +856,38 @@ public: /// \brief Determine whether this particular declaration of this class is /// actually also a definition. bool isThisDeclarationADefinition() const { - return Data && Data->Definition == this; + return getDefinition() == this; } /// \brief Determine whether this class has been defined. - bool hasDefinition() const { return Data; } + bool hasDefinition() const { + // If the name of this class is out-of-date, bring it up-to-date, which + // might bring in a definition. + // Note: a null value indicates that we don't have a definition and that + // modules are enabled. + if (!Data.getOpaqueValue()) { + if (IdentifierInfo *II = getIdentifier()) { + if (II->isOutOfDate()) { + updateOutOfDate(*II); + } + } + } + + return Data.getPointer(); + } /// \brief Retrieve the definition of this class, or NULL if this class /// has been forward-declared (with \@class) but not yet defined (with /// \@interface). ObjCInterfaceDecl *getDefinition() { - return hasDefinition()? Data->Definition : 0; + return hasDefinition()? Data.getPointer()->Definition : 0; } /// \brief Retrieve the definition of this class, or NULL if this class /// has been forward-declared (with \@class) but not yet defined (with /// \@interface). const ObjCInterfaceDecl *getDefinition() const { - return hasDefinition()? Data->Definition : 0; + return hasDefinition()? Data.getPointer()->Definition : 0; } /// \brief Starts the definition of this Objective-C class, taking it from @@ -1142,7 +1159,7 @@ public: /// ObjCInterfaceDecl node. This is for legacy objective-c \@implementation /// declaration without an \@interface declaration. bool isImplicitInterfaceDecl() const { - return hasDefinition() ? Data->Definition->isImplicit() : isImplicit(); + return hasDefinition() ? data().Definition->isImplicit() : isImplicit(); } /// ClassImplementsProtocol - Checks that 'lProto' protocol @@ -1319,12 +1336,17 @@ class ObjCProtocolDecl : public ObjCContainerDecl, /// \brief Referenced protocols ObjCProtocolList ReferencedProtocols; }; - - DefinitionData *Data; + + /// \brief Contains a pointer to the data associated with this class, + /// which will be NULL if this class has not yet been defined. + /// + /// The bit indicates when we don't need to check for out-of-date + /// declarations. It will be set unless modules are enabled. + llvm::PointerIntPair<DefinitionData *, 1, bool> Data; DefinitionData &data() const { - assert(Data && "Objective-C protocol has no definition!"); - return *Data; + assert(Data.getPointer() && "Objective-C protocol has no definition!"); + return *Data.getPointer(); } ObjCProtocolDecl(DeclContext *DC, IdentifierInfo *Id, @@ -1343,7 +1365,7 @@ class ObjCProtocolDecl : public ObjCContainerDecl, virtual ObjCProtocolDecl *getMostRecentDeclImpl() { return getMostRecentDecl(); } - + public: static ObjCProtocolDecl *Create(ASTContext &C, DeclContext *DC, IdentifierInfo *Id, @@ -1394,7 +1416,7 @@ public: /// implements. void setProtocolList(ObjCProtocolDecl *const*List, unsigned Num, const SourceLocation *Locs, ASTContext &C) { - assert(Data && "Protocol is not defined"); + assert(hasDefinition() && "Protocol is not defined"); data().ReferencedProtocols.set(List, Num, Locs, C); } @@ -1411,16 +1433,30 @@ public: } /// \brief Determine whether this protocol has a definition. - bool hasDefinition() const { return Data != 0; } + bool hasDefinition() const { + // If the name of this protocol is out-of-date, bring it up-to-date, which + // might bring in a definition. + // Note: a null value indicates that we don't have a definition and that + // modules are enabled. + if (!Data.getOpaqueValue()) { + if (IdentifierInfo *II = getIdentifier()) { + if (II->isOutOfDate()) { + updateOutOfDate(*II); + } + } + } + + return Data.getPointer(); + } /// \brief Retrieve the definition of this protocol, if any. ObjCProtocolDecl *getDefinition() { - return Data? Data->Definition : 0; + return hasDefinition()? Data.getPointer()->Definition : 0; } /// \brief Retrieve the definition of this protocol, if any. const ObjCProtocolDecl *getDefinition() const { - return Data? Data->Definition : 0; + return hasDefinition()? Data.getPointer()->Definition : 0; } /// \brief Determine whether this particular declaration is also the diff --git a/include/clang/AST/ExternalASTSource.h b/include/clang/AST/ExternalASTSource.h index 5f95c775dc..81fcf242b6 100644 --- a/include/clang/AST/ExternalASTSource.h +++ b/include/clang/AST/ExternalASTSource.h @@ -118,6 +118,9 @@ public: /// The default implementation of this method is a no-op. virtual CXXBaseSpecifier *GetExternalCXXBaseSpecifiers(uint64_t Offset); + /// \brief Update an out-of-date identifier. + virtual void updateOutOfDateIdentifier(IdentifierInfo &II) { } + /// \brief Find all declarations with the given name in the given context, /// and add them to the context by calling SetExternalVisibleDeclsForName /// or SetNoExternalVisibleDeclsForName. diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index cdf921de4a..85ed3ba7db 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -2612,6 +2612,16 @@ void TagDecl::completeDefinition() { TagDecl *TagDecl::getDefinition() const { if (isCompleteDefinition()) return const_cast<TagDecl *>(this); + + // If it's possible for us to have an out-of-date definition, check now. + if (MayHaveOutOfDateDef) { + if (IdentifierInfo *II = getIdentifier()) { + if (II->isOutOfDate()) { + updateOutOfDate(*II); + } + } + } + if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(this)) return CXXRD->getDefinition(); @@ -2668,14 +2678,17 @@ EnumDecl *EnumDecl::Create(ASTContext &C, DeclContext *DC, bool IsScopedUsingClassTag, bool IsFixed) { EnumDecl *Enum = new (C) EnumDecl(DC, StartLoc, IdLoc, Id, PrevDecl, IsScoped, IsScopedUsingClassTag, IsFixed); + Enum->MayHaveOutOfDateDef = C.getLangOpts().Modules; C.getTypeDeclType(Enum, PrevDecl); return Enum; } EnumDecl *EnumDecl::CreateDeserialized(ASTContext &C, unsigned ID) { void *Mem = AllocateDeserializedDecl(C, ID, sizeof(EnumDecl)); - return new (Mem) EnumDecl(0, SourceLocation(), SourceLocation(), 0, 0, - false, false, false); + EnumDecl *Enum = new (Mem) EnumDecl(0, SourceLocation(), SourceLocation(), + 0, 0, false, false, false); + Enum->MayHaveOutOfDateDef = C.getLangOpts().Modules; + return Enum; } void EnumDecl::completeDefinition(QualType NewType, @@ -2743,14 +2756,18 @@ RecordDecl *RecordDecl::Create(const ASTContext &C, TagKind TK, DeclContext *DC, IdentifierInfo *Id, RecordDecl* PrevDecl) { RecordDecl* R = new (C) RecordDecl(Record, TK, DC, StartLoc, IdLoc, Id, PrevDecl); + R->MayHaveOutOfDateDef = C.getLangOpts().Modules; + C.getTypeDeclType(R, PrevDecl); return R; } RecordDecl *RecordDecl::CreateDeserialized(const ASTContext &C, unsigned ID) { void *Mem = AllocateDeserializedDecl(C, ID, sizeof(RecordDecl)); - return new (Mem) RecordDecl(Record, TTK_Struct, 0, SourceLocation(), - SourceLocation(), 0, 0); + RecordDecl *R = new (Mem) RecordDecl(Record, TTK_Struct, 0, SourceLocation(), + SourceLocation(), 0, 0); + R->MayHaveOutOfDateDef = C.getLangOpts().Modules; + return R; } bool RecordDecl::isInjectedClassName() const { diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp index e1202c23a8..2073658549 100644 --- a/lib/AST/DeclBase.cpp +++ b/lib/AST/DeclBase.cpp @@ -40,6 +40,10 @@ using namespace clang; #define ABSTRACT_DECL(DECL) #include "clang/AST/DeclNodes.inc" +void Decl::updateOutOfDate(IdentifierInfo &II) const { + getASTContext().getExternalSource()->updateOutOfDateIdentifier(II); +} + void *Decl::AllocateDeserializedDecl(const ASTContext &Context, unsigned ID, unsigned Size) { diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index 90a2b4ab46..4dd3694bc4 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -87,6 +87,7 @@ CXXRecordDecl *CXXRecordDecl::Create(const ASTContext &C, TagKind TK, bool DelayTypeCreation) { CXXRecordDecl* R = new (C) CXXRecordDecl(CXXRecord, TK, DC, StartLoc, IdLoc, Id, PrevDecl); + R->MayHaveOutOfDateDef = C.getLangOpts().Modules; // FIXME: DelayTypeCreation seems like such a hack if (!DelayTypeCreation) @@ -101,6 +102,7 @@ CXXRecordDecl *CXXRecordDecl::CreateLambda(const ASTContext &C, DeclContext *DC, 0, 0); R->IsBeingDefined = true; R->DefinitionData = new (C) struct LambdaDefinitionData(R, Info, Dependent); + R->MayHaveOutOfDateDef = false; C.getTypeDeclType(R, /*PrevDecl=*/0); return R; } @@ -108,8 +110,11 @@ CXXRecordDecl *CXXRecordDecl::CreateLambda(const ASTContext &C, DeclContext *DC, CXXRecordDecl * CXXRecordDecl::CreateDeserialized(const ASTContext &C, unsigned ID) { void *Mem = AllocateDeserializedDecl(C, ID, sizeof(CXXRecordDecl)); - return new (Mem) CXXRecordDecl(CXXRecord, TTK_Struct, 0, SourceLocation(), - SourceLocation(), 0, 0); + CXXRecordDecl *R = new (Mem) CXXRecordDecl(CXXRecord, TTK_Struct, 0, + SourceLocation(), SourceLocation(), + 0, 0); + R->MayHaveOutOfDateDef = false; + return R; } void diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp index b99c45ccfb..ce765a7bf5 100644 --- a/lib/AST/DeclObjC.cpp +++ b/lib/AST/DeclObjC.cpp @@ -301,8 +301,8 @@ void ObjCInterfaceDecl::mergeClassExtensionProtocolList( void ObjCInterfaceDecl::allocateDefinitionData() { assert(!hasDefinition() && "ObjC class already has a definition"); - Data = new (getASTContext()) DefinitionData(); - Data->Definition = this; + Data.setPointer(new (getASTContext()) DefinitionData()); + Data.getPointer()->Definition = this; // Make the type point at the definition, now that we have one. if (TypeForDecl) @@ -1011,6 +1011,7 @@ ObjCInterfaceDecl *ObjCInterfaceDecl::Create(const ASTContext &C, bool isInternal){ ObjCInterfaceDecl *Result = new (C) ObjCInterfaceDecl(DC, atLoc, Id, ClassLoc, PrevDecl, isInternal); + Result->Data.setInt(!C.getLangOpts().Modules); C.getObjCInterfaceType(Result, PrevDecl); return Result; } @@ -1018,8 +1019,11 @@ ObjCInterfaceDecl *ObjCInterfaceDecl::Create(const ASTContext &C, ObjCInterfaceDecl *ObjCInterfaceDecl::CreateDeserialized(ASTContext &C, unsigned ID) { void *Mem = AllocateDeserializedDecl(C, ID, sizeof(ObjCInterfaceDecl)); - return new (Mem) ObjCInterfaceDecl(0, SourceLocation(), 0, SourceLocation(), - 0, false); + ObjCInterfaceDecl *Result = new (Mem) ObjCInterfaceDecl(0, SourceLocation(), + 0, SourceLocation(), + 0, false); + Result->Data.setInt(!C.getLangOpts().Modules); + return Result; } ObjCInterfaceDecl:: @@ -1334,15 +1338,17 @@ ObjCProtocolDecl *ObjCProtocolDecl::Create(ASTContext &C, DeclContext *DC, ObjCProtocolDecl *PrevDecl) { ObjCProtocolDecl *Result = new (C) ObjCProtocolDecl(DC, Id, nameLoc, atStartLoc, PrevDecl); - + Result->Data.setInt(!C.getLangOpts().Modules); return Result; } ObjCProtocolDecl *ObjCProtocolDecl::CreateDeserialized(ASTContext &C, unsigned ID) { void *Mem = AllocateDeserializedDecl(C, ID, sizeof(ObjCProtocolDecl)); - return new (Mem) ObjCProtocolDecl(0, 0, SourceLocation(), SourceLocation(), - 0); + ObjCProtocolDecl *Result = new (Mem) ObjCProtocolDecl(0, 0, SourceLocation(), + SourceLocation(), 0); + Result->Data.setInt(!C.getLangOpts().Modules); + return Result; } ObjCProtocolDecl *ObjCProtocolDecl::lookupProtocolNamed(IdentifierInfo *Name) { @@ -1380,9 +1386,9 @@ ObjCMethodDecl *ObjCProtocolDecl::lookupMethod(Selector Sel, } void ObjCProtocolDecl::allocateDefinitionData() { - assert(!Data && "Protocol already has a definition!"); - Data = new (getASTContext()) DefinitionData; - Data->Definition = this; + assert(!Data.getPointer() && "Protocol already has a definition!"); + Data.setPointer(new (getASTContext()) DefinitionData); + Data.getPointer()->Definition = this; } void ObjCProtocolDecl::startDefinition() { diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp index bd5ab8a5b9..42929aa71d 100644 --- a/lib/AST/DeclTemplate.cpp +++ b/lib/AST/DeclTemplate.cpp @@ -728,6 +728,8 @@ ClassTemplateSpecializationDecl::Create(ASTContext &Context, TagKind TK, SpecializedTemplate, Args, NumArgs, PrevDecl); + Result->MayHaveOutOfDateDef = false; + Context.getTypeDeclType(Result, PrevDecl); return Result; } @@ -737,7 +739,10 @@ ClassTemplateSpecializationDecl::CreateDeserialized(ASTContext &C, unsigned ID) { void *Mem = AllocateDeserializedDecl(C, ID, sizeof(ClassTemplateSpecializationDecl)); - return new (Mem) ClassTemplateSpecializationDecl(ClassTemplateSpecialization); + ClassTemplateSpecializationDecl *Result = + new (Mem) ClassTemplateSpecializationDecl(ClassTemplateSpecialization); + Result->MayHaveOutOfDateDef = false; + return Result; } void @@ -857,6 +862,7 @@ Create(ASTContext &Context, TagKind TK,DeclContext *DC, PrevDecl, SequenceNumber); Result->setSpecializationKind(TSK_ExplicitSpecialization); + Result->MayHaveOutOfDateDef = false; Context.getInjectedClassNameType(Result, CanonInjectedType); return Result; @@ -867,7 +873,10 @@ ClassTemplatePartialSpecializationDecl::CreateDeserialized(ASTContext &C, unsigned ID) { void *Mem = AllocateDeserializedDecl(C, ID, sizeof(ClassTemplatePartialSpecializationDecl)); - return new (Mem) ClassTemplatePartialSpecializationDecl(); + ClassTemplatePartialSpecializationDecl *Result + = new (Mem) ClassTemplatePartialSpecializationDecl(); + Result->MayHaveOutOfDateDef = false; + return Result; } //===----------------------------------------------------------------------===// diff --git a/test/Modules/Inputs/def.h b/test/Modules/Inputs/def.h index 6d06b08125..eb7eb7e59d 100644 --- a/test/Modules/Inputs/def.h +++ b/test/Modules/Inputs/def.h @@ -8,4 +8,13 @@ } @end +@interface Def +- defMethod; +@end +#ifdef __cplusplus +class Def2 { +public: + void func(); +}; +#endif diff --git a/test/Modules/decldef.m b/test/Modules/decldef.m new file mode 100644 index 0000000000..7fb8a61386 --- /dev/null +++ b/test/Modules/decldef.m @@ -0,0 +1,28 @@ +// RUN: rm -rf %t +// RUN: %clang_cc1 -fmodules -fobjc-arc -I %S/Inputs -fmodules-cache-path=%t %s -verify + + +// In other file: expected-note {{previous definition is here}} + +@class Def; +Def *def; + +@import decldef; +A *a1; // expected-error{{unknown type name 'A'}} +B *b1; // expected-error{{must use 'struct' tag to refer to type 'B'}} +@import decldef.Decl; + +A *a2; +struct B *b; + +void testA(A *a) { + a->ivar = 17; // expected-error{{definition of 'A' must be imported from module 'decldef.Def' before it is required}} +} + +void testB() { + B b; // Note: redundant error silenced +} + +void testDef() { + [def defMethod]; +} diff --git a/test/Modules/decldef.mm b/test/Modules/decldef.mm index 97ce72dd35..732c2a27e2 100644 --- a/test/Modules/decldef.mm +++ b/test/Modules/decldef.mm @@ -1,9 +1,18 @@ // RUN: rm -rf %t -// RUN: %clang_cc1 -fmodules -I %S/Inputs -fmodules-cache-path=%t %s -verify +// RUN: %clang_cc1 -fmodules -fobjc-arc -I %S/Inputs -fmodules-cache-path=%t %s -verify // In other file: expected-note {{previous definition is here}} +@class Def; +Def *def; +class Def2; +Def2 *def2; + +@interface Unrelated +- defMethod; +@end + @import decldef; A *a1; // expected-error{{unknown type name 'A'}} B *b1; // expected-error{{unknown type name 'B'}} @@ -19,3 +28,11 @@ void testA(A *a) { void testB() { B b; // Note: redundant error silenced } + +void testDef() { + [def defMethod]; +} + +void testDef2() { + def2->func(); +} |