summaryrefslogtreecommitdiffstats
path: root/clang
diff options
context:
space:
mode:
Diffstat (limited to 'clang')
-rw-r--r--clang/include/clang/Serialization/ASTReader.h11
-rw-r--r--clang/lib/Serialization/ASTReader.cpp42
-rw-r--r--clang/lib/Serialization/ASTReaderDecl.cpp36
-rw-r--r--clang/test/Modules/merge-deduced-return.cpp6
-rw-r--r--clang/test/Modules/merge-lambdas.cpp3
5 files changed, 78 insertions, 20 deletions
diff --git a/clang/include/clang/Serialization/ASTReader.h b/clang/include/clang/Serialization/ASTReader.h
index 0eecb6f5d65..b959f596f90 100644
--- a/clang/include/clang/Serialization/ASTReader.h
+++ b/clang/include/clang/Serialization/ASTReader.h
@@ -539,6 +539,11 @@ private:
/// declaration that has an exception specification.
llvm::SmallMapVector<Decl *, FunctionDecl *, 4> PendingExceptionSpecUpdates;
+ /// Deduced return type updates that have been loaded but not yet propagated
+ /// across the relevant redeclaration chain. The map key is the canonical
+ /// declaration and the value is the deduced return type.
+ llvm::SmallMapVector<FunctionDecl *, QualType, 4> PendingDeducedTypeUpdates;
+
/// Declarations that have been imported and have typedef names for
/// linkage purposes.
llvm::DenseMap<std::pair<DeclContext *, IdentifierInfo *>, NamedDecl *>
@@ -1056,6 +1061,12 @@ private:
/// Objective-C protocols.
std::deque<InterestingDecl> PotentiallyInterestingDecls;
+ /// The list of deduced function types that we have not yet read, because
+ /// they might contain a deduced return type that refers to a local type
+ /// declared within the function.
+ SmallVector<std::pair<FunctionDecl *, serialization::TypeID>, 16>
+ PendingFunctionTypes;
+
/// The list of redeclaration chains that still need to be
/// reconstructed, and the local offset to the corresponding list
/// of redeclarations.
diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp
index 723839ff62b..8a02ea93f40 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -9254,7 +9254,7 @@ std::string ASTReader::getOwningModuleNameForDiagnostic(const Decl *D) {
}
void ASTReader::finishPendingActions() {
- while (!PendingIdentifierInfos.empty() ||
+ while (!PendingIdentifierInfos.empty() || !PendingFunctionTypes.empty() ||
!PendingIncompleteDeclChains.empty() || !PendingDeclChains.empty() ||
!PendingMacroIDs.empty() || !PendingDeclContextInfos.empty() ||
!PendingUpdateRecords.empty()) {
@@ -9273,6 +9273,21 @@ void ASTReader::finishPendingActions() {
SetGloballyVisibleDecls(II, DeclIDs, &TopLevelDecls[II]);
}
+ // Load each function type that we deferred loading because it was a
+ // deduced type that might refer to a local type declared within itself.
+ for (unsigned I = 0; I != PendingFunctionTypes.size(); ++I) {
+ auto *FD = PendingFunctionTypes[I].first;
+ FD->setType(GetType(PendingFunctionTypes[I].second));
+
+ // If we gave a function a deduced return type, remember that we need to
+ // propagate that along the redeclaration chain.
+ auto *DT = FD->getReturnType()->getContainedDeducedType();
+ if (DT && DT->isDeduced())
+ PendingDeducedTypeUpdates.insert(
+ {FD->getCanonicalDecl(), FD->getReturnType()});
+ }
+ PendingFunctionTypes.clear();
+
// For each decl chain that we wanted to complete while deserializing, mark
// it as "still needs to be completed".
for (unsigned I = 0; I != PendingIncompleteDeclChains.size(); ++I) {
@@ -9282,7 +9297,8 @@ void ASTReader::finishPendingActions() {
// Load pending declaration chains.
for (unsigned I = 0; I != PendingDeclChains.size(); ++I)
- loadPendingDeclChain(PendingDeclChains[I].first, PendingDeclChains[I].second);
+ loadPendingDeclChain(PendingDeclChains[I].first,
+ PendingDeclChains[I].second);
PendingDeclChains.clear();
// Make the most recent of the top-level declarations visible.
@@ -11531,11 +11547,16 @@ void ASTReader::FinishedDeserializing() {
--NumCurrentElementsDeserializing;
if (NumCurrentElementsDeserializing == 0) {
- // Propagate exception specification updates along redeclaration chains.
- while (!PendingExceptionSpecUpdates.empty()) {
- auto Updates = std::move(PendingExceptionSpecUpdates);
+ // Propagate exception specification and deduced type updates along
+ // redeclaration chains.
+ //
+ // We do this now rather than in finishPendingActions because we want to
+ // be able to walk the complete redeclaration chains of the updated decls.
+ while (!PendingExceptionSpecUpdates.empty() ||
+ !PendingDeducedTypeUpdates.empty()) {
+ auto ESUpdates = std::move(PendingExceptionSpecUpdates);
PendingExceptionSpecUpdates.clear();
- for (auto Update : Updates) {
+ for (auto Update : ESUpdates) {
ProcessingUpdatesRAIIObj ProcessingUpdates(*this);
auto *FPT = Update.second->getType()->castAs<FunctionProtoType>();
auto ESI = FPT->getExtProtoInfo().ExceptionSpec;
@@ -11544,6 +11565,15 @@ void ASTReader::FinishedDeserializing() {
for (auto *Redecl : Update.second->redecls())
getContext().adjustExceptionSpec(cast<FunctionDecl>(Redecl), ESI);
}
+
+ auto DTUpdates = std::move(PendingDeducedTypeUpdates);
+ PendingDeducedTypeUpdates.clear();
+ for (auto Update : DTUpdates) {
+ ProcessingUpdatesRAIIObj ProcessingUpdates(*this);
+ // FIXME: If the return type is already deduced, check that it matches.
+ getContext().adjustDeducedFunctionResultType(Update.first,
+ Update.second);
+ }
}
if (ReadTimer)
diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp
index d17ec8e0461..613579d9079 100644
--- a/clang/lib/Serialization/ASTReaderDecl.cpp
+++ b/clang/lib/Serialization/ASTReaderDecl.cpp
@@ -541,9 +541,6 @@ void ASTDeclReader::Visit(Decl *D) {
// if we have a fully initialized TypeDecl, we can safely read its type now.
ID->TypeForDecl = Reader.GetType(DeferredTypeID).getTypePtrOrNull();
} else if (auto *FD = dyn_cast<FunctionDecl>(D)) {
- if (DeferredTypeID)
- FD->setType(Reader.GetType(DeferredTypeID));
-
// FunctionDecl's body was written last after all other Stmts/Exprs.
// We only read it if FD doesn't already have a body (e.g., from another
// module).
@@ -844,10 +841,11 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
// We'll set up the real type in Visit, once we've finished loading the
// function.
FD->setType(FD->getTypeSourceInfo()->getType());
+ Reader.PendingFunctionTypes.push_back({FD, DeferredTypeID});
} else {
FD->setType(Reader.GetType(DeferredTypeID));
- DeferredTypeID = 0;
}
+ DeferredTypeID = 0;
ReadDeclarationNameLoc(FD->DNLoc, FD->getDeclName());
FD->IdentifierNamespace = Record.readInt();
@@ -3370,6 +3368,11 @@ void ASTDeclReader::attachPreviousDeclImpl(ASTReader &Reader,
}
}
+static bool isUndeducedReturnType(QualType T) {
+ auto *DT = T->getContainedDeducedType();
+ return DT && !DT->isDeduced();
+}
+
template<>
void ASTDeclReader::attachPreviousDeclImpl(ASTReader &Reader,
Redeclarable<FunctionDecl> *D,
@@ -3401,17 +3404,26 @@ void ASTDeclReader::attachPreviousDeclImpl(ASTReader &Reader,
FD->setImplicitlyInline(true);
}
- // If we need to propagate an exception specification along the redecl
- // chain, make a note of that so that we can do so later.
auto *FPT = FD->getType()->getAs<FunctionProtoType>();
auto *PrevFPT = PrevFD->getType()->getAs<FunctionProtoType>();
if (FPT && PrevFPT) {
+ // If we need to propagate an exception specification along the redecl
+ // chain, make a note of that so that we can do so later.
bool IsUnresolved = isUnresolvedExceptionSpec(FPT->getExceptionSpecType());
bool WasUnresolved =
isUnresolvedExceptionSpec(PrevFPT->getExceptionSpecType());
if (IsUnresolved != WasUnresolved)
Reader.PendingExceptionSpecUpdates.insert(
- std::make_pair(Canon, IsUnresolved ? PrevFD : FD));
+ {Canon, IsUnresolved ? PrevFD : FD});
+
+ // If we need to propagate a deduced return type along the redecl chain,
+ // make a note of that so that we can do it later.
+ bool IsUndeduced = isUndeducedReturnType(FPT->getReturnType());
+ bool WasUndeduced = isUndeducedReturnType(PrevFPT->getReturnType());
+ if (IsUndeduced != WasUndeduced)
+ Reader.PendingDeducedTypeUpdates.insert(
+ {cast<FunctionDecl>(Canon),
+ (IsUndeduced ? PrevFPT : FPT)->getReturnType()});
}
}
@@ -4328,14 +4340,10 @@ void ASTDeclReader::UpdateDecl(Decl *D,
}
case UPD_CXX_DEDUCED_RETURN_TYPE: {
- // FIXME: Also do this when merging redecls.
+ auto *FD = cast<FunctionDecl>(D);
QualType DeducedResultType = Record.readType();
- for (auto *Redecl : merged_redecls(D)) {
- // FIXME: If the return type is already deduced, check that it matches.
- auto *FD = cast<FunctionDecl>(Redecl);
- Reader.getContext().adjustDeducedFunctionResultType(FD,
- DeducedResultType);
- }
+ Reader.PendingDeducedTypeUpdates.insert(
+ {FD->getCanonicalDecl(), DeducedResultType});
break;
}
diff --git a/clang/test/Modules/merge-deduced-return.cpp b/clang/test/Modules/merge-deduced-return.cpp
index 0a4de7b9755..71dc29b633b 100644
--- a/clang/test/Modules/merge-deduced-return.cpp
+++ b/clang/test/Modules/merge-deduced-return.cpp
@@ -8,6 +8,8 @@ module A {}
#pragma clang module begin A
inline auto f() { struct X {}; return X(); }
inline auto a = f();
+auto g(int);
+template<typename T> auto h(T t) { return g(t); }
#pragma clang module end
#pragma clang module endbuild
@@ -17,12 +19,14 @@ module B {}
#pragma clang module begin B
inline auto f() { struct X {}; return X(); }
inline auto b = f();
+auto g(int) { return 0; }
#pragma clang module end
#pragma clang module endbuild
#ifdef LOCAL
inline auto f() { struct X {}; return X(); }
inline auto b = f();
+auto g(int) { return 0; }
#else
#pragma clang module import B
#endif
@@ -31,3 +35,5 @@ inline auto b = f();
using T = decltype(a);
using T = decltype(b);
+
+int test_g = h(0);
diff --git a/clang/test/Modules/merge-lambdas.cpp b/clang/test/Modules/merge-lambdas.cpp
index 8b3b5013284..463a4c9b2fc 100644
--- a/clang/test/Modules/merge-lambdas.cpp
+++ b/clang/test/Modules/merge-lambdas.cpp
@@ -46,3 +46,6 @@ using U = decltype(y2);
using V = decltype(x3);
using V = decltype(y3);
+
+#pragma clang module import A
+void (*p)() = f<int>();
OpenPOWER on IntegriCloud