aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/AST/DeclObjC.h18
-rw-r--r--include/clang/Serialization/ASTReader.h5
-rw-r--r--lib/AST/DeclObjC.cpp4
-rw-r--r--lib/Serialization/ASTReader.cpp22
-rw-r--r--lib/Serialization/ASTReaderDecl.cpp31
-rw-r--r--test/Modules/Inputs/redecl-merge-left.h2
-rw-r--r--test/Modules/Inputs/redecl-merge-right.h2
-rw-r--r--test/Modules/Inputs/redecl-merge-top.h2
8 files changed, 61 insertions, 25 deletions
diff --git a/include/clang/AST/DeclObjC.h b/include/clang/AST/DeclObjC.h
index a1a287118e..459e9b3500 100644
--- a/include/clang/AST/DeclObjC.h
+++ b/include/clang/AST/DeclObjC.h
@@ -174,8 +174,7 @@ private:
SourceLocation DeclEndLoc; // the location of the ';' or '{'.
// The following are only used for method definitions, null otherwise.
- // FIXME: space savings opportunity, consider a sub-class.
- Stmt *Body;
+ LazyDeclStmtPtr Body;
/// SelfDecl - Decl for the implicit self parameter. This is lazily
/// constructed by createImplicitParams.
@@ -242,7 +241,7 @@ private:
SelLocsKind(SelLoc_StandardNoSpace), IsOverriding(0),
MethodDeclType(T), ResultTInfo(ResultTInfo),
ParamsAndSelLocs(0), NumParams(0),
- DeclEndLoc(endLoc), Body(0), SelfDecl(0), CmdDecl(0) {
+ DeclEndLoc(endLoc), Body(), SelfDecl(0), CmdDecl(0) {
setImplicit(isImplicitlyDeclared);
}
@@ -427,10 +426,15 @@ public:
return ImplementationControl(DeclImplementation);
}
- virtual Stmt *getBody() const {
- return (Stmt*) Body;
- }
- CompoundStmt *getCompoundBody() { return (CompoundStmt*)Body; }
+ /// \brief Determine whether this method has a body.
+ virtual bool hasBody() const { return Body; }
+
+ /// \brief Retrieve the body of this method, if it has one.
+ virtual Stmt *getBody() const;
+
+ void setLazyBody(uint64_t Offset) { Body = Offset; }
+
+ CompoundStmt *getCompoundBody() { return (CompoundStmt*)getBody(); }
void setBody(Stmt *B) { Body = B; }
/// \brief Returns whether this specific method is a definition.
diff --git a/include/clang/Serialization/ASTReader.h b/include/clang/Serialization/ASTReader.h
index 7bdd0a70dc..5136113f79 100644
--- a/include/clang/Serialization/ASTReader.h
+++ b/include/clang/Serialization/ASTReader.h
@@ -341,7 +341,10 @@ private:
/// \brief The set of C++ or Objective-C classes that have forward
/// declarations that have not yet been linked to their definitions.
llvm::SmallPtrSet<Decl *, 4> PendingDefinitions;
-
+
+ /// \brief Functions or methods that have bodies that will be attached.
+ llvm::SmallDenseMap<Decl *, uint64_t, 4> PendingBodies;
+
/// \brief Read the records that describe the contents of declcontexts.
bool ReadDeclContextStorage(ModuleFile &M,
llvm::BitstreamCursor &Cursor,
diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp
index d28a910d0a..45c57d6591 100644
--- a/lib/AST/DeclObjC.cpp
+++ b/lib/AST/DeclObjC.cpp
@@ -445,6 +445,10 @@ ObjCMethodDecl *ObjCMethodDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
Selector(), QualType(), 0, 0);
}
+Stmt *ObjCMethodDecl::getBody() const {
+ return Body.get(getASTContext().getExternalSource());
+}
+
void ObjCMethodDecl::setAsRedeclaration(const ObjCMethodDecl *PrevMethod) {
assert(PrevMethod);
getASTContext().setObjCMethodRedeclaration(PrevMethod, this);
diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp
index 05a453143c..b37f8c2363 100644
--- a/lib/Serialization/ASTReader.cpp
+++ b/lib/Serialization/ASTReader.cpp
@@ -6477,9 +6477,29 @@ void ASTReader::finishPendingActions() {
for (RedeclarableTemplateDecl::redecl_iterator R = RTD->redecls_begin(),
REnd = RTD->redecls_end();
R != REnd; ++R)
- R->Common = RTD->Common;
+ R->Common = RTD->Common;
}
PendingDefinitions.clear();
+
+ // Load the bodies of any functions or methods we've encountered. We do
+ // this now (delayed) so that we can be sure that the declaration chains
+ // have been fully wired up.
+ for (llvm::SmallDenseMap<Decl *, uint64_t, 4>::iterator
+ PB = PendingBodies.begin(), PBEnd = PendingBodies.end();
+ PB != PBEnd; ++PB) {
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(PB->first)) {
+ // FIXME: Check for =delete/=default?
+ // FIXME: Complain about ODR violations here?
+ if (!getContext().getLangOpts().Modules || !FD->hasBody())
+ FD->setLazyBody(PB->second);
+ continue;
+ }
+
+ ObjCMethodDecl *MD = cast<ObjCMethodDecl>(PB->first);
+ if (!getContext().getLangOpts().Modules || !MD->hasBody())
+ MD->setLazyBody(PB->second);
+ }
+ PendingBodies.clear();
}
void ASTReader::FinishedDeserializing() {
diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp
index 762ad01b51..41d8ff98a1 100644
--- a/lib/Serialization/ASTReaderDecl.cpp
+++ b/lib/Serialization/ASTReaderDecl.cpp
@@ -47,6 +47,8 @@ namespace clang {
DeclID DeclContextIDForTemplateParmDecl;
DeclID LexicalDeclContextIDForTemplateParmDecl;
+ bool HasPendingBody;
+
uint64_t GetCurrentCursorOffset();
SourceLocation ReadSourceLocation(const RecordData &R, unsigned &I) {
@@ -198,11 +200,14 @@ namespace clang {
const RecordData &Record, unsigned &Idx)
: Reader(Reader), F(F), ThisDeclID(thisDeclID),
RawLocation(RawLocation), Record(Record), Idx(Idx),
- TypeIDForTypeDecl(0) { }
+ TypeIDForTypeDecl(0), HasPendingBody(false) { }
static void attachPreviousDecl(Decl *D, Decl *previous);
static void attachLatestDecl(Decl *D, Decl *latest);
+ /// \brief Determine whether this declaration has a pending body.
+ bool hasPendingBody() const { return HasPendingBody; }
+
void Visit(Decl *D);
void UpdateDecl(Decl *D, ModuleFile &ModuleFile,
@@ -324,9 +329,10 @@ void ASTDeclReader::Visit(Decl *D) {
// module).
// FIXME: Also consider = default and = delete.
// FIXME: Can we diagnose ODR violations somehow?
- if (Record[Idx++] &&
- (!Reader.getContext().getLangOpts().Modules || !FD->hasBody()))
- FD->setLazyBody(GetCurrentCursorOffset());
+ if (Record[Idx++]) {
+ Reader.PendingBodies[FD] = GetCurrentCursorOffset();
+ HasPendingBody = true;
+ }
} else if (D->isTemplateParameter()) {
// If we have a fully initialized template parameter, we can now
// set its DeclContext.
@@ -634,13 +640,10 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
void ASTDeclReader::VisitObjCMethodDecl(ObjCMethodDecl *MD) {
VisitNamedDecl(MD);
if (Record[Idx++]) {
- // In practice, this won't be executed (since method definitions
- // don't occur in header files).
- // Switch case IDs for this method body.
- ASTReader::SwitchCaseMapTy SwitchCaseStmtsForObjCMethod;
- SaveAndRestore<ASTReader::SwitchCaseMapTy *>
- SCFOM(Reader.CurrSwitchCaseStmts, &SwitchCaseStmtsForObjCMethod);
- MD->setBody(Reader.ReadStmt(F));
+ // Load the body on-demand. Most clients won't care, because method
+ // definitions rarely show up in headers.
+ Reader.PendingBodies[MD] = GetCurrentCursorOffset();
+ HasPendingBody = true;
MD->setSelfDecl(ReadDeclAs<ImplicitParamDecl>(Record, Idx));
MD->setCmdDecl(ReadDeclAs<ImplicitParamDecl>(Record, Idx));
}
@@ -1662,7 +1665,7 @@ inline void ASTReader::LoadedDecl(unsigned Index, Decl *D) {
/// This routine should return true for anything that might affect
/// code generation, e.g., inline function definitions, Objective-C
/// declarations with metadata, etc.
-static bool isConsumerInterestedIn(Decl *D) {
+static bool isConsumerInterestedIn(Decl *D, bool HasBody) {
// An ObjCMethodDecl is never considered as "interesting" because its
// implementation container always is.
@@ -1674,7 +1677,7 @@ static bool isConsumerInterestedIn(Decl *D) {
return Var->isFileVarDecl() &&
Var->isThisDeclarationADefinition() == VarDecl::Definition;
if (FunctionDecl *Func = dyn_cast<FunctionDecl>(D))
- return Func->doesThisDeclarationHaveABody();
+ return Func->doesThisDeclarationHaveABody() || HasBody;
return false;
}
@@ -2162,7 +2165,7 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) {
// AST consumer might need to know about, queue it.
// We don't pass it to the consumer immediately because we may be in recursive
// loading, and some declarations may still be initializing.
- if (isConsumerInterestedIn(D))
+ if (isConsumerInterestedIn(D, Reader.hasPendingBody()))
InterestingDecls.push_back(D);
return D;
diff --git a/test/Modules/Inputs/redecl-merge-left.h b/test/Modules/Inputs/redecl-merge-left.h
index ee794ff320..5e6d2e512b 100644
--- a/test/Modules/Inputs/redecl-merge-left.h
+++ b/test/Modules/Inputs/redecl-merge-left.h
@@ -60,7 +60,7 @@ typedef int T1;
typedef float T2;
int func0(int);
-int func1(int);
+int func1(int x) { return x; }
int func2(int);
diff --git a/test/Modules/Inputs/redecl-merge-right.h b/test/Modules/Inputs/redecl-merge-right.h
index f62020f205..20223083c3 100644
--- a/test/Modules/Inputs/redecl-merge-right.h
+++ b/test/Modules/Inputs/redecl-merge-right.h
@@ -65,7 +65,7 @@ typedef double T2;
int func0(int);
int func1(int);
int func1(int);
-int func1(int);
+int func1(int x) { return x; }
int func1(int);
static int func2(int);
diff --git a/test/Modules/Inputs/redecl-merge-top.h b/test/Modules/Inputs/redecl-merge-top.h
index 25456deb28..690e6df1c9 100644
--- a/test/Modules/Inputs/redecl-merge-top.h
+++ b/test/Modules/Inputs/redecl-merge-top.h
@@ -14,3 +14,5 @@
struct S1;
struct S2;
struct S2;
+
+int func1(int);