/// 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 *>
/// 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.
}
void ASTReader::finishPendingActions() {
- while (!PendingIdentifierInfos.empty() ||
+ while (!PendingIdentifierInfos.empty() || !PendingFunctionTypes.empty() ||
!PendingIncompleteDeclChains.empty() || !PendingDeclChains.empty() ||
!PendingMacroIDs.empty() || !PendingDeclContextInfos.empty() ||
!PendingUpdateRecords.empty()) {
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) {
// 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.
--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;
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)
// 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).
// 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();
}
}
+static bool isUndeducedReturnType(QualType T) {
+ auto *DT = T->getContainedDeducedType();
+ return DT && !DT->isDeduced();
+}
+
template<>
void ASTDeclReader::attachPreviousDeclImpl(ASTReader &Reader,
Redeclarable<FunctionDecl> *D,
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()});
}
}
}
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;
}
#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
#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
using T = decltype(a);
using T = decltype(b);
+
+int test_g = h(0);
using V = decltype(x3);
using V = decltype(y3);
+
+#pragma clang module import A
+void (*p)() = f<int>();