aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/AST/Decl.h6
-rw-r--r--include/clang/AST/DeclBase.h5
-rw-r--r--include/clang/AST/DeclObjC.h72
-rw-r--r--include/clang/AST/ExternalASTSource.h3
-rw-r--r--lib/AST/Decl.cpp25
-rw-r--r--lib/AST/DeclBase.cpp4
-rw-r--r--lib/AST/DeclCXX.cpp9
-rw-r--r--lib/AST/DeclObjC.cpp26
-rw-r--r--lib/AST/DeclTemplate.cpp13
-rw-r--r--test/Modules/Inputs/def.h9
-rw-r--r--test/Modules/decldef.m28
-rw-r--r--test/Modules/decldef.mm19
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();
+}