From be3015ba66355f8f3a5cb197947d5fbe064163f1 Mon Sep 17 00:00:00 2001 From: Mike Ash Date: Thu, 8 Jun 2023 11:00:26 -0400 Subject: [PATCH 01/37] [Test] Remove five second delay in swift-reflection-test startup. This was added in ea54c3ba40447b165e108df7ec7ce8d36a9a55cb, presumably inadvertently. --- stdlib/tools/swift-reflection-test/swift-reflection-test.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/stdlib/tools/swift-reflection-test/swift-reflection-test.c b/stdlib/tools/swift-reflection-test/swift-reflection-test.c index 5339f0b0c544b..c4f9c0c75d006 100644 --- a/stdlib/tools/swift-reflection-test/swift-reflection-test.c +++ b/stdlib/tools/swift-reflection-test/swift-reflection-test.c @@ -764,10 +764,6 @@ int doDumpHeapInstance(const char *BinaryFilename) { exit(status); } default: { // Parent - for (int i = 5; i > 1; i--) { - fprintf(stderr, "%d\n", i); - sleep(1); - } close(PipeMemoryReader_getChildReadFD(&Pipe)); close(PipeMemoryReader_getChildWriteFD(&Pipe)); SwiftReflectionContextRef RC = From 0996342b47428423ba6c8e4654dc41b7a7222407 Mon Sep 17 00:00:00 2001 From: Alex Hoppen Date: Fri, 9 Jun 2023 15:49:17 -0700 Subject: [PATCH 02/37] [CodeCompletion] Fix an issue that causes an iterator to be invalidated while iterating MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In `SourceLookupCache::lookupVisibleDecls`, copy the top level values before iterating them. If we have 'addinitstotoplevel' enabled, calling 'addConstructorCallsForType' can cause macros to get expanded, which can then cause new members ot get added to 'TopLevelValues', invalidating the current iterator. I have not been able to reduce this to a test case that doesn’t rely on the `Observation` module in the SDK but here is the test case with which I was able to reproduce the issue very reliably. ```swift import Foundation import Observation @Observable class MyObject {} extension MyObject {} // RUN: ~/sbin/sourcekitd-test \ // RUN: -req=complete.open \ // RUN: -req-opts=addinitstotoplevel=1 \ // RUN: -pos=8:1 \ // RUN: %s \ // RUN: -- \ // RUN: %s \ // RUN: -Xfrontend \ // RUN: -load-plugin-library \ // RUN: -Xfrontend \ // RUN: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/host/plugins/libObservationMacros.dylib \ // RUN: -sdk \ // RUN: /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX14.0.sdk ``` rdar://109202157 --- lib/IDE/CompletionLookup.cpp | 49 +++++++++++++++++++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/lib/IDE/CompletionLookup.cpp b/lib/IDE/CompletionLookup.cpp index b697641afeba4..6d402107a1812 100644 --- a/lib/IDE/CompletionLookup.cpp +++ b/lib/IDE/CompletionLookup.cpp @@ -3214,6 +3214,36 @@ void CompletionLookup::getTypeCompletionsInDeclContext(SourceLoc Loc, RequestedCachedResults.insert(RequestedResultsTy::topLevelResults(filter)); } +namespace { + +/// A \c VisibleDeclConsumer that stores all decls that are found and is able +/// to forward the to another \c VisibleDeclConsumer later. +class StoringDeclConsumer : public VisibleDeclConsumer { + struct FoundDecl { + ValueDecl *VD; + DeclVisibilityKind Reason; + DynamicLookupInfo DynamicLookupInfo; + }; + + std::vector FoundDecls; + + void foundDecl(ValueDecl *VD, DeclVisibilityKind Reason, + DynamicLookupInfo DynamicLookupInfo = {}) override { + FoundDecls.push_back({VD, Reason, DynamicLookupInfo}); + } + +public: + /// Call \c foundDecl for every declaration that this consumer has found. + void forward(VisibleDeclConsumer &Consumer) { + for (auto &FoundDecl : FoundDecls) { + Consumer.foundDecl(FoundDecl.VD, FoundDecl.Reason, + FoundDecl.DynamicLookupInfo); + } + } +}; + +} // namespace + void CompletionLookup::getToplevelCompletions(CodeCompletionFilter Filter) { Kind = (Filter - CodeCompletionFilterFlag::Module) .containsOnly(CodeCompletionFilterFlag::Type) @@ -3221,9 +3251,24 @@ void CompletionLookup::getToplevelCompletions(CodeCompletionFilter Filter) { : LookupKind::ValueInDeclContext; NeedLeadingDot = false; + // If we have 'addinitstotoplevel' enabled, calling `foundDecl` on `this` + // can cause macros to get expanded, which can then cause new members ot get + // added to 'TopLevelValues', invalidating iterator over `TopLevelDecls` in + // `SourceLookupCache::lookupVisibleDecls`. + // + // Technically `foundDecl` should not expand macros or discover new top level + // members in any way because those newly discovered decls will not be added + // to the code completion results. However, it's preferrable to miss results + // than to silently invalidate a collection, resulting in hard-to-diagnose + // crashes. + // Thus, store all the decls found by `CurrModule->lookupVisibleDecls` in a + // vector first and only call `this->foundDecl` once we have left the + // iteration loop over `TopLevelDecls`. + StoringDeclConsumer StoringConsumer; + UsableFilteringDeclConsumer UsableFilteringConsumer( Ctx.SourceMgr, CurrDeclContext, Ctx.SourceMgr.getIDEInspectionTargetLoc(), - *this); + StoringConsumer); AccessFilteringDeclConsumer AccessFilteringConsumer(CurrDeclContext, UsableFilteringConsumer); @@ -3242,6 +3287,8 @@ void CompletionLookup::getToplevelCompletions(CodeCompletionFilter Filter) { CurrModule->lookupVisibleDecls({}, FilteringConsumer, NLKind::UnqualifiedLookup); + + StoringConsumer.forward(*this); } void CompletionLookup::lookupExternalModuleDecls( From abcdc6c60f2ea456869347da4f3c2698d38528de Mon Sep 17 00:00:00 2001 From: Holly Borla Date: Wed, 7 Jun 2023 21:27:33 -0700 Subject: [PATCH 03/37] [ASTScope] Rename and generalize AttachedPropertyWrapperScope to CustomAttributeScope so that it can represent the scope for any custom attribute and its arguments. This commit is NFC, but CustomAttributeScope is now applicable to attached macros. --- include/swift/AST/ASTScope.h | 24 ++++++++++-------------- lib/AST/ASTScope.cpp | 2 +- lib/AST/ASTScopeCreation.cpp | 6 +++--- lib/AST/ASTScopeSourceRange.cpp | 2 +- 4 files changed, 15 insertions(+), 19 deletions(-) diff --git a/include/swift/AST/ASTScope.h b/include/swift/AST/ASTScope.h index 5ebe70dcef3be..5cbbc8ee8ab4e 100644 --- a/include/swift/AST/ASTScope.h +++ b/include/swift/AST/ASTScope.h @@ -840,24 +840,20 @@ class DefaultArgumentInitializerScope final : public ASTScopeImpl { bool ignoreInDebugInfo() const override { return true; } }; -/// Consider: -/// @_propertyWrapper -/// struct WrapperWithInitialValue { -/// } -/// struct HasWrapper { -/// @WrapperWithInitialValue var y = 17 -/// } -/// Lookup has to be able to find the use of WrapperWithInitialValue, that's -/// what this scope is for. Because the source positions are screwy. - -class AttachedPropertyWrapperScope final : public ASTScopeImpl { +/// The scope for custom attributes and their arguments, such as for +/// attached property wrappers and for attached macros. +/// +/// Source locations for the attribute name and its arguments are in the +/// custom attribute, so lookup is invoked from within the attribute +/// itself. +class CustomAttributeScope final : public ASTScopeImpl { public: CustomAttr *attr; - VarDecl *decl; + ValueDecl *decl; - AttachedPropertyWrapperScope(CustomAttr *attr, VarDecl *decl) + CustomAttributeScope(CustomAttr *attr, ValueDecl *decl) : attr(attr), decl(decl) {} - virtual ~AttachedPropertyWrapperScope() {} + virtual ~CustomAttributeScope() {} protected: ASTScopeImpl *expandSpecifically(ScopeCreator &) override; diff --git a/lib/AST/ASTScope.cpp b/lib/AST/ASTScope.cpp index c4eb1d1370f5f..e71d5f2e9014a 100644 --- a/lib/AST/ASTScope.cpp +++ b/lib/AST/ASTScope.cpp @@ -138,7 +138,7 @@ DEFINE_GET_CLASS_NAME(AbstractFunctionDeclScope) DEFINE_GET_CLASS_NAME(ParameterListScope) DEFINE_GET_CLASS_NAME(FunctionBodyScope) DEFINE_GET_CLASS_NAME(DefaultArgumentInitializerScope) -DEFINE_GET_CLASS_NAME(AttachedPropertyWrapperScope) +DEFINE_GET_CLASS_NAME(CustomAttributeScope) DEFINE_GET_CLASS_NAME(PatternEntryDeclScope) DEFINE_GET_CLASS_NAME(PatternEntryInitializerScope) DEFINE_GET_CLASS_NAME(ConditionalClausePatternUseScope) diff --git a/lib/AST/ASTScopeCreation.cpp b/lib/AST/ASTScopeCreation.cpp index 66821d17e6c49..ef6f34abd8c53 100644 --- a/lib/AST/ASTScopeCreation.cpp +++ b/lib/AST/ASTScopeCreation.cpp @@ -602,7 +602,7 @@ void ScopeCreator::addChildrenForKnownAttributes(ValueDecl *decl, } } else if (auto *customAttr = dyn_cast(attr)) { if (auto *vd = dyn_cast(decl)) { - constructExpandAndInsert( + constructExpandAndInsert( parent, customAttr, vd); } } @@ -716,7 +716,7 @@ CREATES_NEW_INSERTION_POINT(ConditionalClausePatternUseScope) NO_NEW_INSERTION_POINT(FunctionBodyScope) NO_NEW_INSERTION_POINT(AbstractFunctionDeclScope) -NO_NEW_INSERTION_POINT(AttachedPropertyWrapperScope) +NO_NEW_INSERTION_POINT(CustomAttributeScope) NO_NEW_INSERTION_POINT(EnumElementScope) NO_NEW_INSERTION_POINT(GuardStmtBodyScope) NO_NEW_INSERTION_POINT(ParameterListScope) @@ -1177,7 +1177,7 @@ void DefaultArgumentInitializerScope:: scopeCreator.addToScopeTree(initExpr, this); } -void AttachedPropertyWrapperScope:: +void CustomAttributeScope:: expandAScopeThatDoesNotCreateANewInsertionPoint( ScopeCreator &scopeCreator) { if (auto *args = attr->getArgs()) { diff --git a/lib/AST/ASTScopeSourceRange.cpp b/lib/AST/ASTScopeSourceRange.cpp index 0073be55f8e89..1ce85b9319b55 100644 --- a/lib/AST/ASTScopeSourceRange.cpp +++ b/lib/AST/ASTScopeSourceRange.cpp @@ -360,7 +360,7 @@ SourceRange ClosureParametersScope::getSourceRangeOfThisASTNode( return explicitClosureExpr->getSourceRange(); } -SourceRange AttachedPropertyWrapperScope::getSourceRangeOfThisASTNode( +SourceRange CustomAttributeScope::getSourceRangeOfThisASTNode( const bool omitAssertions) const { return attr->getRange(); } From 2c0c596d95f9ad967a97d6f77a032ad266f40b36 Mon Sep 17 00:00:00 2001 From: Holly Borla Date: Fri, 9 Jun 2023 23:33:17 -0700 Subject: [PATCH 04/37] [ASTScope] Add attribute scopes for nominal type and extension scopes. --- include/swift/AST/ASTScope.h | 8 ++++---- lib/AST/ASTScopeCreation.cpp | 14 +++++++------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/include/swift/AST/ASTScope.h b/include/swift/AST/ASTScope.h index 5cbbc8ee8ab4e..6c88eca412355 100644 --- a/include/swift/AST/ASTScope.h +++ b/include/swift/AST/ASTScope.h @@ -849,9 +849,9 @@ class DefaultArgumentInitializerScope final : public ASTScopeImpl { class CustomAttributeScope final : public ASTScopeImpl { public: CustomAttr *attr; - ValueDecl *decl; + Decl *decl; - CustomAttributeScope(CustomAttr *attr, ValueDecl *decl) + CustomAttributeScope(CustomAttr *attr,Decl *decl) : attr(attr), decl(decl) {} virtual ~CustomAttributeScope() {} @@ -1130,9 +1130,9 @@ class SpecializeAttributeScope final : public ASTScopeImpl { class DifferentiableAttributeScope final : public ASTScopeImpl { public: DifferentiableAttr *const differentiableAttr; - ValueDecl *const attributedDeclaration; + Decl *const attributedDeclaration; - DifferentiableAttributeScope(DifferentiableAttr *diffAttr, ValueDecl *decl) + DifferentiableAttributeScope(DifferentiableAttr *diffAttr, Decl *decl) : differentiableAttr(diffAttr), attributedDeclaration(decl) {} virtual ~DifferentiableAttributeScope() {} diff --git a/lib/AST/ASTScopeCreation.cpp b/lib/AST/ASTScopeCreation.cpp index ef6f34abd8c53..f2bcdedd65f1b 100644 --- a/lib/AST/ASTScopeCreation.cpp +++ b/lib/AST/ASTScopeCreation.cpp @@ -180,7 +180,7 @@ class ScopeCreator final : public ASTAllocated { addChildrenForParsedAccessors(AbstractStorageDecl *asd, ASTScopeImpl *parent); - void addChildrenForKnownAttributes(ValueDecl *decl, + void addChildrenForKnownAttributes(Decl *decl, ASTScopeImpl *parent); /// Add PatternEntryDeclScopes for each pattern binding entry. @@ -569,7 +569,7 @@ void ScopeCreator::addChildrenForParsedAccessors( }); } -void ScopeCreator::addChildrenForKnownAttributes(ValueDecl *decl, +void ScopeCreator::addChildrenForKnownAttributes(Decl *decl, ASTScopeImpl *parent) { SmallVector relevantAttrs; @@ -601,10 +601,8 @@ void ScopeCreator::addChildrenForKnownAttributes(ValueDecl *decl, parent, specAttr, afd); } } else if (auto *customAttr = dyn_cast(attr)) { - if (auto *vd = dyn_cast(decl)) { - constructExpandAndInsert( - parent, customAttr, vd); - } + constructExpandAndInsert( + parent, customAttr, decl); } } } @@ -1192,7 +1190,9 @@ ASTScopeImpl *GenericTypeOrExtensionWholePortion::expandScope( GenericTypeOrExtensionScope *scope, ScopeCreator &scopeCreator) const { // Get now in case recursion emancipates scope auto *const ip = scope->getParent().get(); - + + scopeCreator.addChildrenForKnownAttributes(scope->getDecl(), scope); + auto *context = scope->getGenericContext(); auto *genericParams = (isa(context) ? context->getParsedGenericParams() From cd79cf97d683a7fb711d89cff2ea0bcd447e0d6b Mon Sep 17 00:00:00 2001 From: Holly Borla Date: Sat, 10 Jun 2023 00:40:15 -0700 Subject: [PATCH 05/37] [ASTScope] Add APIs for determining whether a given source location is inside a macro argument. --- include/swift/AST/ASTScope.h | 25 ++++++++++++++++++++++++- include/swift/AST/NameLookup.h | 4 ++++ lib/AST/ASTScope.cpp | 5 +++++ lib/AST/ASTScopeLookup.cpp | 18 ++++++++++++++++++ 4 files changed, 51 insertions(+), 1 deletion(-) diff --git a/include/swift/AST/ASTScope.h b/include/swift/AST/ASTScope.h index 6c88eca412355..a8d229e89069b 100644 --- a/include/swift/AST/ASTScope.h +++ b/include/swift/AST/ASTScope.h @@ -278,6 +278,17 @@ class ASTScopeImpl : public ASTAllocated { static std::pair lookupFallthroughSourceAndDest(SourceFile *sourceFile, SourceLoc loc); + /// Returns \c true if the given source location is inside an attached + /// or freestanding macro argument. + static bool isInMacroArgument(SourceFile *sourceFile, SourceLoc loc); + + /// Returns \c true if this scope contains macro arguments. + /// + /// This is always true within macro expansion decl scopes, and it's + /// true within custom attribute scopes if the attribute name is a + /// potential macro reference. + virtual bool isMacroArgumentScope() const { return false; } + /// Scopes that cannot bind variables may set this to true to create more /// compact scope tree in the debug info. virtual bool ignoreInDebugInfo() const { return false; } @@ -867,7 +878,15 @@ class CustomAttributeScope final : public ASTScopeImpl { NullablePtr getDeclAttributeIfAny() const override { return attr; } - bool ignoreInDebugInfo() const override { return true; } + bool ignoreInDebugInfo() const override { return true; } + + bool isMacroArgumentScope() const override { + // FIXME: This should check whether the attribute name is + // a macro. Otherwise, macro expansion will be suppressed + // for property wrapper arguments. + return true; + } + private: void expandAScopeThatDoesNotCreateANewInsertionPoint(ScopeCreator &); }; @@ -1266,6 +1285,10 @@ class MacroExpansionDeclScope final : public ASTScopeImpl { SourceRange getSourceRangeOfThisASTNode(bool omitAssertions = false) const override; + bool isMacroArgumentScope() const override { + return true; + } + protected: void printSpecifics(llvm::raw_ostream &out) const override; diff --git a/include/swift/AST/NameLookup.h b/include/swift/AST/NameLookup.h index a4b8a0a3c14f4..baa687e140652 100644 --- a/include/swift/AST/NameLookup.h +++ b/include/swift/AST/NameLookup.h @@ -816,6 +816,10 @@ class ASTScope : public ASTAllocated { static std::pair lookupFallthroughSourceAndDest(SourceFile *sourceFile, SourceLoc loc); + /// Returns \c true if the given source location is inside an attached + /// or freestanding macro argument. + static bool isInMacroArgument(SourceFile *sourceFile, SourceLoc loc); + SWIFT_DEBUG_DUMP; void print(llvm::raw_ostream &) const; void dumpOneScopeMapLocation(std::pair); diff --git a/lib/AST/ASTScope.cpp b/lib/AST/ASTScope.cpp index e71d5f2e9014a..b9b830aad6cce 100644 --- a/lib/AST/ASTScope.cpp +++ b/lib/AST/ASTScope.cpp @@ -60,6 +60,11 @@ std::pair ASTScope::lookupFallthroughSourceAndDest( return ASTScopeImpl::lookupFallthroughSourceAndDest(sourceFile, loc); } +bool ASTScope::isInMacroArgument(SourceFile *sourceFile, + SourceLoc loc) { + return ASTScopeImpl::isInMacroArgument(sourceFile, loc); +} + #if SWIFT_COMPILER_IS_MSVC #pragma warning(push) #pragma warning(disable : 4996) diff --git a/lib/AST/ASTScopeLookup.cpp b/lib/AST/ASTScopeLookup.cpp index 676e6e9dbdd77..f7aa0bba5b46c 100644 --- a/lib/AST/ASTScopeLookup.cpp +++ b/lib/AST/ASTScopeLookup.cpp @@ -675,3 +675,21 @@ std::pair ASTScopeImpl::lookupFallthroughSourceAndDest( return { nullptr, nullptr }; } + +bool ASTScopeImpl::isInMacroArgument(SourceFile *sourceFile, + SourceLoc loc) { + if (!sourceFile || sourceFile->Kind == SourceFileKind::Interface) + return false; + + if (loc.isInvalid()) + return false; + + auto *fileScope = sourceFile->getScope().impl; + auto *scope = fileScope->findInnermostEnclosingScope(loc, nullptr); + do { + if (scope->isMacroArgumentScope()) + return true; + } while ((scope = scope->getParent().getPtrOrNull())); + + return false; +} From 29430645110307597f6aa1ea0e342ac0dfd4fc45 Mon Sep 17 00:00:00 2001 From: Holly Borla Date: Sat, 10 Jun 2023 00:52:17 -0700 Subject: [PATCH 06/37] [Macros] Always exclude macro expansions in TypeChecker::lookupMacros. --- lib/Sema/CSGen.cpp | 9 ++++----- lib/Sema/TypeCheckDecl.cpp | 12 ++++++++++-- lib/Sema/TypeCheckMacros.cpp | 2 +- lib/Sema/TypeChecker.h | 3 +-- 4 files changed, 16 insertions(+), 10 deletions(-) diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp index c30c94dbc2792..8286a65c3a1ec 100644 --- a/lib/Sema/CSGen.cpp +++ b/lib/Sema/CSGen.cpp @@ -1244,7 +1244,7 @@ namespace { auto macroIdent = ctx.getIdentifier(kind); auto macros = lookupMacros( - macroIdent, expr->getLoc(), FunctionRefKind::Unapplied, + macroIdent, FunctionRefKind::Unapplied, MacroRole::Expression); if (!macros.empty()) { // Introduce an overload set for the macro reference. @@ -3896,12 +3896,12 @@ namespace { /// Lookup all macros with the given macro name. SmallVector - lookupMacros(Identifier macroName, SourceLoc loc, + lookupMacros(Identifier macroName, FunctionRefKind functionRefKind, MacroRoles roles) { SmallVector choices; auto results = TypeChecker::lookupMacros( - CurDC, DeclNameRef(macroName), loc, roles); + CurDC, DeclNameRef(macroName), roles); for (const auto &result : results) { OverloadChoice choice = OverloadChoice(Type(), result, functionRefKind); choices.push_back(choice); @@ -3926,8 +3926,7 @@ namespace { auto macroIdent = expr->getMacroName().getBaseIdentifier(); FunctionRefKind functionRefKind = FunctionRefKind::SingleApply; auto macros = lookupMacros( - macroIdent, expr->getMacroNameLoc().getBaseNameLoc(), - functionRefKind, expr->getMacroRoles()); + macroIdent, functionRefKind, expr->getMacroRoles()); if (macros.empty()) { ctx.Diags.diagnose(expr->getMacroNameLoc(), diag::macro_undefined, macroIdent) diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp index dd0f7655608e3..f545fa889a86a 100644 --- a/lib/Sema/TypeCheckDecl.cpp +++ b/lib/Sema/TypeCheckDecl.cpp @@ -1611,11 +1611,19 @@ TypeChecker::lookupPrecedenceGroup(DeclContext *dc, Identifier name, SmallVector TypeChecker::lookupMacros(DeclContext *dc, DeclNameRef macroName, - SourceLoc loc, MacroRoles roles) { + MacroRoles roles) { SmallVector choices; auto moduleScopeDC = dc->getModuleScopeContext(); ASTContext &ctx = moduleScopeDC->getASTContext(); - UnqualifiedLookupDescriptor descriptor(macroName, moduleScopeDC); + + // Macro lookup should always exclude macro expansions; macro + // expansions cannot introduce new macro declarations. Note that + // the source location here doesn't matter. + UnqualifiedLookupDescriptor descriptor{ + macroName, moduleScopeDC, SourceLoc(), + UnqualifiedLookupFlags::ExcludeMacroExpansions + }; + auto lookup = evaluateOrDefault( ctx.evaluator, UnqualifiedLookupRequest{descriptor}, {}); for (const auto &found : lookup.allResults()) { diff --git a/lib/Sema/TypeCheckMacros.cpp b/lib/Sema/TypeCheckMacros.cpp index 90e00f9fb0c78..a5b1922c2b237 100644 --- a/lib/Sema/TypeCheckMacros.cpp +++ b/lib/Sema/TypeCheckMacros.cpp @@ -1487,7 +1487,7 @@ ConcreteDeclRef ResolveMacroRequest::evaluate(Evaluator &evaluator, // So bail out to prevent diagnostics from the contraint system. if (macroRef.getAttr()) { auto foundMacros = TypeChecker::lookupMacros( - dc, macroRef.getMacroName(), SourceLoc(), roles); + dc, macroRef.getMacroName(), roles); if (foundMacros.empty()) return ConcreteDeclRef(); } diff --git a/lib/Sema/TypeChecker.h b/lib/Sema/TypeChecker.h index 4cba8b17db863..ae1a548050102 100644 --- a/lib/Sema/TypeChecker.h +++ b/lib/Sema/TypeChecker.h @@ -940,8 +940,7 @@ PrecedenceGroupLookupResult lookupPrecedenceGroup(DeclContext *dc, Identifier name, SourceLoc nameLoc); SmallVector -lookupMacros(DeclContext *dc, DeclNameRef macroName, SourceLoc loc, - MacroRoles contexts); +lookupMacros(DeclContext *dc, DeclNameRef macroName, MacroRoles contexts); enum class UnsupportedMemberTypeAccessKind : uint8_t { None, From cd752cca225174fd8459986273c172fc0c86d2af Mon Sep 17 00:00:00 2001 From: Holly Borla Date: Sat, 10 Jun 2023 01:38:30 -0700 Subject: [PATCH 07/37] [NameLookup] Plumb source location arguments through all name lookup APIs. This source location will be used to determine whether to add a name lookup option to exclude macro expansions when the name lookup request is constructed. Currently, the source location argument is unused. --- include/swift/AST/Decl.h | 5 +- include/swift/AST/DeclContext.h | 7 ++- include/swift/AST/ModuleNameLookup.h | 2 +- include/swift/AST/NameLookupRequests.h | 8 +-- include/swift/Sema/ConstraintSystem.h | 3 +- lib/AST/ASTContext.cpp | 7 ++- lib/AST/Decl.cpp | 8 +-- lib/AST/DocComment.cpp | 3 +- lib/AST/ModuleNameLookup.cpp | 4 +- lib/AST/NameLookup.cpp | 61 ++++++++++++------- lib/AST/NameLookupRequests.cpp | 23 ++++--- lib/AST/RequirementMachine/NameLookup.cpp | 2 +- lib/AST/UnqualifiedLookup.cpp | 6 +- lib/ClangImporter/ImportDecl.cpp | 7 ++- lib/Frontend/ModuleInterfaceSupport.cpp | 2 +- lib/IDE/ExprContextAnalysis.cpp | 9 ++- lib/SIL/IR/SILFunctionType.cpp | 2 +- lib/SILGen/SILGen.cpp | 2 +- lib/SILGen/SILGenFunction.cpp | 2 +- lib/Sema/BuilderTransform.cpp | 1 + lib/Sema/CSDiagnostics.cpp | 3 +- lib/Sema/CSSimplify.cpp | 17 ++++-- lib/Sema/CodeSynthesis.cpp | 1 + lib/Sema/ConstraintSystem.cpp | 6 +- lib/Sema/ImportResolution.cpp | 2 +- lib/Sema/LookupVisibleDecls.cpp | 1 + lib/Sema/MiscDiagnostics.cpp | 3 +- lib/Sema/PreCheckExpr.cpp | 3 +- lib/Sema/TypeCheckAttr.cpp | 14 +++-- lib/Sema/TypeCheckCodeCompletion.cpp | 3 +- lib/Sema/TypeCheckConcurrency.cpp | 3 +- lib/Sema/TypeCheckDecl.cpp | 2 +- lib/Sema/TypeCheckDeclOverride.cpp | 2 +- lib/Sema/TypeCheckDeclPrimary.cpp | 1 + lib/Sema/TypeCheckNameLookup.cpp | 6 +- lib/Sema/TypeCheckPattern.cpp | 2 +- lib/Sema/TypeCheckPropertyWrapper.cpp | 5 +- lib/Sema/TypeCheckProtocol.cpp | 14 +++-- lib/Sema/TypeCheckProtocolInference.cpp | 1 + lib/Sema/TypeCheckStmt.cpp | 1 + lib/Sema/TypeCheckStorage.cpp | 4 +- lib/Sema/TypeCheckType.cpp | 9 +-- lib/Sema/TypeChecker.h | 2 + lib/Serialization/Deserialization.cpp | 4 +- lib/Serialization/ModuleFile.cpp | 2 +- .../lib/SwiftLang/SwiftSourceDocInfo.cpp | 4 +- 46 files changed, 174 insertions(+), 105 deletions(-) diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index b6b2d8396a46f..8de237d91cd67 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -3899,7 +3899,7 @@ class NominalTypeDecl : public GenericTypeDecl, public IterableDeclContext { /// protocols to which the nominal type conforms. Furthermore, the resulting /// set of declarations has not been filtered for visibility, nor have /// overridden declarations been removed. - TinyPtrVector lookupDirect(DeclName name, + TinyPtrVector lookupDirect(DeclName name, SourceLoc loc = SourceLoc(), OptionSet flags = OptionSet()); @@ -4454,7 +4454,8 @@ class ClassDecl final : public NominalTypeDecl { // Force loading all the members, which will add this attribute if any of // members are determined to be missing while loading. auto mutableThis = const_cast(this); - (void)mutableThis->lookupDirect(DeclBaseName::createConstructor()); + (void)mutableThis->lookupDirect(DeclBaseName::createConstructor(), + getStartLoc()); } if (Bits.ClassDecl.ComputedHasMissingDesignatedInitializers) diff --git a/include/swift/AST/DeclContext.h b/include/swift/AST/DeclContext.h index d6e21e3167959..8de5bd8494950 100644 --- a/include/swift/AST/DeclContext.h +++ b/include/swift/AST/DeclContext.h @@ -598,7 +598,8 @@ class alignas(1 << DeclContextAlignInBits) DeclContext /// lookup. /// /// \returns true if anything was found. - bool lookupQualified(Type type, DeclNameRef member, NLOptions options, + bool lookupQualified(Type type, DeclNameRef member, + SourceLoc loc, NLOptions options, SmallVectorImpl &decls) const; /// Look for the set of declarations with the given name within the @@ -616,12 +617,12 @@ class alignas(1 << DeclContextAlignInBits) DeclContext /// /// \returns true if anything was found. bool lookupQualified(ArrayRef types, DeclNameRef member, - NLOptions options, + SourceLoc loc, NLOptions options, SmallVectorImpl &decls) const; /// Perform qualified lookup for the given member in the given module. bool lookupQualified(ModuleDecl *module, DeclNameRef member, - NLOptions options, + SourceLoc loc, NLOptions options, SmallVectorImpl &decls) const; /// Look up all Objective-C methods with the given selector visible diff --git a/include/swift/AST/ModuleNameLookup.h b/include/swift/AST/ModuleNameLookup.h index bb09a801f3d66..18283f44dd518 100644 --- a/include/swift/AST/ModuleNameLookup.h +++ b/include/swift/AST/ModuleNameLookup.h @@ -62,7 +62,7 @@ void lookupInModule(const DeclContext *moduleOrFile, DeclName name, SmallVectorImpl &decls, NLKind lookupKind, ResolutionKind resolutionKind, const DeclContext *moduleScopeContext, - NLOptions options); + SourceLoc loc, NLOptions options); /// Performs a qualified lookup into the given module and, if necessary, its /// reexports, observing proper shadowing rules. diff --git a/include/swift/AST/NameLookupRequests.h b/include/swift/AST/NameLookupRequests.h index 39fe9d7dc2a3b..7aa1c47ee83a5 100644 --- a/include/swift/AST/NameLookupRequests.h +++ b/include/swift/AST/NameLookupRequests.h @@ -461,7 +461,7 @@ class LookupInModuleRequest LookupInModuleRequest( const DeclContext *, DeclName, NLKind, namelookup::ResolutionKind, const DeclContext *, - NLOptions); + SourceLoc, NLOptions); private: friend SimpleRequest; @@ -511,7 +511,7 @@ class ModuleQualifiedLookupRequest public: ModuleQualifiedLookupRequest(const DeclContext *, ModuleDecl *, DeclNameRef, - NLOptions); + SourceLoc, NLOptions); private: friend SimpleRequest; @@ -537,7 +537,7 @@ class QualifiedLookupRequest public: QualifiedLookupRequest(const DeclContext *, SmallVector, - DeclNameRef, NLOptions); + DeclNameRef, SourceLoc, NLOptions); private: friend SimpleRequest; @@ -588,7 +588,7 @@ class DirectLookupRequest TinyPtrVector(DirectLookupDescriptor), RequestFlags::Uncached|RequestFlags::DependencySink> { public: - DirectLookupRequest(DirectLookupDescriptor); + DirectLookupRequest(DirectLookupDescriptor, SourceLoc); private: friend SimpleRequest; diff --git a/include/swift/Sema/ConstraintSystem.h b/include/swift/Sema/ConstraintSystem.h index 6d6bb23a2712c..e003098aa03ab 100644 --- a/include/swift/Sema/ConstraintSystem.h +++ b/include/swift/Sema/ConstraintSystem.h @@ -2910,7 +2910,8 @@ class ConstraintSystem { /// and no new names are introduced after that point. /// /// \returns A reference to the member-lookup result. - LookupResult &lookupMember(Type base, DeclNameRef name); + LookupResult &lookupMember(Type base, DeclNameRef name, + SourceLoc loc); /// Retrieve the set of "alternative" literal types that we'll explore /// for a given literal protocol kind. diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 00bd291f3a025..93c8f0f0959e4 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -1072,8 +1072,8 @@ DECLTYPE *ASTContext::get##NAME##Decl() const { \ /* Note: lookupQualified() will search both the Swift overlay \ * and the Clang module it imports. */ \ SmallVector decls; \ - M->lookupQualified(M, DeclNameRef(getIdentifier(#NAME)), NL_OnlyTypes, \ - decls); \ + M->lookupQualified(M, DeclNameRef(getIdentifier(#NAME)), SourceLoc(), \ + NL_OnlyTypes, decls); \ if (decls.size() == 1 && isa(decls[0])) { \ auto decl = cast(decls[0]); \ if (isa(decl) \ @@ -1336,7 +1336,8 @@ ConcreteDeclRef ASTContext::getRegexInitDecl(Type regexType) const { {Id_regexString, Id_version}); SmallVector results; spModule->lookupQualified(getRegexType(), DeclNameRef(name), - NL_IncludeUsableFromInline, results); + SourceLoc(), NL_IncludeUsableFromInline, + results); assert(results.size() == 1); auto *foundDecl = cast(results[0]); auto subs = regexType->getMemberSubstitutionMap(spModule, foundDecl); diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 14d6a9c2849fe..eb62453ce060b 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -5395,7 +5395,7 @@ NominalTypeDecl::getExecutorOwnedEnqueueFunction() const { llvm::SmallVector results; lookupQualified(getSelfNominalTypeDecl(), DeclNameRef(C.Id_enqueue), - NL_ProtocolMembers, + getLoc(), NL_ProtocolMembers, results); for (auto candidate: results) { @@ -5434,7 +5434,7 @@ NominalTypeDecl::getExecutorLegacyOwnedEnqueueFunction() const { llvm::SmallVector results; lookupQualified(getSelfNominalTypeDecl(), DeclNameRef(C.Id_enqueue), - NL_ProtocolMembers, + getLoc(), NL_ProtocolMembers, results); for (auto candidate: results) { @@ -5473,7 +5473,7 @@ NominalTypeDecl::getExecutorLegacyUnownedEnqueueFunction() const { llvm::SmallVector results; lookupQualified(getSelfNominalTypeDecl(), DeclNameRef(C.Id_enqueue), - NL_ProtocolMembers, + getLoc(), NL_ProtocolMembers, results); for (auto candidate: results) { @@ -9927,7 +9927,7 @@ const VarDecl *ClassDecl::getUnownedExecutorProperty() const { llvm::SmallVector results; this->lookupQualified(getSelfNominalTypeDecl(), DeclNameRef(C.Id_unownedExecutor), - NL_ProtocolMembers, + getLoc(), NL_ProtocolMembers, results); for (auto candidate: results) { diff --git a/lib/AST/DocComment.cpp b/lib/AST/DocComment.cpp index 96bf365ef8745..5c73b29a42959 100644 --- a/lib/AST/DocComment.cpp +++ b/lib/AST/DocComment.cpp @@ -435,7 +435,8 @@ class CommentProviderFinder final { SmallVector members; protocol->lookupQualified(const_cast(protocol), DeclNameRef(VD->getName()), - NLOptions::NL_ProtocolMembers, members); + VD->getLoc(), NLOptions::NL_ProtocolMembers, + members); Optional result; for (auto *member : members) { diff --git a/lib/AST/ModuleNameLookup.cpp b/lib/AST/ModuleNameLookup.cpp index 10ea32c053c17..98ae1381690ce 100644 --- a/lib/AST/ModuleNameLookup.cpp +++ b/lib/AST/ModuleNameLookup.cpp @@ -281,10 +281,10 @@ void namelookup::lookupInModule(const DeclContext *moduleOrFile, NLKind lookupKind, ResolutionKind resolutionKind, const DeclContext *moduleScopeContext, - NLOptions options) { + SourceLoc loc, NLOptions options) { auto &ctx = moduleOrFile->getASTContext(); LookupInModuleRequest req(moduleOrFile, name, lookupKind, resolutionKind, - moduleScopeContext, options); + moduleScopeContext, loc, options); auto results = evaluateOrDefault(ctx.evaluator, req, {}); decls.append(results.begin(), results.end()); } diff --git a/lib/AST/NameLookup.cpp b/lib/AST/NameLookup.cpp index 77e029d8e3199..66c3bd8a97657 100644 --- a/lib/AST/NameLookup.cpp +++ b/lib/AST/NameLookup.cpp @@ -1851,10 +1851,10 @@ maybeFilterOutUnwantedDecls(TinyPtrVector decls, } TinyPtrVector -NominalTypeDecl::lookupDirect(DeclName name, +NominalTypeDecl::lookupDirect(DeclName name, SourceLoc loc, OptionSet flags) { return evaluateOrDefault(getASTContext().evaluator, - DirectLookupRequest({this, name, flags}), {}); + DirectLookupRequest({this, name, flags}, loc), {}); } TinyPtrVector @@ -2195,6 +2195,7 @@ void namelookup::tryExtractDirectlyReferencedNominalTypes( bool DeclContext::lookupQualified(Type type, DeclNameRef member, + SourceLoc loc, NLOptions options, SmallVectorImpl &decls) const { using namespace namelookup; @@ -2209,14 +2210,16 @@ bool DeclContext::lookupQualified(Type type, // Handle lookup in a module. if (auto moduleTy = type->getAs()) - return lookupQualified(moduleTy->getModule(), member, options, decls); + return lookupQualified(moduleTy->getModule(), member, + loc, options, decls); // Figure out which nominal types we will look into. SmallVector nominalTypesToLookInto; namelookup::extractDirectlyReferencedNominalTypes(type, nominalTypesToLookInto); - return lookupQualified(nominalTypesToLookInto, member, options, decls); + return lookupQualified(nominalTypesToLookInto, member, + loc, options, decls); } static void installPropertyWrapperMembersIfNeeded(NominalTypeDecl *target, @@ -2251,11 +2254,11 @@ static void installPropertyWrapperMembersIfNeeded(NominalTypeDecl *target, bool DeclContext::lookupQualified(ArrayRef typeDecls, DeclNameRef member, - NLOptions options, + SourceLoc loc, NLOptions options, SmallVectorImpl &decls) const { assert(decls.empty() && "additive lookup not supported"); QualifiedLookupRequest req{this, {typeDecls.begin(), typeDecls.end()}, - member, options}; + member, loc, options}; decls = evaluateOrDefault(getASTContext().evaluator, req, {}); return !decls.empty(); } @@ -2309,7 +2312,11 @@ QualifiedLookupRequest::evaluate(Evaluator &eval, const DeclContext *DC, flags |= NominalTypeDecl::LookupDirectFlags::IncludeAttrImplements; if (options & NL_ExcludeMacroExpansions) flags |= NominalTypeDecl::LookupDirectFlags::ExcludeMacroExpansions; - for (auto decl : current->lookupDirect(member.getFullName(), flags)) { + + // Note that the source loc argument doesn't matter, because excluding + // macro expansions is already propagated through the lookup flags above. + for (auto decl : current->lookupDirect(member.getFullName(), + SourceLoc(), flags)) { // If we're performing a type lookup, don't even attempt to validate // the decl if its not a type. if ((options & NL_OnlyTypes) && !isa(decl)) @@ -2383,10 +2390,10 @@ QualifiedLookupRequest::evaluate(Evaluator &eval, const DeclContext *DC, } bool DeclContext::lookupQualified(ModuleDecl *module, DeclNameRef member, - NLOptions options, + SourceLoc loc, NLOptions options, SmallVectorImpl &decls) const { assert(decls.empty() && "additive lookup not supported"); - ModuleQualifiedLookupRequest req{this, module, member, options}; + ModuleQualifiedLookupRequest req{this, module, member, loc, options}; decls = evaluateOrDefault(getASTContext().evaluator, req, {}); return !decls.empty(); } @@ -2404,7 +2411,7 @@ ModuleQualifiedLookupRequest::evaluate(Evaluator &eval, const DeclContext *DC, auto topLevelScope = DC->getModuleScopeContext(); if (module == topLevelScope->getParentModule()) { lookupInModule(module, member.getFullName(), decls, NLKind::QualifiedLookup, - kind, topLevelScope, options); + kind, topLevelScope, SourceLoc(), options); } else { // Note: This is a lookup into another module. Unless we're compiling // multiple modules at once, or if the other module re-exports this one, @@ -2421,7 +2428,7 @@ ModuleQualifiedLookupRequest::evaluate(Evaluator &eval, const DeclContext *DC, })) { lookupInModule(module, member.getFullName(), decls, NLKind::QualifiedLookup, kind, topLevelScope, - options); + SourceLoc(), options); } } @@ -2613,6 +2620,20 @@ directReferencesForUnqualifiedTypeLookup(DeclNameRef name, SourceLoc loc, DeclContext *dc, LookupOuterResults lookupOuter, bool allowUsableFromInline=false) { + UnqualifiedLookupOptions options = + UnqualifiedLookupFlags::TypeLookup | + UnqualifiedLookupFlags::AllowProtocolMembers; + if (lookupOuter == LookupOuterResults::Included) + options |= UnqualifiedLookupFlags::IncludeOuterResults; + + if (allowUsableFromInline) + options |= UnqualifiedLookupFlags::IncludeUsableFromInline; + + // Manually exclude macro expansions here since the source location + // is overridden below. + if (ASTScope::isInMacroArgument(dc->getParentSourceFile(), loc)) + options |= UnqualifiedLookupFlags::ExcludeMacroExpansions; + // In a protocol or protocol extension, the 'where' clause can refer to // associated types without 'Self' qualification: // @@ -2640,15 +2661,6 @@ directReferencesForUnqualifiedTypeLookup(DeclNameRef name, DirectlyReferencedTypeDecls results; - UnqualifiedLookupOptions options = - UnqualifiedLookupFlags::TypeLookup | - UnqualifiedLookupFlags::AllowProtocolMembers; - if (lookupOuter == LookupOuterResults::Included) - options |= UnqualifiedLookupFlags::IncludeOuterResults; - - if (allowUsableFromInline) - options |= UnqualifiedLookupFlags::IncludeUsableFromInline; - auto &ctx = dc->getASTContext(); auto descriptor = UnqualifiedLookupDescriptor(name, dc, loc, options); auto lookup = evaluateOrDefault(ctx.evaluator, @@ -2679,6 +2691,7 @@ directReferencesForQualifiedTypeLookup(Evaluator &evaluator, ArrayRef baseTypes, DeclNameRef name, DeclContext *dc, + SourceLoc loc, bool allowUsableFromInline=false) { DirectlyReferencedTypeDecls result; auto addResults = [&result](ArrayRef found){ @@ -2705,7 +2718,7 @@ directReferencesForQualifiedTypeLookup(Evaluator &evaluator, resolveTypeDeclsToNominal(ctx.evaluator, ctx, baseTypes, moduleDecls, anyObject); - dc->lookupQualified(nominalTypeDecls, name, options, members); + dc->lookupQualified(nominalTypeDecls, name, loc, options, members); // Search all of the modules. for (auto module : moduleDecls) { @@ -2713,7 +2726,7 @@ directReferencesForQualifiedTypeLookup(Evaluator &evaluator, innerOptions &= ~NL_RemoveOverridden; innerOptions &= ~NL_RemoveNonVisible; SmallVector moduleMembers; - dc->lookupQualified(module, name, innerOptions, moduleMembers); + dc->lookupQualified(module, name, loc, innerOptions, moduleMembers); members.append(moduleMembers.begin(), moduleMembers.end()); } @@ -2765,6 +2778,7 @@ directReferencesForDeclRefTypeRepr(Evaluator &evaluator, ASTContext &ctx, current = directReferencesForQualifiedTypeLookup(evaluator, ctx, current, component->getNameRef(), dc, + component->getLoc(), allowUsableFromInline); if (current.empty()) return current; @@ -3552,7 +3566,8 @@ bool IsCallAsFunctionNominalRequest::evaluate(Evaluator &evaluator, // member access. SmallVector results; auto opts = NL_QualifiedDefault | NL_ProtocolMembers | NL_IgnoreAccessControl; - dc->lookupQualified(decl, DeclNameRef(ctx.Id_callAsFunction), opts, results); + dc->lookupQualified(decl, DeclNameRef(ctx.Id_callAsFunction), + decl->getLoc(), opts, results); return llvm::any_of(results, [](ValueDecl *decl) -> bool { if (auto *fd = dyn_cast(decl)) diff --git a/lib/AST/NameLookupRequests.cpp b/lib/AST/NameLookupRequests.cpp index 617db015e9040..2376d38928e2c 100644 --- a/lib/AST/NameLookupRequests.cpp +++ b/lib/AST/NameLookupRequests.cpp @@ -555,7 +555,7 @@ static UnqualifiedLookupDescriptor excludeMacrosIfNeeded( /// Exclude macros in the direct lookup descriptor if we need to. static DirectLookupDescriptor excludeMacrosIfNeeded( - DirectLookupDescriptor descriptor) { + DirectLookupDescriptor descriptor, SourceLoc loc) { if (descriptor.Options.contains( NominalTypeDecl::LookupDirectFlags::ExcludeMacroExpansions)) return descriptor; @@ -572,7 +572,8 @@ static DirectLookupDescriptor excludeMacrosIfNeeded( /// Exclude macros in the name lookup options if we need to. static NLOptions -excludeMacrosIfNeeded(const DeclContext *dc, NLOptions options) { +excludeMacrosIfNeeded(const DeclContext *dc, SourceLoc loc, + NLOptions options) { if (options & NL_ExcludeMacroExpansions) return options; @@ -591,25 +592,27 @@ LookupInModuleRequest::LookupInModuleRequest( const DeclContext *moduleOrFile, DeclName name, NLKind lookupKind, namelookup::ResolutionKind resolutionKind, const DeclContext *moduleScopeContext, - NLOptions options + SourceLoc loc, NLOptions options ) : SimpleRequest(moduleOrFile, name, lookupKind, resolutionKind, moduleScopeContext, - excludeMacrosIfNeeded(moduleOrFile, options)) { } + excludeMacrosIfNeeded(moduleOrFile, loc, options)) { } ModuleQualifiedLookupRequest::ModuleQualifiedLookupRequest( const DeclContext *dc, ModuleDecl *module, DeclNameRef name, - NLOptions options - ) : SimpleRequest(dc, module, name, excludeMacrosIfNeeded(dc, options)) { } + SourceLoc loc, NLOptions options + ) : SimpleRequest(dc, module, name, + excludeMacrosIfNeeded(dc, loc, options)) { } QualifiedLookupRequest::QualifiedLookupRequest( const DeclContext *dc, SmallVector decls, - DeclNameRef name, NLOptions options + DeclNameRef name, + SourceLoc loc, NLOptions options ) : SimpleRequest(dc, std::move(decls), name, - excludeMacrosIfNeeded(dc, options)) { } + excludeMacrosIfNeeded(dc, loc, options)) { } -DirectLookupRequest::DirectLookupRequest(DirectLookupDescriptor descriptor) - : SimpleRequest(excludeMacrosIfNeeded(descriptor)) { } +DirectLookupRequest::DirectLookupRequest(DirectLookupDescriptor descriptor, SourceLoc loc) + : SimpleRequest(excludeMacrosIfNeeded(descriptor, loc)) { } // Implement the clang importer type zone. #define SWIFT_TYPEID_ZONE ClangImporter diff --git a/lib/AST/RequirementMachine/NameLookup.cpp b/lib/AST/RequirementMachine/NameLookup.cpp index ddb218353a656..6a9e83421f37e 100644 --- a/lib/AST/RequirementMachine/NameLookup.cpp +++ b/lib/AST/RequirementMachine/NameLookup.cpp @@ -48,7 +48,7 @@ swift::rewriting::lookupConcreteNestedType( SmallVectorImpl &concreteDecls) { SmallVector foundMembers; decl->getParentModule()->lookupQualified( - decl, DeclNameRef(name), + decl, DeclNameRef(name), decl->getLoc(), NL_QualifiedDefault | NL_OnlyTypes | NL_ProtocolMembers, foundMembers); for (auto member : foundMembers) diff --git a/lib/AST/UnqualifiedLookup.cpp b/lib/AST/UnqualifiedLookup.cpp index b48b4abcadc15..6651bbea3322a 100644 --- a/lib/AST/UnqualifiedLookup.cpp +++ b/lib/AST/UnqualifiedLookup.cpp @@ -333,7 +333,8 @@ void UnqualifiedLookupFactory::ResultFinderForTypeContext::findResults( return; SmallVector Lookup; - contextForLookup->lookupQualified(selfBounds, Name, baseNLOptions, Lookup); + contextForLookup->lookupQualified(selfBounds, Name, factory->Loc, + baseNLOptions, Lookup); for (auto Result : Lookup) { auto baseDC = const_cast(whereValueIsMember(Result)); auto baseDecl = getBaseDeclForResult(baseDC); @@ -531,7 +532,8 @@ void UnqualifiedLookupFactory::addImportedResults(const DeclContext *const dc) { if (options.contains(Flags::ExcludeMacroExpansions)) nlOptions |= NL_ExcludeMacroExpansions; lookupInModule(dc, Name.getFullName(), CurModuleResults, - NLKind::UnqualifiedLookup, resolutionKind, dc, nlOptions); + NLKind::UnqualifiedLookup, resolutionKind, dc, + Loc, nlOptions); // Always perform name shadowing for type lookup. if (options.contains(Flags::TypeLookup)) { diff --git a/lib/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp index d7d3527a6c7a0..88d2a9a93dd3e 100644 --- a/lib/ClangImporter/ImportDecl.cpp +++ b/lib/ClangImporter/ImportDecl.cpp @@ -6532,7 +6532,7 @@ void SwiftDeclConverter::recordObjCOverride(AbstractFunctionDecl *decl) { // Dig out the Objective-C superclass. SmallVector results; superDecl->lookupQualified(superDecl, DeclNameRef(decl->getName()), - NL_QualifiedDefault, + decl->getLoc(), NL_QualifiedDefault, results); for (auto member : results) { if (member->getKind() != decl->getKind() || @@ -6605,7 +6605,7 @@ void SwiftDeclConverter::recordObjCOverride(SubscriptDecl *subscript) { SmallVector lookup; subscript->getModuleContext()->lookupQualified( superDecl, DeclNameRef(subscript->getName()), - NL_QualifiedDefault, lookup); + subscript->getLoc(), NL_QualifiedDefault, lookup); for (auto result : lookup) { auto parentSub = dyn_cast(result); @@ -8292,7 +8292,8 @@ static void finishTypeWitnesses( NL_OnlyTypes | NL_ProtocolMembers); - dc->lookupQualified(nominal, DeclNameRef(assocType->getName()), options, + dc->lookupQualified(nominal, DeclNameRef(assocType->getName()), + nominal->getLoc(), options, lookupResults); for (auto member : lookupResults) { auto typeDecl = cast(member); diff --git a/lib/Frontend/ModuleInterfaceSupport.cpp b/lib/Frontend/ModuleInterfaceSupport.cpp index ee08b89e508c3..3a01ee45af93c 100644 --- a/lib/Frontend/ModuleInterfaceSupport.cpp +++ b/lib/Frontend/ModuleInterfaceSupport.cpp @@ -181,7 +181,7 @@ diagnoseIfModuleImportsShadowingDecl(ModuleInterfaceOptions const &Opts, SmallVector decls; lookupInModule(importedModule, importingModule->getName(), decls, NLKind::UnqualifiedLookup, ResolutionKind::TypesOnly, - importedModule, + importedModule, SourceLoc(), NL_UnqualifiedDefault | NL_IncludeUsableFromInline); for (auto decl : decls) diagnoseDeclShadowsModule(Opts, cast(decl), importingModule, diff --git a/lib/IDE/ExprContextAnalysis.cpp b/lib/IDE/ExprContextAnalysis.cpp index 2aac61940a841..565be3e8d24c4 100644 --- a/lib/IDE/ExprContextAnalysis.cpp +++ b/lib/IDE/ExprContextAnalysis.cpp @@ -372,7 +372,7 @@ class ExprParentFinder : public ASTWalker { /// Collect function (or subscript) members with the given \p name on \p baseTy. static void collectPossibleCalleesByQualifiedLookup( - DeclContext &DC, Type baseTy, DeclNameRef name, + DeclContext &DC, Type baseTy, DeclNameRef name, SourceLoc loc, SmallVectorImpl &candidates) { auto baseInstanceTy = baseTy->getMetatypeInstanceType(); if (!baseInstanceTy->mayHaveMembers()) @@ -395,7 +395,7 @@ static void collectPossibleCalleesByQualifiedLookup( SmallVector decls; if (!DC.lookupQualified(baseInstanceTy, - name.withoutArgumentLabels(), + name.withoutArgumentLabels(), loc, NL_QualifiedDefault | NL_ProtocolMembers, decls)) return; @@ -522,7 +522,9 @@ static void collectPossibleCalleesByQualifiedLookup( } } - collectPossibleCalleesByQualifiedLookup(DC, baseTy, name, candidates); + collectPossibleCalleesByQualifiedLookup(DC, baseTy, name, + baseExpr->getLoc(), + candidates); // Add virtual 'subscript(keyPath: KeyPath) -> Value'. if (name.getBaseName() == DeclBaseName::createSubscript() && @@ -553,6 +555,7 @@ static bool collectPossibleCalleesForUnresolvedMember( return; collectPossibleCalleesByQualifiedLookup(DC, MetatypeType::get(expectedTy), unresolvedMemberExpr->getName(), + unresolvedMemberExpr->getLoc(), candidates); }; diff --git a/lib/SIL/IR/SILFunctionType.cpp b/lib/SIL/IR/SILFunctionType.cpp index 4afc45feb516f..cfe743ad3c3ec 100644 --- a/lib/SIL/IR/SILFunctionType.cpp +++ b/lib/SIL/IR/SILFunctionType.cpp @@ -1058,7 +1058,7 @@ static CanType getKnownType(Optional &cacheSlot, ASTContext &C, // themselves. SmallVector decls; mod->lookupQualified(mod, DeclNameRef(C.getIdentifier(typeName)), - NL_QualifiedDefault, decls); + SourceLoc(), NL_QualifiedDefault, decls); if (decls.size() != 1) return CanType(); diff --git a/lib/SILGen/SILGen.cpp b/lib/SILGen/SILGen.cpp index 996d654321465..c70a797ceadc9 100644 --- a/lib/SILGen/SILGen.cpp +++ b/lib/SILGen/SILGen.cpp @@ -371,7 +371,7 @@ static FuncDecl *lookupIntrinsic(ModuleDecl &module, return *cache; SmallVector decls; - module.lookupQualified(&module, DeclNameRef(name), + module.lookupQualified(&module, DeclNameRef(name), SourceLoc(), NL_QualifiedDefault | NL_IncludeUsableFromInline, decls); if (decls.size() != 1) { diff --git a/lib/SILGen/SILGenFunction.cpp b/lib/SILGen/SILGenFunction.cpp index 6c04a9f890a5e..90d3014bd6109 100644 --- a/lib/SILGen/SILGenFunction.cpp +++ b/lib/SILGen/SILGenFunction.cpp @@ -1092,7 +1092,7 @@ void SILGenFunction::emitArtificialTopLevel(Decl *mainDecl) { SmallVector results; UIKit->lookupQualified(UIKit, DeclNameRef(ctx.getIdentifier("UIApplicationMain")), - NL_QualifiedDefault, + SourceLoc(), NL_QualifiedDefault, results); // As the comment above alludes, using a qualified lookup into UIKit is diff --git a/lib/Sema/BuilderTransform.cpp b/lib/Sema/BuilderTransform.cpp index b6ae98679227c..78a9739cd694e 100644 --- a/lib/Sema/BuilderTransform.cpp +++ b/lib/Sema/BuilderTransform.cpp @@ -1379,6 +1379,7 @@ ResultBuilderOpSupport TypeChecker::checkBuilderOpSupport( SmallVector foundDecls; dc->lookupQualified( builderType, DeclNameRef(fnName), + builderType->getAnyNominal()->getLoc(), NL_QualifiedDefault | NL_ProtocolMembers, foundDecls); for (auto decl : foundDecls) { if (auto func = dyn_cast(decl)) { diff --git a/lib/Sema/CSDiagnostics.cpp b/lib/Sema/CSDiagnostics.cpp index c2ed909db3352..196217cb62aac 100644 --- a/lib/Sema/CSDiagnostics.cpp +++ b/lib/Sema/CSDiagnostics.cpp @@ -2104,7 +2104,8 @@ bool AssignmentFailure::diagnoseAsError() { if (auto typeContext = DC->getInnermostTypeContext()) { SmallVector results; DC->lookupQualified(typeContext->getSelfNominalTypeDecl(), - VD->createNameRef(), NL_QualifiedDefault, results); + VD->createNameRef(), Loc, + NL_QualifiedDefault, results); auto foundProperty = llvm::find_if(results, [&](ValueDecl *decl) { // We're looking for a settable property that is the same type as the diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index da48e9cd8286a..77d02761259a9 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -9307,6 +9307,9 @@ performMemberLookup(ConstraintKind constraintKind, DeclNameRef memberName, Type baseObjTy = baseTy->getRValueType(); Type instanceTy = baseObjTy; + auto memberNode = simplifyLocatorToAnchor(memberLocator); + auto memberLoc = memberNode ? memberNode.getStartLoc() : SourceLoc(); + if (auto baseObjMeta = baseObjTy->getAs()) { instanceTy = baseObjMeta->getInstanceType(); } @@ -9419,7 +9422,7 @@ performMemberLookup(ConstraintKind constraintKind, DeclNameRef memberName, } // Look for members within the base. - LookupResult &lookup = lookupMember(instanceTy, lookupName); + LookupResult &lookup = lookupMember(instanceTy, lookupName, memberLoc); // If this is true, we're using type construction syntax (Foo()) rather // than an explicit call to `init` (Foo.init()). @@ -9819,7 +9822,8 @@ performMemberLookup(ConstraintKind constraintKind, DeclNameRef memberName, memberName.getBaseName() == DeclBaseName::createConstructor() && !isImplicitInit) { auto &compatLookup = lookupMember(instanceTy, - DeclNameRef(ctx.getIdentifier("init"))); + DeclNameRef(ctx.getIdentifier("init")), + memberLoc); for (auto result : compatLookup) addChoice(getOverloadChoice(result.getValueDecl(), /*isBridged=*/false, @@ -9829,7 +9833,8 @@ performMemberLookup(ConstraintKind constraintKind, DeclNameRef memberName, // If the instance type is a bridged to an Objective-C type, perform // a lookup into that Objective-C type. if (bridgedType) { - LookupResult &bridgedLookup = lookupMember(bridgedType, memberName); + LookupResult &bridgedLookup = lookupMember(bridgedType, memberName, + memberLoc); ModuleDecl *foundationModule = nullptr; for (auto result : bridgedLookup) { // Ignore results from the Objective-C "Foundation" @@ -9892,7 +9897,8 @@ performMemberLookup(ConstraintKind constraintKind, DeclNameRef memberName, // prioritize them and mark any results found on wrapped type // as a fallback results. bool isFallback = !result.ViableCandidates.empty(); - LookupResult &optionalLookup = lookupMember(objectType, memberName); + LookupResult &optionalLookup = lookupMember(objectType, memberName, + memberLoc); for (auto result : optionalLookup) addChoice(getOverloadChoice(result.getValueDecl(), /*bridged*/ false, @@ -9960,7 +9966,8 @@ performMemberLookup(ConstraintKind constraintKind, DeclNameRef memberName, lookupOptions |= NameLookupFlags::IgnoreAccessControl; auto lookup = - TypeChecker::lookupMember(DC, instanceTy, memberName, lookupOptions); + TypeChecker::lookupMember(DC, instanceTy, memberName, + memberLoc, lookupOptions); for (auto entry : lookup) { auto *cand = entry.getValueDecl(); diff --git a/lib/Sema/CodeSynthesis.cpp b/lib/Sema/CodeSynthesis.cpp index 26e6a088d0cea..30bf38a0771f4 100644 --- a/lib/Sema/CodeSynthesis.cpp +++ b/lib/Sema/CodeSynthesis.cpp @@ -1014,6 +1014,7 @@ static void collectNonOveriddenSuperclassInits( SmallVector lookupResults; subclass->lookupQualified( superclassDecl, DeclNameRef::createConstructor(), + subclass->getStartLoc(), subOptions, lookupResults); for (auto decl : lookupResults) { diff --git a/lib/Sema/ConstraintSystem.cpp b/lib/Sema/ConstraintSystem.cpp index 10563c1fe10f8..632c9ef72690b 100644 --- a/lib/Sema/ConstraintSystem.cpp +++ b/lib/Sema/ConstraintSystem.cpp @@ -279,13 +279,15 @@ getDynamicResultSignature(ValueDecl *decl) { llvm_unreachable("Not a valid @objc member"); } -LookupResult &ConstraintSystem::lookupMember(Type base, DeclNameRef name) { +LookupResult &ConstraintSystem::lookupMember(Type base, DeclNameRef name, + SourceLoc loc) { // Check whether we've already performed this lookup. auto &result = MemberLookups[{base, name}]; if (result) return *result; // Lookup the member. - result = TypeChecker::lookupMember(DC, base, name, defaultMemberLookupOptions); + result = TypeChecker::lookupMember(DC, base, name, loc, + defaultMemberLookupOptions); // If we aren't performing dynamic lookup, we're done. if (!*result || !base->isAnyObject()) diff --git a/lib/Sema/ImportResolution.cpp b/lib/Sema/ImportResolution.cpp index 520ae263b6a09..5661c3a20ebc2 100644 --- a/lib/Sema/ImportResolution.cpp +++ b/lib/Sema/ImportResolution.cpp @@ -1135,7 +1135,7 @@ ScopedImportLookupRequest::evaluate(Evaluator &evaluator, lookupInModule(topLevelModule, accessPath.front().Item, decls, NLKind::QualifiedLookup, ResolutionKind::Overloadable, import->getDeclContext()->getModuleScopeContext(), - NL_QualifiedDefault); + import->getLoc(), NL_QualifiedDefault); auto importLoc = import->getLoc(); if (decls.empty()) { diff --git a/lib/Sema/LookupVisibleDecls.cpp b/lib/Sema/LookupVisibleDecls.cpp index c089f6767ad2e..2d723468f1597 100644 --- a/lib/Sema/LookupVisibleDecls.cpp +++ b/lib/Sema/LookupVisibleDecls.cpp @@ -1188,6 +1188,7 @@ static void lookupVisibleDynamicMemberLookupDecls( SmallVector subscripts; dc->lookupQualified(baseType, subscriptName, + baseType->getAnyNominal()->getLoc(), NL_QualifiedDefault | NL_ProtocolMembers, subscripts); for (ValueDecl *VD : subscripts) { diff --git a/lib/Sema/MiscDiagnostics.cpp b/lib/Sema/MiscDiagnostics.cpp index 4b17e5bfb1859..0c144273096c6 100644 --- a/lib/Sema/MiscDiagnostics.cpp +++ b/lib/Sema/MiscDiagnostics.cpp @@ -4332,7 +4332,8 @@ class ObjCSelectorWalker : public ASTWalker { auto nominal = method->getDeclContext()->getSelfNominalTypeDecl(); auto result = TypeChecker::lookupMember( const_cast(DC), nominal->getDeclaredInterfaceType(), - DeclNameRef(lookupName), defaultMemberLookupOptions); + DeclNameRef(lookupName), method->getLoc(), + defaultMemberLookupOptions); // If we didn't find multiple methods, there is no ambiguity. if (result.size() < 2) return false; diff --git a/lib/Sema/PreCheckExpr.cpp b/lib/Sema/PreCheckExpr.cpp index f634cdf72cdaa..e270db6a2e799 100644 --- a/lib/Sema/PreCheckExpr.cpp +++ b/lib/Sema/PreCheckExpr.cpp @@ -1395,7 +1395,7 @@ TypeExpr *PreCheckExpression::simplifyNestedTypeExpr(UnresolvedDotExpr *UDE) { // See if the type has a member type with this name. auto Result = TypeChecker::lookupMemberType( DC, TD->getDeclaredInterfaceType(), Name, - defaultMemberLookupOptions); + UDE->getLoc(), defaultMemberLookupOptions); // If there is no nested type with this name, we have a lookup of // a non-type member, so leave the expression as-is. @@ -1488,6 +1488,7 @@ TypeExpr *PreCheckExpression::simplifyNestedTypeExpr(UnresolvedDotExpr *UDE) { if (BaseTy->mayHaveMembers()) { // See if there is a member type with this name. auto Result = TypeChecker::lookupMemberType(DC, BaseTy, Name, + UDE->getLoc(), defaultMemberLookupOptions); // If there is no nested type with this name, we have a lookup of diff --git a/lib/Sema/TypeCheckAttr.cpp b/lib/Sema/TypeCheckAttr.cpp index ae66572e3f267..9d1d99b2b2114 100644 --- a/lib/Sema/TypeCheckAttr.cpp +++ b/lib/Sema/TypeCheckAttr.cpp @@ -2328,7 +2328,8 @@ void AttributeChecker::checkApplicationMainAttribute(DeclAttribute *attr, namelookup::lookupInModule(KitModule, Id_ApplicationDelegate, decls, NLKind::QualifiedLookup, namelookup::ResolutionKind::TypesOnly, - SF, NL_QualifiedDefault); + SF, attr->getLocation(), + NL_QualifiedDefault); if (decls.size() == 1) ApplicationDelegateProto = dyn_cast(decls[0]); } @@ -3047,7 +3048,8 @@ static void lookupReplacedDecl(DeclNameRef replacedDeclName, options |= NL_IncludeUsableFromInline; if (typeCtx) - moduleScopeCtxt->lookupQualified({typeCtx}, replacedDeclName, options, + moduleScopeCtxt->lookupQualified({typeCtx}, replacedDeclName, + attr->getLocation(), options, results); } @@ -4057,11 +4059,12 @@ void AttributeChecker::visitResultBuilderAttr(ResultBuilderAttr *attr) { auto builderType = nominal->getDeclaredType(); nominal->lookupQualified(builderType, DeclNameRef(buildPartialBlockFirst), - NL_QualifiedDefault, + attr->getLocation(), NL_QualifiedDefault, buildPartialBlockFirstMatches); nominal->lookupQualified( builderType, DeclNameRef(buildPartialBlockAccumulated), - NL_QualifiedDefault, buildPartialBlockAccumulatedMatches); + attr->getLocation(), NL_QualifiedDefault, + buildPartialBlockAccumulatedMatches); hasAccessibleBuildPartialBlockFirst = llvm::any_of( buildPartialBlockFirstMatches, isBuildMethodAsAccessibleAsType); @@ -7267,7 +7270,8 @@ ValueDecl *RenamedDeclRequest::evaluate(Evaluator &evaluator, SmallVector lookupResults; attachedContext->lookupQualified(attachedContext->getParentModule(), nameRef.withoutArgumentLabels(), - NL_OnlyTypes, lookupResults); + attr->getLocation(), NL_OnlyTypes, + lookupResults); if (lookupResults.size() == 1) return lookupResults[0]; return nullptr; diff --git a/lib/Sema/TypeCheckCodeCompletion.cpp b/lib/Sema/TypeCheckCodeCompletion.cpp index 58acb0c1e1965..9076c7b7f7aef 100644 --- a/lib/Sema/TypeCheckCodeCompletion.cpp +++ b/lib/Sema/TypeCheckCodeCompletion.cpp @@ -767,6 +767,7 @@ bool swift::typeCheckExpression(DeclContext *DC, Expr *&parsedExpr) { LookupResult swift::lookupSemanticMember(DeclContext *DC, Type ty, DeclName name) { - return TypeChecker::lookupMember(DC, ty, DeclNameRef(name), None); + return TypeChecker::lookupMember(DC, ty, DeclNameRef(name), + SourceLoc(), None); } diff --git a/lib/Sema/TypeCheckConcurrency.cpp b/lib/Sema/TypeCheckConcurrency.cpp index eb566bcde9a3c..4501c282578be 100644 --- a/lib/Sema/TypeCheckConcurrency.cpp +++ b/lib/Sema/TypeCheckConcurrency.cpp @@ -266,7 +266,8 @@ VarDecl *GlobalActorInstanceRequest::evaluate( // conformance to the 'GlobalActor' protocol. SmallVector decls; nominal->lookupQualified( - nominal, DeclNameRef(ctx.Id_shared), NL_QualifiedDefault, decls); + nominal, DeclNameRef(ctx.Id_shared), + nominal->getLoc(), NL_QualifiedDefault, decls); for (auto decl : decls) { auto var = dyn_cast(decl); if (!var) diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp index f545fa889a86a..0d039346f9589 100644 --- a/lib/Sema/TypeCheckDecl.cpp +++ b/lib/Sema/TypeCheckDecl.cpp @@ -774,7 +774,7 @@ PrimaryAssociatedTypesRequest::evaluate(Evaluator &evaluator, SmallVector result; decl->lookupQualified(ArrayRef(decl), - DeclNameRef(pair.first), + DeclNameRef(pair.first), decl->getLoc(), NL_QualifiedDefault | NL_OnlyTypes, result); diff --git a/lib/Sema/TypeCheckDeclOverride.cpp b/lib/Sema/TypeCheckDeclOverride.cpp index d4aff7bc2bffc..1ff5390225d7f 100644 --- a/lib/Sema/TypeCheckDeclOverride.cpp +++ b/lib/Sema/TypeCheckDeclOverride.cpp @@ -928,7 +928,7 @@ SmallVector OverrideMatcher::match( ctx->synthesizeSemanticMembersIfNeeded(membersName); } dc->lookupQualified(superContexts, DeclNameRef(membersName), - NL_QualifiedDefault, members); + decl->getLoc(), NL_QualifiedDefault, members); } // Check each member we found. diff --git a/lib/Sema/TypeCheckDeclPrimary.cpp b/lib/Sema/TypeCheckDeclPrimary.cpp index a0ecff79ba60c..7b3283e5b959c 100644 --- a/lib/Sema/TypeCheckDeclPrimary.cpp +++ b/lib/Sema/TypeCheckDeclPrimary.cpp @@ -1412,6 +1412,7 @@ static void diagnoseClassWithoutInitializers(ClassDecl *classDecl) { { C, DeclBaseName::createConstructor(), { C.Id_from } }); auto result = TypeChecker::lookupMember(superclassDecl, superclassType, initFrom, + classDecl->getLoc(), NameLookupFlags::IgnoreAccessControl); if (!result.empty() && !result.front().getValueDecl()->isImplicit()) diff --git a/lib/Sema/TypeCheckNameLookup.cpp b/lib/Sema/TypeCheckNameLookup.cpp index 51b8f416467b3..8d1c037b6aee1 100644 --- a/lib/Sema/TypeCheckNameLookup.cpp +++ b/lib/Sema/TypeCheckNameLookup.cpp @@ -314,6 +314,7 @@ TypeChecker::lookupUnqualifiedType(DeclContext *dc, DeclNameRef name, LookupResult TypeChecker::lookupMember(DeclContext *dc, Type type, DeclNameRef name, + SourceLoc loc, NameLookupOptions options) { assert(type->mayHaveMembers()); @@ -331,7 +332,7 @@ LookupResult TypeChecker::lookupMember(DeclContext *dc, LookupResultBuilder builder(result, dc, options); SmallVector lookupResults; - dc->lookupQualified(type, name, subOptions, lookupResults); + dc->lookupQualified(type, name, loc, subOptions, lookupResults); for (auto found : lookupResults) builder.add(found, nullptr, /*baseDecl=*/nullptr, type, /*isOuter=*/false); @@ -407,6 +408,7 @@ TypeChecker::isUnsupportedMemberTypeAccess(Type type, TypeDecl *typeDecl, LookupTypeResult TypeChecker::lookupMemberType(DeclContext *dc, Type type, DeclNameRef name, + SourceLoc loc, NameLookupOptions options) { LookupTypeResult result; @@ -422,7 +424,7 @@ LookupTypeResult TypeChecker::lookupMemberType(DeclContext *dc, // Make sure we've resolved implicit members, if we need them. namelookup::installSemanticMembersIfNeeded(type, name); - if (!dc->lookupQualified(type, name, subOptions, decls)) + if (!dc->lookupQualified(type, name, loc, subOptions, decls)) return result; // Look through the declarations, keeping only the unique type declarations. diff --git a/lib/Sema/TypeCheckPattern.cpp b/lib/Sema/TypeCheckPattern.cpp index 69260e9a0975e..eafc5638c7c13 100644 --- a/lib/Sema/TypeCheckPattern.cpp +++ b/lib/Sema/TypeCheckPattern.cpp @@ -142,7 +142,7 @@ lookupEnumMemberElement(DeclContext *DC, Type ty, // FIXME: We should be able to tell if this is a private lookup. NameLookupOptions lookupOptions = defaultMemberLookupOptions; LookupResult foundElements = - TypeChecker::lookupMember(DC, ty, name, lookupOptions); + TypeChecker::lookupMember(DC, ty, name, UseLoc, lookupOptions); return filterForEnumElement(DC, UseLoc, /*unqualifiedLookup=*/false, foundElements); } diff --git a/lib/Sema/TypeCheckPropertyWrapper.cpp b/lib/Sema/TypeCheckPropertyWrapper.cpp index 8e0717021ef52..8419c276f9d57 100644 --- a/lib/Sema/TypeCheckPropertyWrapper.cpp +++ b/lib/Sema/TypeCheckPropertyWrapper.cpp @@ -38,7 +38,9 @@ static VarDecl *findValueProperty(ASTContext &ctx, NominalTypeDecl *nominal, SmallVector vars; { SmallVector decls; - nominal->lookupQualified(nominal, DeclNameRef(name), NL_QualifiedDefault, + nominal->lookupQualified(nominal, DeclNameRef(name), + nominal->getStartLoc(), + NL_QualifiedDefault, decls); for (const auto &foundDecl : decls) { auto foundVar = dyn_cast(foundDecl); @@ -348,6 +350,7 @@ PropertyWrapperTypeInfoRequest::evaluate( SmallVector decls; nominal->lookupQualified(nominal, DeclNameRef::createConstructor(), + nominal->getStartLoc(), NL_QualifiedDefault, decls); PropertyWrapperTypeInfo result; diff --git a/lib/Sema/TypeCheckProtocol.cpp b/lib/Sema/TypeCheckProtocol.cpp index e8197806b3d10..a2580fe9c680e 100644 --- a/lib/Sema/TypeCheckProtocol.cpp +++ b/lib/Sema/TypeCheckProtocol.cpp @@ -1306,7 +1306,8 @@ WitnessChecker::lookupValueWitnessesViaImplementsAttr( nominal->synthesizeSemanticMembersIfNeeded(name.getFullName()); SmallVector lookupResults; - DC->lookupQualified(nominal, name, subOptions, lookupResults); + DC->lookupQualified(nominal, name, nominal->getLoc(), + subOptions, lookupResults); for (auto decl : lookupResults) { if (!isa(decl->getDeclContext())) @@ -1387,7 +1388,8 @@ WitnessChecker::lookupValueWitnesses(ValueDecl *req, bool *ignoringNames) { SmallVector lookupResults; bool addedAny = false; - DC->lookupQualified(nominal, reqName, options, lookupResults); + DC->lookupQualified(nominal, reqName, nominal->getLoc(), + options, lookupResults); for (auto *decl : lookupResults) { if (!isa(decl->getDeclContext())) { witnesses.push_back(decl); @@ -1399,7 +1401,8 @@ WitnessChecker::lookupValueWitnesses(ValueDecl *req, bool *ignoringNames) { // again using only the base name. if (!addedAny && ignoringNames) { lookupResults.clear(); - DC->lookupQualified(nominal, reqBaseName, options, lookupResults); + DC->lookupQualified(nominal, reqBaseName, nominal->getLoc(), + options, lookupResults); for (auto *decl : lookupResults) { if (!isa(decl->getDeclContext())) witnesses.push_back(decl); @@ -4754,6 +4757,7 @@ ResolveWitnessResult ConformanceChecker::resolveTypeWitnessViaLookup( DC->lookupQualified(DC->getSelfNominalTypeDecl(), assocType->createNameRef(), + DC->getSelfNominalTypeDecl()->getLoc(), subOptions, candidates); // If there aren't any candidates, we're done. @@ -6331,7 +6335,8 @@ diagnoseMissingAppendInterpolationMethod(NominalTypeDecl *typeDecl) { DeclNameRef baseName(typeDecl->getASTContext().Id_appendInterpolation); SmallVector lookupResults; - typeDecl->lookupQualified(typeDecl, baseName, subOptions, lookupResults); + typeDecl->lookupQualified(typeDecl, baseName, typeDecl->getLoc(), + subOptions, lookupResults); for (auto decl : lookupResults) { auto method = dyn_cast(decl); if (!method) continue; @@ -7202,6 +7207,7 @@ void TypeChecker::inferDefaultWitnesses(ProtocolDecl *proto) { SmallVector found; module->lookupQualified( proto, DeclNameRef(assocType->getName()), + proto->getLoc(), NL_QualifiedDefault|NL_ProtocolMembers|NL_OnlyTypes, found); if (found.size() == 1 && isa(found[0])) diff --git a/lib/Sema/TypeCheckProtocolInference.cpp b/lib/Sema/TypeCheckProtocolInference.cpp index 89fdacaa6b247..830d1aed3df7a 100644 --- a/lib/Sema/TypeCheckProtocolInference.cpp +++ b/lib/Sema/TypeCheckProtocolInference.cpp @@ -594,6 +594,7 @@ AssociatedTypeInference::inferTypeWitnessesViaAssociatedType( // @_implements attributes. SmallVector lookupResults; dc->lookupQualified(adoptee->getAnyNominal(), defaultName, + adoptee->getAnyNominal()->getStartLoc(), subOptions, lookupResults); InferredAssociatedTypesByWitnesses result; diff --git a/lib/Sema/TypeCheckStmt.cpp b/lib/Sema/TypeCheckStmt.cpp index 6acbee696995c..ae0b89651947f 100644 --- a/lib/Sema/TypeCheckStmt.cpp +++ b/lib/Sema/TypeCheckStmt.cpp @@ -2180,6 +2180,7 @@ static bool checkSuperInit(ConstructorDecl *fromCtor, SmallVector lookupResults; fromCtor->lookupQualified(superclassDecl, DeclNameRef::createConstructor(), + apply->getLoc(), subOptions, lookupResults); for (auto decl : lookupResults) { diff --git a/lib/Sema/TypeCheckStorage.cpp b/lib/Sema/TypeCheckStorage.cpp index c448f4dd90103..979654b18cc1b 100644 --- a/lib/Sema/TypeCheckStorage.cpp +++ b/lib/Sema/TypeCheckStorage.cpp @@ -2730,10 +2730,10 @@ static VarDecl *synthesizePropertyWrapperProjectionVar( auto dc = var->getDeclContext(); if (dc->isTypeContext()) { dc->lookupQualified(dc->getSelfNominalTypeDecl(), projectionName, - NL_QualifiedDefault, declsFound); + var->getLoc(), NL_QualifiedDefault, declsFound); } else if (dc->isModuleScopeContext()) { dc->lookupQualified(dc->getParentModule(), projectionName, - NL_QualifiedDefault, declsFound); + var->getLoc(), NL_QualifiedDefault, declsFound); } else { llvm_unreachable("Property wrappers don't work in local contexts"); } diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index 6926bef6593d0..ef53dab93a395 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -1412,7 +1412,8 @@ static Type diagnoseUnknownType(TypeResolution resolution, NameLookupOptions relookupOptions = lookupOptions; relookupOptions |= NameLookupFlags::IgnoreAccessControl; auto inaccessibleMembers = TypeChecker::lookupMemberType( - dc, parentType, repr->getNameRef(), relookupOptions); + dc, parentType, repr->getNameRef(), + repr->getLoc(), relookupOptions); if (inaccessibleMembers) { // FIXME: What if the unviable candidates have different levels of access? const TypeDecl *first = inaccessibleMembers.front().Member; @@ -1443,8 +1444,8 @@ static Type diagnoseUnknownType(TypeResolution resolution, NLOptions memberLookupOptions = (NL_QualifiedDefault | NL_IgnoreAccessControl); SmallVector results; - dc->lookupQualified(parentType, repr->getNameRef(), memberLookupOptions, - results); + dc->lookupQualified(parentType, repr->getNameRef(), repr->getLoc(), + memberLookupOptions, results); // Looks like this is not a member type, but simply a member of parent type. if (!results.empty()) { @@ -1834,7 +1835,7 @@ static Type resolveQualifiedIdentTypeRepr(TypeResolution resolution, LookupTypeResult memberTypes; if (parentTy->mayHaveMembers()) memberTypes = TypeChecker::lookupMemberType( - DC, parentTy, repr->getNameRef(), lookupOptions); + DC, parentTy, repr->getNameRef(), repr->getLoc(), lookupOptions); // Name lookup was ambiguous. Complain. // FIXME: Could try to apply generic arguments first, and see whether diff --git a/lib/Sema/TypeChecker.h b/lib/Sema/TypeChecker.h index ae1a548050102..7fe330049c3b4 100644 --- a/lib/Sema/TypeChecker.h +++ b/lib/Sema/TypeChecker.h @@ -914,6 +914,7 @@ LookupResult lookupUnqualifiedType( /// \returns The result of name lookup. LookupResult lookupMember(DeclContext *dc, Type type, DeclNameRef name, + SourceLoc loc = SourceLoc(), NameLookupOptions options = defaultMemberLookupOptions); /// Look up a member type within the given type. @@ -929,6 +930,7 @@ lookupMember(DeclContext *dc, Type type, DeclNameRef name, /// \returns The result of name lookup. LookupTypeResult lookupMemberType(DeclContext *dc, Type type, DeclNameRef name, + SourceLoc loc = SourceLoc(), NameLookupOptions options = defaultMemberTypeLookupOptions); /// Given an expression that's known to be an infix operator, diff --git a/lib/Serialization/Deserialization.cpp b/lib/Serialization/Deserialization.cpp index 21f3f0bcc34a4..b07da21d476c2 100644 --- a/lib/Serialization/Deserialization.cpp +++ b/lib/Serialization/Deserialization.cpp @@ -1926,7 +1926,7 @@ ModuleFile::resolveCrossReference(ModuleID MID, uint32_t pathLen) { getIdentifier(privateDiscriminator)); } else { baseModule->lookupQualified(baseModule, DeclNameRef(name), - NL_QualifiedDefault, + SourceLoc(), NL_QualifiedDefault, values); } filterValues(filterTy, nullptr, nullptr, isType, inProtocolExt, @@ -2113,7 +2113,7 @@ ModuleFile::resolveCrossReference(ModuleID MID, uint32_t pathLen) { getIdentifier(privateDiscriminator)); } else { otherModule->lookupQualified(otherModule, DeclNameRef(name), - NL_QualifiedDefault, + SourceLoc(), NL_QualifiedDefault, values); } diff --git a/lib/Serialization/ModuleFile.cpp b/lib/Serialization/ModuleFile.cpp index 4e7bc7a429dce..98e7cf39b4641 100644 --- a/lib/Serialization/ModuleFile.cpp +++ b/lib/Serialization/ModuleFile.cpp @@ -560,7 +560,7 @@ void ModuleFile::getImportDecls(SmallVectorImpl &Results) { SmallVector Decls; TopLevelModule->lookupQualified( TopLevelModule, DeclNameRef(ScopeID), - NL_QualifiedDefault, Decls); + SourceLoc(), NL_QualifiedDefault, Decls); Optional FoundKind = ImportDecl::findBestImportKind(Decls); assert(FoundKind.has_value() && "deserialized imports should not be ambiguous"); diff --git a/tools/SourceKit/lib/SwiftLang/SwiftSourceDocInfo.cpp b/tools/SourceKit/lib/SwiftLang/SwiftSourceDocInfo.cpp index c0bc79d71151a..928377c556793 100644 --- a/tools/SourceKit/lib/SwiftLang/SwiftSourceDocInfo.cpp +++ b/tools/SourceKit/lib/SwiftLang/SwiftSourceDocInfo.cpp @@ -536,7 +536,8 @@ static void walkRelatedDecls(const ValueDecl *VD, const FnTy &Fn) { auto type = DC->getDeclaredInterfaceType(); if (!type->is()) { DC->lookupQualified(type, DeclNameRef(VD->getBaseName()), - NL_QualifiedDefault, results); + VD->getLoc(), NL_QualifiedDefault, + results); } } else { namelookup::lookupInModule(DC->getModuleScopeContext(), @@ -544,6 +545,7 @@ static void walkRelatedDecls(const ValueDecl *VD, const FnTy &Fn) { NLKind::UnqualifiedLookup, namelookup::ResolutionKind::Overloadable, DC->getModuleScopeContext(), + VD->getLoc(), NL_UnqualifiedDefault); } From 61c99ccd1a12232d230305ce2f530d536a6c6948 Mon Sep 17 00:00:00 2001 From: Holly Borla Date: Sat, 10 Jun 2023 01:41:20 -0700 Subject: [PATCH 08/37] [NameLookup] Use source locations to determine whether to exclude macro expansions. Evaluator::hasActiveResolveMacroRequest is now unused. --- lib/AST/NameLookupRequests.cpp | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/lib/AST/NameLookupRequests.cpp b/lib/AST/NameLookupRequests.cpp index 2376d38928e2c..600a27ba4b283 100644 --- a/lib/AST/NameLookupRequests.cpp +++ b/lib/AST/NameLookupRequests.cpp @@ -545,8 +545,10 @@ static UnqualifiedLookupDescriptor excludeMacrosIfNeeded( UnqualifiedLookupFlags::ExcludeMacroExpansions)) return descriptor; - auto &evaluator = descriptor.DC->getASTContext().evaluator; - if (!evaluator.hasActiveResolveMacroRequest()) + auto isInMacroArgument = ASTScope::isInMacroArgument( + descriptor.DC->getParentSourceFile(), descriptor.Loc); + + if (!isInMacroArgument) return descriptor; descriptor.Options |= UnqualifiedLookupFlags::ExcludeMacroExpansions; @@ -560,8 +562,10 @@ static DirectLookupDescriptor excludeMacrosIfNeeded( NominalTypeDecl::LookupDirectFlags::ExcludeMacroExpansions)) return descriptor; - auto &evaluator = descriptor.DC->getASTContext().evaluator; - if (!evaluator.hasActiveResolveMacroRequest()) + auto isInMacroArgument = ASTScope::isInMacroArgument( + descriptor.DC->getParentSourceFile(), loc); + + if (!isInMacroArgument) return descriptor; descriptor.Options |= @@ -577,8 +581,10 @@ excludeMacrosIfNeeded(const DeclContext *dc, SourceLoc loc, if (options & NL_ExcludeMacroExpansions) return options; - auto &evaluator = dc->getASTContext().evaluator; - if (!evaluator.hasActiveResolveMacroRequest()) + auto isInMacroArgument = ASTScope::isInMacroArgument( + dc->getParentSourceFile(), loc); + + if (!isInMacroArgument) return options; return options | NL_ExcludeMacroExpansions; From db23cf5f32d1df12624deb4250fd02d61c323cf5 Mon Sep 17 00:00:00 2001 From: Holly Borla Date: Sat, 10 Jun 2023 01:42:25 -0700 Subject: [PATCH 09/37] [PreCheckExpr] Don't perform typo correction inside macro arguments. --- lib/Sema/PreCheckExpr.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/lib/Sema/PreCheckExpr.cpp b/lib/Sema/PreCheckExpr.cpp index e270db6a2e799..0fe4d0df8d8d3 100644 --- a/lib/Sema/PreCheckExpr.cpp +++ b/lib/Sema/PreCheckExpr.cpp @@ -602,8 +602,14 @@ Expr *TypeChecker::resolveDeclRefExpr(UnresolvedDeclRefExpr *UDRE, } TypoCorrectionResults corrections(Name, nameLoc); - TypeChecker::performTypoCorrection(DC, UDRE->getRefKind(), Type(), - lookupOptions, corrections); + + // FIXME: Don't perform typo correction inside macro arguments, because it + // will invoke synthesizing declarations in this scope, which will attempt to + // expand this macro which leads to circular reference errors. + if (!ASTScope::isInMacroArgument(DC->getParentSourceFile(), UDRE->getLoc())) { + TypeChecker::performTypoCorrection(DC, UDRE->getRefKind(), Type(), + lookupOptions, corrections); + } if (auto typo = corrections.claimUniqueCorrection()) { auto diag = Context.Diags.diagnose( From f9f63e3aea61e3ae01419427225efee96c982e7d Mon Sep 17 00:00:00 2001 From: Holly Borla Date: Sat, 10 Jun 2023 01:42:46 -0700 Subject: [PATCH 10/37] [Macros] Add a test that invokes macro expansion through the conformance checker while type checking a freestanding macro argument in the same scope. --- .../Inputs/syntax_macro_definitions.swift | 23 +++++++++++++++++++ test/Macros/top_level_freestanding.swift | 21 +++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/test/Macros/Inputs/syntax_macro_definitions.swift b/test/Macros/Inputs/syntax_macro_definitions.swift index b01cb48da66dc..3b4d17dc27118 100644 --- a/test/Macros/Inputs/syntax_macro_definitions.swift +++ b/test/Macros/Inputs/syntax_macro_definitions.swift @@ -1603,3 +1603,26 @@ extension SelfAlwaysEqualOperator: MemberMacro { ] } } + +public struct InitializableMacro: ConformanceMacro, MemberMacro { + public static func expansion( + of node: AttributeSyntax, + providingConformancesOf decl: some DeclGroupSyntax, + in context: some MacroExpansionContext + ) throws -> [(TypeSyntax, GenericWhereClauseSyntax?)] { + return [("Initializable", nil)] + } + + public static func expansion( + of node: AttributeSyntax, + providingMembersOf decl: some DeclGroupSyntax, + in context: some MacroExpansionContext + ) throws -> [DeclSyntax] { + let requirement: DeclSyntax = + """ + init(value: Int) {} + """ + + return [requirement] + } +} diff --git a/test/Macros/top_level_freestanding.swift b/test/Macros/top_level_freestanding.swift index 3fd9c07c1d6bd..ed4cc3e51f3b5 100644 --- a/test/Macros/top_level_freestanding.swift +++ b/test/Macros/top_level_freestanding.swift @@ -104,3 +104,24 @@ func testGlobalVariable() { } #endif + + +@freestanding(declaration) +macro Empty(_ closure: () -> T) = #externalMacro(module: "MacroDefinition", type: "EmptyDeclarationMacro") + +#Empty { + S(a: 10, b: 10) +} + +@attached(conformance) +@attached(member, names: named(init)) +macro Initializable() = #externalMacro(module: "MacroDefinition", type: "InitializableMacro") + +protocol Initializable { + init(value: Int) +} + +@Initializable +struct S { + init(a: Int, b: Int) {} +} From 98249543cd8625d283d94d175636a8d0535d0887 Mon Sep 17 00:00:00 2001 From: Holly Borla Date: Sat, 10 Jun 2023 15:08:29 -0700 Subject: [PATCH 11/37] [Macros] Ban freestanding and peer macro expansions that can produce arbitrary names at global scope. Freestanding and peer macros applied at top-level scope cannot introduce arbitrary names. Introducing arbitrary names means that any lookup into this scope must expand the macro. This is a problem, because resolving the macro can invoke type checking other declarations, e.g. anything that the macro arguments depend on. If _anything_ the macro depends on performs name unqualified name lookup, e.g. type resolution, we'll get circularity errors. It's better to prevent this by banning these macros at global scope if any of the macro candidates introduce arbitrary names. --- include/swift/AST/DiagnosticsSema.def | 4 ++ lib/Sema/TypeCheckMacros.cpp | 47 ++++++++++++++++++++++++ test/Macros/macro_expand_peers.swift | 10 +++++ test/Macros/top_level_freestanding.swift | 4 ++ 4 files changed, 65 insertions(+) diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 97e2fb51b35a8..dee6d8918c7b3 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -7188,6 +7188,10 @@ ERROR(macro_accessor_missing_from_expansion,none, ERROR(macro_init_accessor_not_documented,none, "expansion of macro %0 produced an unexpected 'init' accessor", (DeclName)) +ERROR(global_arbitrary_name,none, + "'%0' macros are not allowed to introduce arbitrary names " + "at global scope", + (StringRef)) ERROR(macro_resolve_circular_reference, none, "circular reference resolving %select{freestanding|attached}0 macro %1", diff --git a/lib/Sema/TypeCheckMacros.cpp b/lib/Sema/TypeCheckMacros.cpp index a5b1922c2b237..00be8a294574a 100644 --- a/lib/Sema/TypeCheckMacros.cpp +++ b/lib/Sema/TypeCheckMacros.cpp @@ -1470,6 +1470,40 @@ swift::expandConformances(CustomAttr *attr, MacroDecl *macro, return macroSourceFile->getBufferID(); } +/// Emits an error and returns \c true if the maro reference may +/// introduce arbitrary names at global scope. +static bool diagnoseArbitraryGlobalNames(DeclContext *dc, + UnresolvedMacroReference macroRef, + MacroRole macroRole) { + auto &ctx = dc->getASTContext(); + assert(macroRole == MacroRole::Declaration || + macroRole == MacroRole::Peer); + + if (!dc->isModuleScopeContext()) + return false; + + bool isInvalid = false; + namelookup::forEachPotentialResolvedMacro( + dc, macroRef.getMacroName(), macroRole, + [&](MacroDecl *decl, const MacroRoleAttr *attr) { + if (!isInvalid && + attr->hasNameKind(MacroIntroducedDeclNameKind::Arbitrary)) { + ctx.Diags.diagnose(macroRef.getSigilLoc(), + diag::global_arbitrary_name, + getMacroRoleString(macroRole)); + isInvalid = true; + + // If this is an attached macro, mark the attribute as invalid + // to avoid diagnosing an unknown attribute later. + if (auto *attr = macroRef.getAttr()) { + attr->setInvalid(); + } + } + }); + + return isInvalid; +} + ConcreteDeclRef ResolveMacroRequest::evaluate(Evaluator &evaluator, UnresolvedMacroReference macroRef, DeclContext *dc) const { @@ -1492,6 +1526,19 @@ ConcreteDeclRef ResolveMacroRequest::evaluate(Evaluator &evaluator, return ConcreteDeclRef(); } + // Freestanding and peer macros applied at top-level scope cannot introduce + // arbitrary names. Introducing arbitrary names means that any lookup + // into this scope must expand the macro. This is a problem, because + // resolving the macro can invoke type checking other declarations, e.g. + // anything that the macro arguments depend on. If _anything_ the macro + // depends on performs name unqualified name lookup, e.g. type resolution, + // we'll get circularity errors. It's better to prevent this by banning + // these macros at global scope if any of the macro candidates introduce + // arbitrary names. + if (diagnoseArbitraryGlobalNames(dc, macroRef, MacroRole::Declaration) || + diagnoseArbitraryGlobalNames(dc, macroRef, MacroRole::Peer)) + return ConcreteDeclRef(); + // If we already have a MacroExpansionExpr, use that. Otherwise, // create one. MacroExpansionExpr *macroExpansion; diff --git a/test/Macros/macro_expand_peers.swift b/test/Macros/macro_expand_peers.swift index 1f469a088a814..304c621f186fa 100644 --- a/test/Macros/macro_expand_peers.swift +++ b/test/Macros/macro_expand_peers.swift @@ -162,6 +162,16 @@ struct S2 { #endif } +#if TEST_DIAGNOSTICS +// Peer macros cannot introduce arbitrary names at global scope + +//expected-error@+1 {{'peer' macros are not allowed to introduce arbitrary names at global scope}} +@addCompletionHandlerArbitrarily(x) +func h(a: Int, for b: String, _ value: Double) async -> String { + return b +} +#endif + // Stored properties generated by a peer macro @attached(accessor) @attached(peer, names: prefixed(_)) diff --git a/test/Macros/top_level_freestanding.swift b/test/Macros/top_level_freestanding.swift index ed4cc3e51f3b5..48fe22e78ca51 100644 --- a/test/Macros/top_level_freestanding.swift +++ b/test/Macros/top_level_freestanding.swift @@ -72,13 +72,17 @@ struct HasInnerClosure { #freestandingWithClosure(1) { x in x } } +#if TEST_DIAGNOSTICS // Arbitrary names at global scope #bitwidthNumberedStructs("MyIntGlobal") +// expected-error@-1 {{'declaration' macros are not allowed to introduce arbitrary names at global scope}} func testArbitraryAtGlobal() { _ = MyIntGlobal16() + // expected-error@-1 {{cannot find 'MyIntGlobal16' in scope}} } +#endif // DIAG_BUFFERS-DAG: @__swiftmacro_9MacroUser33_{{.*}}9stringifyfMf1_{{.*}}warning: 'deprecated()' is deprecated // DIAG_BUFFERS-DAG: @__swiftmacro_9MacroUser33_{{.*}}9stringifyfMf2_{{.*}}warning: 'deprecated()' is deprecated From 0b91f633492ee4f3c7d3108838a6e301d2d99369 Mon Sep 17 00:00:00 2001 From: Holly Borla Date: Sat, 10 Jun 2023 16:19:01 -0700 Subject: [PATCH 12/37] [ASTScope] Don't consider freestanding macro expansions as being part of a macro argument. --- lib/AST/ASTScopeLookup.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lib/AST/ASTScopeLookup.cpp b/lib/AST/ASTScopeLookup.cpp index f7aa0bba5b46c..196051fa1c016 100644 --- a/lib/AST/ASTScopeLookup.cpp +++ b/lib/AST/ASTScopeLookup.cpp @@ -689,6 +689,16 @@ bool ASTScopeImpl::isInMacroArgument(SourceFile *sourceFile, do { if (scope->isMacroArgumentScope()) return true; + + // If we've reached a source file scope, we can't be inside of + // a macro argument. Either this is a top-level source file, or + // it's macro expansion buffer. We have to check for this because + // macro expansion buffers for freestanding macros are children of + // MacroExpansionDeclScope, and child scopes of freestanding macros + // are otherwise inside the macro argument. + if (scope->getClassName() == "ASTSourceFileScope") + return false; + } while ((scope = scope->getParent().getPtrOrNull())); return false; From 706411d2e65d53a8afac800ae5dde28a03f53a52 Mon Sep 17 00:00:00 2001 From: Holly Borla Date: Sat, 10 Jun 2023 22:07:38 -0700 Subject: [PATCH 13/37] [CodeCompletion] Plumb source locations through code completion name lookup. --- include/swift/AST/NameLookup.h | 2 +- lib/IDE/CompletionLookup.cpp | 19 ++++++++------- lib/IDE/CompletionOverrideLookup.cpp | 2 +- lib/IDE/ConformingMethodList.cpp | 3 ++- lib/IDE/TypeContextInfo.cpp | 3 ++- lib/Sema/LookupVisibleDecls.cpp | 35 ++++++++++++++-------------- lib/Sema/TypeCheckNameLookup.cpp | 2 +- 7 files changed, 35 insertions(+), 31 deletions(-) diff --git a/include/swift/AST/NameLookup.h b/include/swift/AST/NameLookup.h index baa687e140652..51aea7c64db31 100644 --- a/include/swift/AST/NameLookup.h +++ b/include/swift/AST/NameLookup.h @@ -513,7 +513,7 @@ void lookupVisibleDecls(VisibleDeclConsumer &Consumer, /// /// \param CurrDC the DeclContext from which the lookup is done. void lookupVisibleMemberDecls(VisibleDeclConsumer &Consumer, - Type BaseTy, + Type BaseTy, SourceLoc loc, const DeclContext *CurrDC, bool includeInstanceMembers, bool includeDerivedRequirements, diff --git a/lib/IDE/CompletionLookup.cpp b/lib/IDE/CompletionLookup.cpp index b697641afeba4..33f99cc19b0aa 100644 --- a/lib/IDE/CompletionLookup.cpp +++ b/lib/IDE/CompletionLookup.cpp @@ -2262,7 +2262,7 @@ bool CompletionLookup::tryUnwrappedCompletions(Type ExprType, bool isIUO) { // unforced IUO. if (isIUO) { if (Type Unwrapped = ExprType->getOptionalObjectType()) { - lookupVisibleMemberDecls(*this, Unwrapped, CurrDeclContext, + lookupVisibleMemberDecls(*this, Unwrapped, DotLoc, CurrDeclContext, IncludeInstanceMembers, /*includeDerivedRequirements*/ false, /*includeProtocolExtensionMembers*/ true); @@ -2289,7 +2289,8 @@ bool CompletionLookup::tryUnwrappedCompletions(Type ExprType, bool isIUO) { if (NumBytesToEraseForOptionalUnwrap <= CodeCompletionResult::MaxNumBytesToErase) { if (!tryTupleExprCompletions(Unwrapped)) { - lookupVisibleMemberDecls(*this, Unwrapped, CurrDeclContext, + lookupVisibleMemberDecls(*this, Unwrapped, DotLoc, + CurrDeclContext, IncludeInstanceMembers, /*includeDerivedRequirements*/ false, /*includeProtocolExtensionMembers*/ true); @@ -2370,7 +2371,7 @@ void CompletionLookup::getValueExprCompletions(Type ExprType, ValueDecl *VD) { // Don't check/return so we still add the members of Optional itself below tryUnwrappedCompletions(ExprType, isIUO); - lookupVisibleMemberDecls(*this, ExprType, CurrDeclContext, + lookupVisibleMemberDecls(*this, ExprType, DotLoc, CurrDeclContext, IncludeInstanceMembers, /*includeDerivedRequirements*/ false, /*includeProtocolExtensionMembers*/ true); @@ -2833,7 +2834,7 @@ void CompletionLookup::getUnresolvedMemberCompletions(Type T) { llvm::SaveAndRestore SaveLook(Kind, LookupKind::ValueExpr); llvm::SaveAndRestore SaveType(ExprType, baseType); llvm::SaveAndRestore SaveUnresolved(IsUnresolvedMember, true); - lookupVisibleMemberDecls(consumer, baseType, CurrDeclContext, + lookupVisibleMemberDecls(consumer, baseType, DotLoc, CurrDeclContext, /*includeInstanceMembers=*/false, /*includeDerivedRequirements*/ false, /*includeProtocolExtensionMembers*/ true); @@ -2847,7 +2848,7 @@ void CompletionLookup::getEnumElementPatternCompletions(Type T) { llvm::SaveAndRestore SaveLook(Kind, LookupKind::EnumElement); llvm::SaveAndRestore SaveType(ExprType, baseType); llvm::SaveAndRestore SaveUnresolved(IsUnresolvedMember, true); - lookupVisibleMemberDecls(*this, baseType, CurrDeclContext, + lookupVisibleMemberDecls(*this, baseType, DotLoc, CurrDeclContext, /*includeInstanceMembers=*/false, /*includeDerivedRequirements=*/false, /*includeProtocolExtensionMembers=*/true); @@ -2915,8 +2916,8 @@ void CompletionLookup::getTypeCompletions(Type BaseType) { Kind = LookupKind::Type; this->BaseType = BaseType; NeedLeadingDot = !HaveDot; - lookupVisibleMemberDecls(*this, MetatypeType::get(BaseType), CurrDeclContext, - IncludeInstanceMembers, + lookupVisibleMemberDecls(*this, MetatypeType::get(BaseType), DotLoc, + CurrDeclContext, IncludeInstanceMembers, /*includeDerivedRequirements*/ false, /*includeProtocolExtensionMembers*/ false); if (BaseType->isAnyExistentialType()) { @@ -2951,8 +2952,8 @@ void CompletionLookup::getGenericRequirementCompletions( Kind = LookupKind::GenericRequirement; this->BaseType = selfTy; NeedLeadingDot = false; - lookupVisibleMemberDecls(*this, MetatypeType::get(selfTy), CurrDeclContext, - IncludeInstanceMembers, + lookupVisibleMemberDecls(*this, MetatypeType::get(selfTy), DotLoc, + CurrDeclContext, IncludeInstanceMembers, /*includeDerivedRequirements*/ false, /*includeProtocolExtensionMembers*/ true); // We not only allow referencing nested types/typealiases directly, but also diff --git a/lib/IDE/CompletionOverrideLookup.cpp b/lib/IDE/CompletionOverrideLookup.cpp index 53320471bfbe7..8a97365271c7e 100644 --- a/lib/IDE/CompletionOverrideLookup.cpp +++ b/lib/IDE/CompletionOverrideLookup.cpp @@ -541,7 +541,7 @@ void CompletionOverrideLookup::getOverrideCompletions(SourceLoc Loc) { if (CurrTy && !CurrTy->is()) { // Look for overridable static members too. Type Meta = MetatypeType::get(CurrTy); - lookupVisibleMemberDecls(*this, Meta, CurrDeclContext, + lookupVisibleMemberDecls(*this, Meta, introducerLoc, CurrDeclContext, /*includeInstanceMembers=*/true, /*includeDerivedRequirements*/ true, /*includeProtocolExtensionMembers*/ false); diff --git a/lib/IDE/ConformingMethodList.cpp b/lib/IDE/ConformingMethodList.cpp index ed5fde99cead9..ef1d355695116 100644 --- a/lib/IDE/ConformingMethodList.cpp +++ b/lib/IDE/ConformingMethodList.cpp @@ -166,7 +166,8 @@ void ConformingMethodListCallbacks::getMatchingMethods( } LocalConsumer(CurDeclContext, T, expectedTypes, result); - lookupVisibleMemberDecls(LocalConsumer, MetatypeType::get(T), CurDeclContext, + lookupVisibleMemberDecls(LocalConsumer, MetatypeType::get(T), + Loc, CurDeclContext, /*includeInstanceMembers=*/false, /*includeDerivedRequirements*/false, /*includeProtocolExtensionMembers*/true); diff --git a/lib/IDE/TypeContextInfo.cpp b/lib/IDE/TypeContextInfo.cpp index ffb398ae39b8f..abbc8a88a7bcf 100644 --- a/lib/IDE/TypeContextInfo.cpp +++ b/lib/IDE/TypeContextInfo.cpp @@ -194,7 +194,8 @@ void ContextInfoCallbacks::getImplicitMembers( } LocalConsumer(CurDeclContext, T, Result); - lookupVisibleMemberDecls(LocalConsumer, MetatypeType::get(T), CurDeclContext, + lookupVisibleMemberDecls(LocalConsumer, MetatypeType::get(T), + Loc, CurDeclContext, /*includeInstanceMembers=*/false, /*includeDerivedRequirements*/false, /*includeProtocolExtensionMembers*/true); diff --git a/lib/Sema/LookupVisibleDecls.cpp b/lib/Sema/LookupVisibleDecls.cpp index 2d723468f1597..ad39282fdea44 100644 --- a/lib/Sema/LookupVisibleDecls.cpp +++ b/lib/Sema/LookupVisibleDecls.cpp @@ -1143,7 +1143,7 @@ struct KeyPathDynamicMemberConsumer : public VisibleDeclConsumer { } // end anonymous namespace static void lookupVisibleDynamicMemberLookupDecls( - Type baseType, KeyPathDynamicMemberConsumer &consumer, + Type baseType, SourceLoc loc, KeyPathDynamicMemberConsumer &consumer, const DeclContext *dc, LookupState LS, DeclVisibilityKind reason, GenericSignature Sig, VisitedSet &visited, llvm::DenseSet &seenDynamicLookup); @@ -1154,13 +1154,14 @@ static void lookupVisibleDynamicMemberLookupDecls( /// \note This is an implementation detail of \c lookupVisibleMemberDecls and /// exists to create the correct recursion for dynamic member lookup. static void lookupVisibleMemberAndDynamicMemberDecls( - Type baseType, VisibleDeclConsumer &consumer, + Type baseType, SourceLoc loc, VisibleDeclConsumer &consumer, KeyPathDynamicMemberConsumer &dynamicMemberConsumer, const DeclContext *DC, LookupState LS, DeclVisibilityKind reason, GenericSignature Sig, VisitedSet &visited, llvm::DenseSet &seenDynamicLookup) { lookupVisibleMemberDeclsImpl(baseType, consumer, DC, LS, reason, Sig, visited); - lookupVisibleDynamicMemberLookupDecls(baseType, dynamicMemberConsumer, DC, LS, - reason, Sig, visited, seenDynamicLookup); + lookupVisibleDynamicMemberLookupDecls(baseType, loc, dynamicMemberConsumer, + DC, LS, reason, Sig, visited, + seenDynamicLookup); } /// Enumerates all keypath dynamic members of \c baseType, as seen from the @@ -1170,7 +1171,7 @@ static void lookupVisibleMemberAndDynamicMemberDecls( /// dynamic member subscripts and looks up the members of the keypath's root /// type. static void lookupVisibleDynamicMemberLookupDecls( - Type baseType, KeyPathDynamicMemberConsumer &consumer, + Type baseType, SourceLoc loc, KeyPathDynamicMemberConsumer &consumer, const DeclContext *dc, LookupState LS, DeclVisibilityKind reason, GenericSignature Sig, VisitedSet &visited, llvm::DenseSet &seenDynamicLookup) { @@ -1187,8 +1188,7 @@ static void lookupVisibleDynamicMemberLookupDecls( { ctx, DeclBaseName::createSubscript(), { ctx.Id_dynamicMember} }); SmallVector subscripts; - dc->lookupQualified(baseType, subscriptName, - baseType->getAnyNominal()->getLoc(), + dc->lookupQualified(baseType, subscriptName, loc, NL_QualifiedDefault | NL_ProtocolMembers, subscripts); for (ValueDecl *VD : subscripts) { @@ -1210,9 +1210,9 @@ static void lookupVisibleDynamicMemberLookupDecls( KeyPathDynamicMemberConsumer::SubscriptChange sub(consumer, subscript, baseType); - lookupVisibleMemberAndDynamicMemberDecls(memberType, consumer, consumer, dc, - LS, reason, Sig, visited, - seenDynamicLookup); + lookupVisibleMemberAndDynamicMemberDecls(memberType, loc, consumer, + consumer, dc, LS, reason, Sig, + visited, seenDynamicLookup); } } @@ -1223,8 +1223,9 @@ static void lookupVisibleDynamicMemberLookupDecls( /// where 'self' is the type of 'a'. This operation is only valid after name /// binding. static void lookupVisibleMemberDecls( - Type BaseTy, VisibleDeclConsumer &Consumer, const DeclContext *CurrDC, - LookupState LS, DeclVisibilityKind Reason, GenericSignature Sig) { + Type BaseTy, SourceLoc loc, VisibleDeclConsumer &Consumer, + const DeclContext *CurrDC, LookupState LS, + DeclVisibilityKind Reason, GenericSignature Sig) { OverrideFilteringConsumer overrideConsumer(BaseTy, CurrDC); KeyPathDynamicMemberConsumer dynamicConsumer( Consumer, @@ -1233,7 +1234,7 @@ static void lookupVisibleMemberDecls( VisitedSet Visited; llvm::DenseSet seenDynamicLookup; lookupVisibleMemberAndDynamicMemberDecls( - BaseTy, overrideConsumer, dynamicConsumer, CurrDC, LS, Reason, + BaseTy, loc, overrideConsumer, dynamicConsumer, CurrDC, LS, Reason, Sig, Visited, seenDynamicLookup); // Report the declarations we found to the real consumer. @@ -1347,8 +1348,8 @@ static void lookupVisibleDeclsImpl(VisibleDeclConsumer &Consumer, } if (ExtendedType) { - ::lookupVisibleMemberDecls(ExtendedType, Consumer, DC, LS, MemberReason, - nullptr); + ::lookupVisibleMemberDecls(ExtendedType, Loc, Consumer, DC, LS, + MemberReason, nullptr); // Going outside the current type context. MemberReason = DeclVisibilityKind::MemberOfOutsideNominal; @@ -1404,7 +1405,7 @@ void swift::lookupVisibleDecls(VisibleDeclConsumer &Consumer, } void swift::lookupVisibleMemberDecls(VisibleDeclConsumer &Consumer, Type BaseTy, - const DeclContext *CurrDC, + SourceLoc loc, const DeclContext *CurrDC, bool includeInstanceMembers, bool includeDerivedRequirements, bool includeProtocolExtensionMembers, @@ -1421,7 +1422,7 @@ void swift::lookupVisibleMemberDecls(VisibleDeclConsumer &Consumer, Type BaseTy, ls = ls.withIncludeProtocolExtensionMembers(); } - ::lookupVisibleMemberDecls(BaseTy, Consumer, CurrDC, ls, + ::lookupVisibleMemberDecls(BaseTy, loc, Consumer, CurrDC, ls, DeclVisibilityKind::MemberOfCurrentNominal, Sig); } diff --git a/lib/Sema/TypeCheckNameLookup.cpp b/lib/Sema/TypeCheckNameLookup.cpp index 8d1c037b6aee1..4cfc994ab296c 100644 --- a/lib/Sema/TypeCheckNameLookup.cpp +++ b/lib/Sema/TypeCheckNameLookup.cpp @@ -617,7 +617,7 @@ void TypeChecker::performTypoCorrection(DeclContext *DC, DeclRefKind refKind, }); if (baseTypeOrNull) { - lookupVisibleMemberDecls(consumer, baseTypeOrNull, DC, + lookupVisibleMemberDecls(consumer, baseTypeOrNull, SourceLoc(), DC, /*includeInstanceMembers*/true, /*includeDerivedRequirements*/false, /*includeProtocolExtensionMembers*/true, From 51e1a39a0c5eb0731360b2037aaec385ec83010b Mon Sep 17 00:00:00 2001 From: Holly Borla Date: Sat, 10 Jun 2023 23:37:32 -0700 Subject: [PATCH 14/37] [Parser] Reset ASTScopes before performing the IDEInspection second pass. IDE inspection can delay parsing of particular declarations, so expanding ASTScopes during the first pass will miss those declarations. Clear any expanded scopes to force re-expansion during the second pass. --- lib/Parse/Parser.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index 0e163d85d8dd8..7c62326b4a4f4 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -154,6 +154,9 @@ void Parser::performIDEInspectionSecondPassImpl( // discriminators. Context.evaluator.clearCachedOutput(LocalDiscriminatorsRequest{DC}); + // Clear any ASTScopes that were expanded. + SF.clearScope(); + switch (info.Kind) { case IDEInspectionDelayedDeclKind::TopLevelCodeDecl: { // Re-enter the top-level code decl context. From 393b4ceb956f91f02a10c0b671664313a6bb8563 Mon Sep 17 00:00:00 2001 From: Holly Borla Date: Sun, 11 Jun 2023 19:44:07 -0700 Subject: [PATCH 15/37] [NameLookup] Move macro-related name lookup operations into the namelookup namespace. This moves the `isInMacroArgument` predicate and `lookupMacros` into `namelookup`. ASTScope still encapsulates the scope tree and contains the operation to lookup the enclosing macro scope, which then invokes a callback to determine whether a potential macro scope is indeed a macro, because answering this question requires name lookup. --- include/swift/AST/ASTScope.h | 28 +++++--------- include/swift/AST/NameLookup.h | 27 +++++++++++-- include/swift/AST/TypeCheckRequests.h | 3 ++ lib/AST/ASTScope.cpp | 7 ++-- lib/AST/ASTScopeLookup.cpp | 23 ++++++----- lib/AST/NameLookup.cpp | 56 ++++++++++++++++++++++++++- lib/AST/NameLookupRequests.cpp | 6 +-- lib/Sema/CSGen.cpp | 2 +- lib/Sema/PreCheckExpr.cpp | 2 +- lib/Sema/TypeCheckDecl.cpp | 30 -------------- lib/Sema/TypeCheckMacros.cpp | 2 +- lib/Sema/TypeChecker.h | 3 -- 12 files changed, 115 insertions(+), 74 deletions(-) diff --git a/include/swift/AST/ASTScope.h b/include/swift/AST/ASTScope.h index a8d229e89069b..3411bed70fbf9 100644 --- a/include/swift/AST/ASTScope.h +++ b/include/swift/AST/ASTScope.h @@ -218,6 +218,10 @@ class ASTScopeImpl : public ASTAllocated { return nullptr; } + virtual NullablePtr getFreestandingMacro() const { + return nullptr; + } + #pragma mark - debugging and printing public: @@ -278,16 +282,9 @@ class ASTScopeImpl : public ASTAllocated { static std::pair lookupFallthroughSourceAndDest(SourceFile *sourceFile, SourceLoc loc); - /// Returns \c true if the given source location is inside an attached - /// or freestanding macro argument. - static bool isInMacroArgument(SourceFile *sourceFile, SourceLoc loc); - - /// Returns \c true if this scope contains macro arguments. - /// - /// This is always true within macro expansion decl scopes, and it's - /// true within custom attribute scopes if the attribute name is a - /// potential macro reference. - virtual bool isMacroArgumentScope() const { return false; } + static void lookupEnclosingMacroScope( + SourceFile *sourceFile, SourceLoc loc, + llvm::function_ref consume); /// Scopes that cannot bind variables may set this to true to create more /// compact scope tree in the debug info. @@ -879,13 +876,6 @@ class CustomAttributeScope final : public ASTScopeImpl { return attr; } bool ignoreInDebugInfo() const override { return true; } - - bool isMacroArgumentScope() const override { - // FIXME: This should check whether the attribute name is - // a macro. Otherwise, macro expansion will be suppressed - // for property wrapper arguments. - return true; - } private: void expandAScopeThatDoesNotCreateANewInsertionPoint(ScopeCreator &); @@ -1285,8 +1275,8 @@ class MacroExpansionDeclScope final : public ASTScopeImpl { SourceRange getSourceRangeOfThisASTNode(bool omitAssertions = false) const override; - bool isMacroArgumentScope() const override { - return true; + NullablePtr getFreestandingMacro() const override { + return decl; } protected: diff --git a/include/swift/AST/NameLookup.h b/include/swift/AST/NameLookup.h index 51aea7c64db31..5d3898d43283e 100644 --- a/include/swift/AST/NameLookup.h +++ b/include/swift/AST/NameLookup.h @@ -545,6 +545,15 @@ template void filterForDiscriminator(SmallVectorImpl &results, DebuggerClient *debugClient); +/// \returns The set of macro declarations with the given name that +/// fulfill any of the given macro roles. +SmallVector +lookupMacros(DeclContext *dc, DeclNameRef macroName, MacroRoles roles); + +/// \returns Whether the given source location is inside an attached +/// or freestanding macro argument. +bool isInMacroArgument(SourceFile *sourceFile, SourceLoc loc); + /// Call the given function body with each macro declaration and its associated /// role attribute for the given role. /// @@ -816,9 +825,21 @@ class ASTScope : public ASTAllocated { static std::pair lookupFallthroughSourceAndDest(SourceFile *sourceFile, SourceLoc loc); - /// Returns \c true if the given source location is inside an attached - /// or freestanding macro argument. - static bool isInMacroArgument(SourceFile *sourceFile, SourceLoc loc); + using PotentialMacro = + llvm::PointerUnion; + + /// Look up the scope tree for the nearest enclosing macro scope at + /// the given source location. + /// + /// \param sourceFile The source file containing the given location. + /// \param loc The source location to start lookup from. + /// \param consume A function that is called when a potential macro + /// scope is found. If \c consume returns \c true, lookup + /// will stop. If \c consume returns \c false, lookup will + /// continue up the scope tree. + static void lookupEnclosingMacroScope( + SourceFile *sourceFile, SourceLoc loc, + llvm::function_ref consume); SWIFT_DEBUG_DUMP; void print(llvm::raw_ostream &) const; diff --git a/include/swift/AST/TypeCheckRequests.h b/include/swift/AST/TypeCheckRequests.h index 8574c38fa42f1..0dd81a6b654cf 100644 --- a/include/swift/AST/TypeCheckRequests.h +++ b/include/swift/AST/TypeCheckRequests.h @@ -3249,6 +3249,9 @@ class UnresolvedMacroReference { public: UnresolvedMacroReference(FreestandingMacroExpansion *exp) : pointer(exp) {} UnresolvedMacroReference(CustomAttr *attr) : pointer(attr) {} + UnresolvedMacroReference( + llvm::PointerUnion pointer) + : pointer(pointer) {} FreestandingMacroExpansion *getFreestanding() const { return pointer.dyn_cast(); diff --git a/lib/AST/ASTScope.cpp b/lib/AST/ASTScope.cpp index b9b830aad6cce..aa80e71159bf9 100644 --- a/lib/AST/ASTScope.cpp +++ b/lib/AST/ASTScope.cpp @@ -60,9 +60,10 @@ std::pair ASTScope::lookupFallthroughSourceAndDest( return ASTScopeImpl::lookupFallthroughSourceAndDest(sourceFile, loc); } -bool ASTScope::isInMacroArgument(SourceFile *sourceFile, - SourceLoc loc) { - return ASTScopeImpl::isInMacroArgument(sourceFile, loc); +void ASTScope::lookupEnclosingMacroScope( + SourceFile *sourceFile, SourceLoc loc, + llvm::function_ref body) { + return ASTScopeImpl::lookupEnclosingMacroScope(sourceFile, loc, body); } #if SWIFT_COMPILER_IS_MSVC diff --git a/lib/AST/ASTScopeLookup.cpp b/lib/AST/ASTScopeLookup.cpp index 196051fa1c016..a8168ca096605 100644 --- a/lib/AST/ASTScopeLookup.cpp +++ b/lib/AST/ASTScopeLookup.cpp @@ -676,19 +676,26 @@ std::pair ASTScopeImpl::lookupFallthroughSourceAndDest( return { nullptr, nullptr }; } -bool ASTScopeImpl::isInMacroArgument(SourceFile *sourceFile, - SourceLoc loc) { +void ASTScopeImpl::lookupEnclosingMacroScope( + SourceFile *sourceFile, SourceLoc loc, + llvm::function_ref consume) { if (!sourceFile || sourceFile->Kind == SourceFileKind::Interface) - return false; + return; if (loc.isInvalid()) - return false; + return; auto *fileScope = sourceFile->getScope().impl; auto *scope = fileScope->findInnermostEnclosingScope(loc, nullptr); do { - if (scope->isMacroArgumentScope()) - return true; + auto *freestanding = scope->getFreestandingMacro().getPtrOrNull(); + if (freestanding && consume(freestanding)) + return; + + auto *attr = scope->getDeclAttributeIfAny().getPtrOrNull(); + auto *potentialAttached = dyn_cast_or_null(attr); + if (potentialAttached && consume(potentialAttached)) + return; // If we've reached a source file scope, we can't be inside of // a macro argument. Either this is a top-level source file, or @@ -697,9 +704,7 @@ bool ASTScopeImpl::isInMacroArgument(SourceFile *sourceFile, // MacroExpansionDeclScope, and child scopes of freestanding macros // are otherwise inside the macro argument. if (scope->getClassName() == "ASTSourceFileScope") - return false; + return; } while ((scope = scope->getParent().getPtrOrNull())); - - return false; } diff --git a/lib/AST/NameLookup.cpp b/lib/AST/NameLookup.cpp index 66c3bd8a97657..ca2162d7e504e 100644 --- a/lib/AST/NameLookup.cpp +++ b/lib/AST/NameLookup.cpp @@ -1594,6 +1594,60 @@ static DeclName adjustLazyMacroExpansionNameKey( return name; } +SmallVector +namelookup::lookupMacros(DeclContext *dc, DeclNameRef macroName, + MacroRoles roles) { + SmallVector choices; + auto moduleScopeDC = dc->getModuleScopeContext(); + ASTContext &ctx = moduleScopeDC->getASTContext(); + + // Macro lookup should always exclude macro expansions; macro + // expansions cannot introduce new macro declarations. Note that + // the source location here doesn't matter. + UnqualifiedLookupDescriptor descriptor{ + macroName, moduleScopeDC, SourceLoc(), + UnqualifiedLookupFlags::ExcludeMacroExpansions + }; + + auto lookup = evaluateOrDefault( + ctx.evaluator, UnqualifiedLookupRequest{descriptor}, {}); + for (const auto &found : lookup.allResults()) { + if (auto macro = dyn_cast(found.getValueDecl())) { + auto candidateRoles = macro->getMacroRoles(); + if ((candidateRoles && roles.contains(candidateRoles)) || + // FIXME: `externalMacro` should have all roles. + macro->getBaseIdentifier().str() == "externalMacro") { + choices.push_back(macro); + } + } + } + return choices; +} + +bool +namelookup::isInMacroArgument(SourceFile *sourceFile, SourceLoc loc) { + bool inMacroArgument = false; + + ASTScope::lookupEnclosingMacroScope( + sourceFile, loc, + [&](auto potentialMacro) -> bool { + UnresolvedMacroReference macro(potentialMacro); + + if (macro.getFreestanding()) { + inMacroArgument = true; + } else if (auto *attr = macro.getAttr()) { + auto *moduleScope = sourceFile->getModuleScopeContext(); + auto results = lookupMacros(moduleScope, macro.getMacroName(), + getAttachedMacroRoles()); + inMacroArgument = !results.empty(); + } + + return inMacroArgument; + }); + + return inMacroArgument; +} + /// Call the given function body with each macro declaration and its associated /// role attribute for the given role. /// @@ -2631,7 +2685,7 @@ directReferencesForUnqualifiedTypeLookup(DeclNameRef name, // Manually exclude macro expansions here since the source location // is overridden below. - if (ASTScope::isInMacroArgument(dc->getParentSourceFile(), loc)) + if (namelookup::isInMacroArgument(dc->getParentSourceFile(), loc)) options |= UnqualifiedLookupFlags::ExcludeMacroExpansions; // In a protocol or protocol extension, the 'where' clause can refer to diff --git a/lib/AST/NameLookupRequests.cpp b/lib/AST/NameLookupRequests.cpp index 600a27ba4b283..d934dec0442e6 100644 --- a/lib/AST/NameLookupRequests.cpp +++ b/lib/AST/NameLookupRequests.cpp @@ -545,7 +545,7 @@ static UnqualifiedLookupDescriptor excludeMacrosIfNeeded( UnqualifiedLookupFlags::ExcludeMacroExpansions)) return descriptor; - auto isInMacroArgument = ASTScope::isInMacroArgument( + auto isInMacroArgument = namelookup::isInMacroArgument( descriptor.DC->getParentSourceFile(), descriptor.Loc); if (!isInMacroArgument) @@ -562,7 +562,7 @@ static DirectLookupDescriptor excludeMacrosIfNeeded( NominalTypeDecl::LookupDirectFlags::ExcludeMacroExpansions)) return descriptor; - auto isInMacroArgument = ASTScope::isInMacroArgument( + auto isInMacroArgument = namelookup::isInMacroArgument( descriptor.DC->getParentSourceFile(), loc); if (!isInMacroArgument) @@ -581,7 +581,7 @@ excludeMacrosIfNeeded(const DeclContext *dc, SourceLoc loc, if (options & NL_ExcludeMacroExpansions) return options; - auto isInMacroArgument = ASTScope::isInMacroArgument( + auto isInMacroArgument = namelookup::isInMacroArgument( dc->getParentSourceFile(), loc); if (!isInMacroArgument) diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp index 8286a65c3a1ec..1c71bf20a74de 100644 --- a/lib/Sema/CSGen.cpp +++ b/lib/Sema/CSGen.cpp @@ -3900,7 +3900,7 @@ namespace { FunctionRefKind functionRefKind, MacroRoles roles) { SmallVector choices; - auto results = TypeChecker::lookupMacros( + auto results = namelookup::lookupMacros( CurDC, DeclNameRef(macroName), roles); for (const auto &result : results) { OverloadChoice choice = OverloadChoice(Type(), result, functionRefKind); diff --git a/lib/Sema/PreCheckExpr.cpp b/lib/Sema/PreCheckExpr.cpp index 0fe4d0df8d8d3..08c56383184cf 100644 --- a/lib/Sema/PreCheckExpr.cpp +++ b/lib/Sema/PreCheckExpr.cpp @@ -606,7 +606,7 @@ Expr *TypeChecker::resolveDeclRefExpr(UnresolvedDeclRefExpr *UDRE, // FIXME: Don't perform typo correction inside macro arguments, because it // will invoke synthesizing declarations in this scope, which will attempt to // expand this macro which leads to circular reference errors. - if (!ASTScope::isInMacroArgument(DC->getParentSourceFile(), UDRE->getLoc())) { + if (!namelookup::isInMacroArgument(DC->getParentSourceFile(), UDRE->getLoc())) { TypeChecker::performTypoCorrection(DC, UDRE->getRefKind(), Type(), lookupOptions, corrections); } diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp index 0d039346f9589..b982f0436f629 100644 --- a/lib/Sema/TypeCheckDecl.cpp +++ b/lib/Sema/TypeCheckDecl.cpp @@ -1609,36 +1609,6 @@ TypeChecker::lookupPrecedenceGroup(DeclContext *dc, Identifier name, return PrecedenceGroupLookupResult(dc, name, std::move(groups)); } -SmallVector -TypeChecker::lookupMacros(DeclContext *dc, DeclNameRef macroName, - MacroRoles roles) { - SmallVector choices; - auto moduleScopeDC = dc->getModuleScopeContext(); - ASTContext &ctx = moduleScopeDC->getASTContext(); - - // Macro lookup should always exclude macro expansions; macro - // expansions cannot introduce new macro declarations. Note that - // the source location here doesn't matter. - UnqualifiedLookupDescriptor descriptor{ - macroName, moduleScopeDC, SourceLoc(), - UnqualifiedLookupFlags::ExcludeMacroExpansions - }; - - auto lookup = evaluateOrDefault( - ctx.evaluator, UnqualifiedLookupRequest{descriptor}, {}); - for (const auto &found : lookup.allResults()) { - if (auto macro = dyn_cast(found.getValueDecl())) { - auto candidateRoles = macro->getMacroRoles(); - if ((candidateRoles && roles.contains(candidateRoles)) || - // FIXME: `externalMacro` should have all roles. - macro->getBaseIdentifier().str() == "externalMacro") { - choices.push_back(macro); - } - } - } - return choices; -} - /// Validate the given operator declaration. /// /// This establishes key invariants, such as an InfixOperatorDecl's diff --git a/lib/Sema/TypeCheckMacros.cpp b/lib/Sema/TypeCheckMacros.cpp index 00be8a294574a..c7b0f454aca02 100644 --- a/lib/Sema/TypeCheckMacros.cpp +++ b/lib/Sema/TypeCheckMacros.cpp @@ -1520,7 +1520,7 @@ ConcreteDeclRef ResolveMacroRequest::evaluate(Evaluator &evaluator, // When a macro is not found for a custom attribute, it may be a non-macro. // So bail out to prevent diagnostics from the contraint system. if (macroRef.getAttr()) { - auto foundMacros = TypeChecker::lookupMacros( + auto foundMacros = namelookup::lookupMacros( dc, macroRef.getMacroName(), roles); if (foundMacros.empty()) return ConcreteDeclRef(); diff --git a/lib/Sema/TypeChecker.h b/lib/Sema/TypeChecker.h index 7fe330049c3b4..22aed44dd31fc 100644 --- a/lib/Sema/TypeChecker.h +++ b/lib/Sema/TypeChecker.h @@ -941,9 +941,6 @@ lookupPrecedenceGroupForInfixOperator(DeclContext *dc, Expr *op, bool diagnose); PrecedenceGroupLookupResult lookupPrecedenceGroup(DeclContext *dc, Identifier name, SourceLoc nameLoc); -SmallVector -lookupMacros(DeclContext *dc, DeclNameRef macroName, MacroRoles contexts); - enum class UnsupportedMemberTypeAccessKind : uint8_t { None, TypeAliasOfUnboundGeneric, From 2cc1204afe883939eeda628c773210b6c7267d51 Mon Sep 17 00:00:00 2001 From: Holly Borla Date: Sun, 11 Jun 2023 19:57:28 -0700 Subject: [PATCH 16/37] [Evaluator] Remove hasActiveResolveMacroRequest(). --- include/swift/AST/Evaluator.h | 22 ---------------------- lib/AST/Evaluator.cpp | 5 ----- lib/AST/NameLookupRequests.cpp | 26 ++++++++------------------ 3 files changed, 8 insertions(+), 45 deletions(-) diff --git a/include/swift/AST/Evaluator.h b/include/swift/AST/Evaluator.h index 7e42e727eb61f..2ff80cd6419d5 100644 --- a/include/swift/AST/Evaluator.h +++ b/include/swift/AST/Evaluator.h @@ -208,18 +208,6 @@ class Evaluator { /// is treated as a stack and is used to detect cycles. llvm::SetVector activeRequests; - /// How many `ResolveMacroRequest` requests are active. - /// - /// This allows us to quickly determine whether there is any - /// `ResolveMacroRequest` active in the active request stack. - /// It saves us from a linear scan through `activeRequests` when - /// we need to determine this information. - /// - /// Why on earth would we need to determine this information? - /// Please see the extended comment that goes with the constructor - /// of `UnqualifiedLookupRequest`. - unsigned numActiveResolveMacroRequests = 0; - /// A cache that stores the results of requests. evaluator::RequestCache cache; @@ -342,16 +330,6 @@ class Evaluator { return activeRequests.count(ActiveRequest(request)); } - /// Determine whether there is any active "resolve macro" request - /// on the request stack. - /// - /// Why on earth would we need to determine this information? - /// Please see the extended comment that goes with the constructor - /// of `UnqualifiedLookupRequest`. - bool hasActiveResolveMacroRequest() const { - return numActiveResolveMacroRequests > 0; - } - private: /// Diagnose a cycle detected in the evaluation of the given /// request. diff --git a/lib/AST/Evaluator.cpp b/lib/AST/Evaluator.cpp index 49c1fab72b53c..fdc1b5889b912 100644 --- a/lib/AST/Evaluator.cpp +++ b/lib/AST/Evaluator.cpp @@ -63,8 +63,6 @@ Evaluator::Evaluator(DiagnosticEngine &diags, const LangOptions &opts) bool Evaluator::checkDependency(const ActiveRequest &request) { // Record this as an active request. if (activeRequests.insert(request)) { - if (request.getAs()) - ++numActiveResolveMacroRequests; return false; } @@ -74,9 +72,6 @@ bool Evaluator::checkDependency(const ActiveRequest &request) { } void Evaluator::finishedRequest(const ActiveRequest &request) { - if (request.getAs()) - --numActiveResolveMacroRequests; - assert(activeRequests.back() == request); activeRequests.pop_back(); } diff --git a/lib/AST/NameLookupRequests.cpp b/lib/AST/NameLookupRequests.cpp index d934dec0442e6..33b8d86e4a6f2 100644 --- a/lib/AST/NameLookupRequests.cpp +++ b/lib/AST/NameLookupRequests.cpp @@ -519,24 +519,14 @@ swift::extractNearestSourceLoc(CustomRefCountingOperationDescriptor desc) { // macros, because doing so trivially creates a cyclic dependency amongst the // macro expansions that will be detected by the request-evaluator. // -// Our lookup requests don't always have enough information to answer the -// question "is this part of an argument to a macro?", so we do a much simpler, -// more efficient, and not-entirely-sound hack based on the request-evaluator. -// Specifically, if we are in the process of resolving a macro (which is -// determined by checking for the presence of a `ResolveMacroRequest` in the -// request-evaluator stack), then we adjust the options used for the name -// lookup request we are forming to exclude macro expansions. The evaluation -// of that request will then avoid expanding any macros, and not produce any -// results that involve entries in already-expanded macros. By adjusting the -// request itself, we still distinguish between requests that can and cannot -// look into macro expansions, so it doesn't break caching for those immediate -// requests. -// -// Over time, we should seek to replace this heuristic with a location-based -// check, where we use ASTScope to determine whether we are inside a macro -// argument. This existing check might still be useful because it's going to -// be faster than a location-based query, but the location-based query can be -// fully correct. +// We use source locations to answer the question "is this part of an argument +// to a macro?" through `namelookup::isInMacroArgument`. If the answer is yes, +// then we adjust the options used for the name lookup request we are forming +// to exclude macro expansions. The evaluation of that request will then avoid +// expanding any macros, and not produce any results that involve entries in +// already-expanded macros. By adjusting the request itself, we still +// distinguish between requests that can and cannot look into macro expansions, +// so it doesn't break caching for those immediate requests. /// Exclude macros in the unqualified lookup descriptor if we need to. static UnqualifiedLookupDescriptor excludeMacrosIfNeeded( From cca5a6e524ade74508929da0bd015bf7581f9932 Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Mon, 12 Jun 2023 11:29:53 +0100 Subject: [PATCH 17/37] [SILGen] Emit block after unreachable when emitting if/switch expressions When emitting the underlying `switch` statement for a `switch` expression, we emit an `unreachable` if the subject is uninhabited. Statement emission code can handle this, but expression emission expects an RValue to handed back. To remedy this, emit an unreachable block that we can emit the rest of the expression emission code into. The SILOptimizer will then drop this unreachable block. --- lib/SILGen/SILGenExpr.cpp | 19 +++++++- test/SILGen/if_expr.swift | 8 ++++ test/SILGen/switch_expr.swift | 87 +++++++++++++++++++++++++++++++++++ 3 files changed, 112 insertions(+), 2 deletions(-) diff --git a/lib/SILGen/SILGenExpr.cpp b/lib/SILGen/SILGenExpr.cpp index b55b6667eac89..6fb3c14dcded1 100644 --- a/lib/SILGen/SILGenExpr.cpp +++ b/lib/SILGen/SILGenExpr.cpp @@ -2174,11 +2174,26 @@ RValue RValueEmitter::visitEnumIsCaseExpr(EnumIsCaseExpr *E, RValue RValueEmitter::visitSingleValueStmtExpr(SingleValueStmtExpr *E, SGFContext C) { + auto emitStmt = [&]() { + SGF.emitStmt(E->getStmt()); + + // A switch of an uninhabited value gets emitted as an unreachable. In that + // case we need to emit a block to emit the rest of the expression code + // into. This block will be unreachable, so will be eliminated by the + // SILOptimizer. This is easier than handling unreachability throughout + // expression emission, as eventually SingleValueStmtExprs ought to be able + // to appear in arbitrary expression position. The rest of the emission + // will reference the uninitialized temporary variable, but that's fine + // because it'll be eliminated. + if (!SGF.B.hasValidInsertionPoint()) + SGF.B.emitBlock(SGF.createBasicBlock()); + }; + // A void SingleValueStmtExpr either only has Void expression branches, or // we've decided that it should have purely statement semantics. In either // case, we can just emit the statement as-is, and produce the void rvalue. if (E->getType()->isVoid()) { - SGF.emitStmt(E->getStmt()); + emitStmt(); return SGF.emitEmptyTupleRValue(E, C); } auto &lowering = SGF.getTypeLowering(E->getType()); @@ -2201,7 +2216,7 @@ RValue RValueEmitter::visitSingleValueStmtExpr(SingleValueStmtExpr *E, // Push the initialization for branches of the statement to initialize into. SGF.SingleValueStmtInitStack.push_back(std::move(initInfo)); SWIFT_DEFER { SGF.SingleValueStmtInitStack.pop_back(); }; - SGF.emitStmt(E->getStmt()); + emitStmt(); return RValue(SGF, E, SGF.emitManagedRValueWithCleanup(resultAddr)); } diff --git a/test/SILGen/if_expr.swift b/test/SILGen/if_expr.swift index b85152bccce87..30a87fd3f72da 100644 --- a/test/SILGen/if_expr.swift +++ b/test/SILGen/if_expr.swift @@ -500,3 +500,11 @@ struct TestLValues { opt![keyPath: kp] = if .random() { 1 } else { throw Err() } } } + +func testNever1() -> Never { + if case let x = fatalError() { x } else { fatalError() } +} + +func testNever2() -> Never { + if .random() { fatalError() } else { fatalError() } +} diff --git a/test/SILGen/switch_expr.swift b/test/SILGen/switch_expr.swift index 310dc90329ab3..c590be65d2597 100644 --- a/test/SILGen/switch_expr.swift +++ b/test/SILGen/switch_expr.swift @@ -616,3 +616,90 @@ func exprPatternInClosure() { } } } + +func testNeverSwitch1() { + let x = switch fatalError() {} + return x +} + +func testNeverSwitch2() -> Never { + let x = switch fatalError() { + case let x: x + } + return x +} + +func testNeverSwitch3() -> Int { + let x = switch fatalError() { + case fatalError(): 0 + case _ where .random(): 1 + default: 2 + } + return x +} + +func testNeverSwitch4() { + let x: Void + x = switch fatalError() {} + return x +} + +func testNeverSwitch5() -> Never { + let x: Never + x = switch fatalError() { + case let x: x + } + return x +} + +func testNeverSwitch6() -> Int { + let x: Int + x = switch fatalError() { + case fatalError(): 0 + case _ where .random(): 1 + default: 2 + } + return x +} + +func testNeverSwitch7() { + let _ = switch fatalError() {} + let _ = switch fatalError() { case let x: x } + let _ = switch fatalError() { default: "" } +} + +func testNeverSwitch8() { + let _ = switch fatalError() { default: C() } +} + +func testNeverSwitch9() { + let i = switch Bool.random() { + case true: + switch fatalError() {} + case false: + switch fatalError() {} + } + return i +} + +func testNeverSwitch10() -> Never { + switch fatalError() {} +} + +func testNeverSwitch11() { + return switch fatalError() {} +} + +func testNeverSwitch12() -> Never { + return switch fatalError() { case let x: x } +} + +func testNeverSwitch13() { + return switch fatalError() { case let x: x } +} + +extension Never { + init(value: Self) { + self = switch value { case let v: v } + } +} From 490c52810469b01c7063a50e9e6af876f46e391a Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Mon, 12 Jun 2023 07:34:36 -0700 Subject: [PATCH 18/37] Windows: add some defines from `WinUser.h` Add the windows message queue status flags macros. This should allow the use of the macros when writing Windows code. --- stdlib/public/Windows/WinSDK.swift | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/stdlib/public/Windows/WinSDK.swift b/stdlib/public/Windows/WinSDK.swift index 81ca84b32ecff..ac2319415fcaf 100644 --- a/stdlib/public/Windows/WinSDK.swift +++ b/stdlib/public/Windows/WinSDK.swift @@ -77,6 +77,20 @@ public var FIONBIO: Int32 { public var CW_USEDEFAULT: Int32 { Int32(bitPattern: 2147483648) } + +public var QS_MOUSE: UINT { + UINT(QS_MOUSEMOVE | QS_MOUSEBUTTON) +} +public var QS_INPUT: UINT { + QS_MOUSE | UINT(QS_KEY | QS_RAWINPUT | QS_TOUCH | QS_POINTER) +} +public var QS_ALLEVENTS: UINT { + QS_INPUT | UINT(QS_POSTMESSAGE | QS_TIMER | QS_PAINT | QS_HOTKEY) +} +public var QS_ALLINPUT: UINT { + QS_INPUT | UINT(QS_POSTMESSAGE | QS_TIMER | QS_PAINT | QS_HOTKEY | QS_SENDMESSAGE) +} + public var WS_OVERLAPPEDWINDOW: UINT { UINT(WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX) } From 1616e167b94f3d47b81058d4aaa4ca3d19f40934 Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Mon, 12 Jun 2023 18:27:24 +0100 Subject: [PATCH 19/37] [CS] Walk into patterns when looking for closure referenced vars Previously we would skip over ExprPatterns, but we need to ensure that we walk them, as they may have interesting variable references that the closure needs to be connected to the type variables for. rdar://110617471 --- lib/Sema/CSGen.cpp | 4 ---- test/Constraints/rdar110617471.swift | 25 +++++++++++++++++++++++++ 2 files changed, 25 insertions(+), 4 deletions(-) create mode 100644 test/Constraints/rdar110617471.swift diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp index c30c94dbc2792..0f2ea6892f750 100644 --- a/lib/Sema/CSGen.cpp +++ b/lib/Sema/CSGen.cpp @@ -2949,10 +2949,6 @@ namespace { PreWalkAction walkToDeclPre(Decl *D) override { return Action::VisitChildrenIf(isa(D)); } - - PreWalkResult walkToPatternPre(Pattern *P) override { - return Action::SkipChildren(P); - } } collectVarRefs(CS); // Walk the capture list if this closure has one, because it could diff --git a/test/Constraints/rdar110617471.swift b/test/Constraints/rdar110617471.swift new file mode 100644 index 0000000000000..305197320f2ec --- /dev/null +++ b/test/Constraints/rdar110617471.swift @@ -0,0 +1,25 @@ +// RUN: %target-typecheck-verify-swift + +// rdar://110617471: Make sure we can type-check this. +class C { + var prop = 0 +} + +func foo(_ fn: () -> Void) {} + +class D { + let c = C() + + func bar() { + foo { [c] in + foo { + switch 0 { + case c.prop: + break + default: + break + } + } + } + } +} From f18293bf7c01991e16ae480bd6f2bd61e2c0a6e1 Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Mon, 12 Jun 2023 18:27:26 +0100 Subject: [PATCH 20/37] [CS] Walk ExprPattern conjunction elements when finding type variables Apply the same logic that we apply to other conjunction elements, to make sure that e.g property wrapper projected values work correctly. rdar://110649179 --- lib/Sema/CSSyntacticElement.cpp | 4 +++- test/Constraints/issue-66561.swift | 36 ++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 test/Constraints/issue-66561.swift diff --git a/lib/Sema/CSSyntacticElement.cpp b/lib/Sema/CSSyntacticElement.cpp index 8fdec6b319a5d..e51026474ca67 100644 --- a/lib/Sema/CSSyntacticElement.cpp +++ b/lib/Sema/CSSyntacticElement.cpp @@ -2625,8 +2625,10 @@ void ConjunctionElement::findReferencedVariables( } if (element.is() || element.is() || - element.is() || element.isStmt(StmtKind::Return)) + element.is() || element.isPattern(PatternKind::Expr) || + element.isStmt(StmtKind::Return)) { element.walk(refFinder); + } } Type constraints::isPlaceholderVar(PatternBindingDecl *PB) { diff --git a/test/Constraints/issue-66561.swift b/test/Constraints/issue-66561.swift new file mode 100644 index 0000000000000..e1293ff0f6c47 --- /dev/null +++ b/test/Constraints/issue-66561.swift @@ -0,0 +1,36 @@ +// RUN: %target-typecheck-verify-swift + +// https://github.com/apple/swift/issues/66561 + +@propertyWrapper +struct WrapperValue { + var value: Value + init(wrappedValue: Value) { + self.value = wrappedValue + } + + var projectedValue: Self { + return self + } + + var wrappedValue: Value { + get { + self.value + } + set { + self.value = newValue + } + } +} + +func test() { + let _ = { + @WrapperValue var value: Bool = false + switch value { + case $value.wrappedValue: + break + default: + break + } + } +} From 7e632c0ee0ee4db011718d499a4c306b84cbb5ed Mon Sep 17 00:00:00 2001 From: Alastair Houghton Date: Mon, 12 Jun 2023 18:54:05 +0100 Subject: [PATCH 21/37] [Backtracing][Linux] Fix Ubuntu 20.04-aarch64 CI failures. These seem to be related to signal handling issues in threads that have been started presumably by the C library or some other library. Primarily this appears to affect Ubuntu 20.04 on aarch64, though I have seen sporadic issues on 18.04 as well. We address the problem by making the thread suspension mechanism more robust in the face of threads with masked signals. rdar://110653167 --- stdlib/public/runtime/CrashHandlerLinux.cpp | 177 ++++++++++++++++++-- 1 file changed, 161 insertions(+), 16 deletions(-) diff --git a/stdlib/public/runtime/CrashHandlerLinux.cpp b/stdlib/public/runtime/CrashHandlerLinux.cpp index 2913245b97566..526b7a7a3c04e 100644 --- a/stdlib/public/runtime/CrashHandlerLinux.cpp +++ b/stdlib/public/runtime/CrashHandlerLinux.cpp @@ -62,10 +62,12 @@ void resume_other_threads(); void take_thread_lock(); void release_thread_lock(); void notify_paused(); +uint32_t currently_paused(); void wait_paused(uint32_t expected, const struct timespec *timeout); int memserver_start(); int memserver_entry(void *); bool run_backtracer(int fd); +void format_unsigned(unsigned u, char buffer[22]); ssize_t safe_read(int fd, void *buf, size_t len) { uint8_t *ptr = (uint8_t *)buf; @@ -88,7 +90,7 @@ ssize_t safe_read(int fd, void *buf, size_t len) { } ssize_t safe_write(int fd, const void *buf, size_t len) { - const uint8_t *ptr = (uint8_t *)buf; + const uint8_t *ptr = (const uint8_t *)buf; const uint8_t *end = ptr + len; ssize_t total = 0; @@ -308,6 +310,124 @@ getdents(int fd, void *buf, size_t bufsiz) return syscall(SYS_getdents64, fd, buf, bufsiz); } +/* Find the signal to use to suspend the given thread. + + Sadly, libdispatch blocks SIGUSR1, so we can't just use that everywhere; + and on Ubuntu 20.04 *something* is starting a thread with SIGPROF blocked, + so we can't just use that either. + + We also can't modify the signal mask for another thread, since there is + no syscall to do that. + + As a workaround, read /proc//task//status to find the signal + mask so that we can decide which signal to try and send. */ +int +signal_for_suspend(int pid, int tid) +{ + char pid_buffer[22]; + char tid_buffer[22]; + + format_unsigned((unsigned)pid, pid_buffer); + format_unsigned((unsigned)tid, tid_buffer); + + char status_file[6 + 22 + 6 + 22 + 7 + 1]; + + strcpy(status_file, "/proc/"); // 6 + strcat(status_file, pid_buffer); // 22 + strcat(status_file, "/task/"); // 6 + strcat(status_file, tid_buffer); // 22 + strcat(status_file, "/status"); // 7 + 1 for NUL + + int fd = open(status_file, O_RDONLY); + if (fd < 0) + return -1; + + enum match_state { + Matching, + EatLine, + AfterMatch, + InHex, + + // states after this terminate the loop + Done, + Bad + }; + + enum match_state state = Matching; + const char *toMatch = "SigBlk:"; + const char *matchPtr = toMatch; + char buffer[256]; + uint64_t mask = 0; + ssize_t count; + while (state < Done && (count = read(fd, buffer, sizeof(buffer))) > 0) { + char *ptr = buffer; + char *end = buffer + count; + + while (state < Done && ptr < end) { + int ch = *ptr++; + + switch (state) { + case Matching: + if (ch != *matchPtr) { + state = EatLine; + matchPtr = toMatch; + } else if (!*++matchPtr) { + state = AfterMatch; + } + break; + case EatLine: + if (ch == '\n') + state = Matching; + break; + case AfterMatch: + if (ch == ' ' || ch == '\t') { + break; + } + state = InHex; + SWIFT_FALLTHROUGH; + case InHex: + if (ch >= '0' && ch <= '9') { + mask = (mask << 4) | (ch - '0'); + } else if (ch >= 'a' && ch <= 'f') { + mask = (mask << 4) | (ch - 'a' + 10); + } else if (ch >= 'A' && ch <= 'F') { + mask = (mask << 4) | (ch - 'A' + 10); + } else if (ch == '\n') { + state = Done; + break; + } else { + state = Bad; + } + break; + case Done: + case Bad: + break; + } + } + } + + close(fd); + + if (state == Done) { + if (!(mask & (1 << (SIGUSR1 - 1)))) + return SIGUSR1; + else if (!(mask & (1 << (SIGUSR2 - 1)))) + return SIGUSR2; + else if (!(mask & (1 << (SIGPROF - 1)))) + return SIGPROF; + else + return -1; + } + + return -1; +} + +// Write a string to stderr +void +warn(const char *str) { + write(STDERR_FILENO, str, strlen(str)); +} + /* Stop all other threads in this process; we do this by establishing a signal handler for SIGPROF, then iterating through the threads sending SIGPROF. @@ -321,7 +441,7 @@ getdents(int fd, void *buf, size_t bufsiz) void suspend_other_threads(struct thread *self) { - struct sigaction sa, sa_old; + struct sigaction sa, sa_old_prof, sa_old_usr1, sa_old_usr2; // Take the lock take_thread_lock(); @@ -329,13 +449,15 @@ suspend_other_threads(struct thread *self) // Start the thread list with this thread reset_threads(self); - // Swap out the SIGPROF signal handler first + // Swap out the signal handlers first sigfillset(&sa.sa_mask); - sa.sa_flags = SA_NODEFER; + sa.sa_flags = 0; sa.sa_handler = NULL; sa.sa_sigaction = pause_thread; - sigaction(SIGPROF, &sa, &sa_old); + sigaction(SIGPROF, &sa, &sa_old_prof); + sigaction(SIGUSR1, &sa, &sa_old_usr1); + sigaction(SIGUSR2, &sa, &sa_old_usr2); /* Now scan /proc/self/task to get the tids of the threads in this process. We need to ignore our own thread. */ @@ -346,11 +468,14 @@ suspend_other_threads(struct thread *self) size_t offset = 0; size_t count = 0; - uint32_t thread_count = 0; - uint32_t old_thread_count; + unsigned max_loops = 15; + uint32_t pending = 0; do { - old_thread_count = thread_count; + uint32_t paused = currently_paused(); + + pending = 0; + lseek(fd, 0, SEEK_SET); for (;;) { @@ -372,21 +497,35 @@ suspend_other_threads(struct thread *self) int tid = atoi(dp->d_name); if ((int64_t)tid != self->tid && !seen_thread(tid)) { - tgkill(our_pid, tid, SIGPROF); - ++thread_count; + int sig_to_use = signal_for_suspend(our_pid, tid); + + if (sig_to_use > 0) { + tgkill(our_pid, tid, sig_to_use); + ++pending; + } else { + warn("swift-runtime: unable to suspend thread "); + warn(dp->d_name); + warn("\n"); + } } } - // Wait up to 5 seconds for the threads to pause - struct timespec timeout = { 5, 0 }; - wait_paused(thread_count, &timeout); - } while (old_thread_count != thread_count); + // If we find no new threads, we're done + if (!pending) + break; + + // Wait for the threads to suspend + struct timespec timeout = { 2, 0 }; + wait_paused(paused + pending, &timeout); + } while (max_loops--); // Close the directory close(fd); - // Finally, reset the signal handler - sigaction(SIGPROF, &sa_old, NULL); + // Finally, reset the signal handlers + sigaction(SIGPROF, &sa_old_prof, NULL); + sigaction(SIGUSR1, &sa_old_usr1, NULL); + sigaction(SIGUSR2, &sa_old_usr2, NULL); } void @@ -441,6 +580,12 @@ notify_paused() futex(&threads_paused, FUTEX_WAKE, 1, NULL, NULL, 0); } +uint32_t +currently_paused() +{ + return __atomic_load_n(&threads_paused, __ATOMIC_ACQUIRE); +} + void wait_paused(uint32_t expected, const struct timespec *timeout) { From b1f99b8e934c7ded4b24385c8e3b11044641eb1c Mon Sep 17 00:00:00 2001 From: Steven Wu Date: Mon, 12 Jun 2023 10:55:53 -0700 Subject: [PATCH 22/37] [CAS] swift dependency scanning using CAS for compiler caching (#66366) Teach swift dependency scanner to use CAS to capture the full dependencies for a build and construct build commands with immutable inputs from CAS. This allows swift compilation caching using CAS. --- .../swift-c/DependencyScan/DependencyScan.h | 58 ++- include/swift/AST/ModuleDependencies.h | 322 +++++++++++---- include/swift/Basic/LangOptions.h | 6 + include/swift/ClangImporter/ClangImporter.h | 5 + .../swift/DependencyScan/DependencyScanImpl.h | 24 ++ .../SerializedModuleDependencyCacheFormat.h | 19 +- include/swift/Frontend/CachingUtils.h | 27 ++ include/swift/Frontend/FrontendOptions.h | 5 +- .../swift/Frontend/ModuleInterfaceLoader.h | 101 ++++- include/swift/Option/Options.td | 13 + .../Serialization/ModuleDependencyScanner.h | 27 +- lib/AST/ModuleDependencies.cpp | 244 ++++++++++- lib/AST/ModuleLoader.cpp | 4 +- lib/ClangImporter/ClangImporter.cpp | 33 +- .../ClangModuleDependencyScanner.cpp | 172 +++++++- lib/DependencyScan/DependencyScanningTool.cpp | 7 +- .../ModuleDependencyCacheSerialization.cpp | 192 ++++++--- lib/DependencyScan/ScanDependencies.cpp | 379 +++++++++++++++--- .../ArgsToFrontendOptionsConverter.cpp | 7 +- lib/Frontend/CachingUtils.cpp | 123 ++++++ lib/Frontend/CompilerInvocation.cpp | 18 +- lib/Frontend/Frontend.cpp | 77 ++-- lib/Frontend/ModuleInterfaceLoader.cpp | 371 ++++++++++++++++- lib/Serialization/ModuleDependencyScanner.cpp | 29 +- lib/Serialization/SerializedModuleLoader.cpp | 3 +- test/CAS/Inputs/SwiftDepsExtractor.py | 34 ++ test/CAS/binary_module_deps.swift | 41 ++ test/CAS/cas-explicit-module-map.swift | 129 ++++++ test/CAS/cas_fs.swift | 1 - test/CAS/module_deps.swift | 195 +++++++++ test/CAS/module_deps_include_tree.swift | 190 +++++++++ test/CMakeLists.txt | 1 + tools/libSwiftScan/libSwiftScan.cpp | 100 +++++ tools/libSwiftScan/libSwiftScan.exports | 10 + 34 files changed, 2670 insertions(+), 297 deletions(-) create mode 100755 test/CAS/Inputs/SwiftDepsExtractor.py create mode 100644 test/CAS/binary_module_deps.swift create mode 100644 test/CAS/cas-explicit-module-map.swift create mode 100644 test/CAS/module_deps.swift create mode 100644 test/CAS/module_deps_include_tree.swift diff --git a/include/swift-c/DependencyScan/DependencyScan.h b/include/swift-c/DependencyScan/DependencyScan.h index c08a6fb7482c3..998c8309bf352 100644 --- a/include/swift-c/DependencyScan/DependencyScan.h +++ b/include/swift-c/DependencyScan/DependencyScan.h @@ -25,7 +25,7 @@ /// SWIFTSCAN_VERSION_MINOR should increase when there are API additions. /// SWIFTSCAN_VERSION_MAJOR is intended for "major" source/ABI breaking changes. #define SWIFTSCAN_VERSION_MAJOR 0 -#define SWIFTSCAN_VERSION_MINOR 3 +#define SWIFTSCAN_VERSION_MINOR 4 SWIFTSCAN_BEGIN_DECLS @@ -139,6 +139,10 @@ SWIFTSCAN_PUBLIC swiftscan_string_set_t * swiftscan_swift_textual_detail_get_command_line( swiftscan_module_details_t details); +SWIFTSCAN_PUBLIC swiftscan_string_set_t * +swiftscan_swift_textual_detail_get_bridging_pch_command_line( + swiftscan_module_details_t details); + SWIFTSCAN_PUBLIC swiftscan_string_set_t * swiftscan_swift_textual_detail_get_extra_pcm_args( swiftscan_module_details_t details); @@ -154,6 +158,14 @@ SWIFTSCAN_PUBLIC swiftscan_string_set_t * swiftscan_swift_textual_detail_get_swift_overlay_dependencies( swiftscan_module_details_t details); +SWIFTSCAN_PUBLIC swiftscan_string_ref_t +swiftscan_swift_textual_detail_get_cas_fs_root_id( + swiftscan_module_details_t details); + +SWIFTSCAN_PUBLIC swiftscan_string_ref_t +swiftscan_swift_textual_detail_get_module_cache_key( + swiftscan_module_details_t details); + //=== Swift Binary Module Details query APIs ------------------------------===// SWIFTSCAN_PUBLIC swiftscan_string_ref_t @@ -172,6 +184,10 @@ SWIFTSCAN_PUBLIC bool swiftscan_swift_binary_detail_get_is_framework( swiftscan_module_details_t details); +SWIFTSCAN_PUBLIC swiftscan_string_ref_t +swiftscan_swift_binary_detail_get_module_cache_key( + swiftscan_module_details_t details); + //=== Swift Placeholder Module Details query APIs -------------------------===// SWIFTSCAN_PUBLIC swiftscan_string_ref_t @@ -200,6 +216,12 @@ swiftscan_clang_detail_get_command_line(swiftscan_module_details_t details); SWIFTSCAN_PUBLIC swiftscan_string_set_t * swiftscan_clang_detail_get_captured_pcm_args(swiftscan_module_details_t details); +SWIFTSCAN_PUBLIC swiftscan_string_ref_t +swiftscan_clang_detail_get_cas_fs_root_id(swiftscan_module_details_t details); + +SWIFTSCAN_PUBLIC swiftscan_string_ref_t +swiftscan_clang_detail_get_module_cache_key(swiftscan_module_details_t details); + //=== Batch Scan Input Functions ------------------------------------------===// /// Create an \c swiftscan_batch_scan_input_t instance. @@ -402,6 +424,40 @@ swiftscan_scanner_cache_reset(swiftscan_scanner_t scanner); /// An entry point to invoke the compiler via a library call. SWIFTSCAN_PUBLIC int invoke_swift_compiler(int argc, const char **argv); +//=== Scanner CAS Operations ----------------------------------------------===// + +/// Opaque container for a CAS instance that includes both ObjectStore and +/// ActionCache. +typedef struct swiftscan_cas_s *swiftscan_cas_t; + +/// Enum types for output types for cache key computation. +/// TODO: complete the list. +typedef enum { + SWIFTSCAN_OUTPUT_TYPE_OBJECT = 0, + SWIFTSCAN_OUTPUT_TYPE_SWIFTMODULE = 1, + SWIFTSCAN_OUTPUT_TYPE_SWIFTINTERFACE = 2, + SWIFTSCAN_OUTPUT_TYPE_SWIFTPRIAVEINTERFACE = 3, + SWIFTSCAN_OUTPUT_TYPE_CLANG_MODULE = 4, + SWIFTSCAN_OUTPUT_TYPE_CLANG_PCH = 5 +} swiftscan_output_kind_t; + +/// Create a \c cas instance that points to path. +SWIFTSCAN_PUBLIC swiftscan_cas_t swiftscan_cas_create(const char *path); + +/// Dispose the \c cas instance. +SWIFTSCAN_PUBLIC void swiftscan_cas_dispose(swiftscan_cas_t cas); + +/// Store content into CAS. Return \c CASID as string. +SWIFTSCAN_PUBLIC swiftscan_string_ref_t swiftscan_cas_store(swiftscan_cas_t cas, + uint8_t *data, + unsigned size); + +/// Compute \c CacheKey for output of \c kind from the compiler invocation \c +/// argc and \c argv with \c input. Return \c CacheKey as string. +SWIFTSCAN_PUBLIC swiftscan_string_ref_t +swiftscan_compute_cache_key(swiftscan_cas_t cas, int argc, const char **argv, + const char *input, swiftscan_output_kind_t kind); + //===----------------------------------------------------------------------===// SWIFTSCAN_END_DECLS diff --git a/include/swift/AST/ModuleDependencies.h b/include/swift/AST/ModuleDependencies.h index 8fb3c39faa1da..98dbc1de8fda6 100644 --- a/include/swift/AST/ModuleDependencies.h +++ b/include/swift/AST/ModuleDependencies.h @@ -23,9 +23,16 @@ #include "clang/Tooling/DependencyScanning/DependencyScanningService.h" #include "clang/Tooling/DependencyScanning/DependencyScanningTool.h" #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/IntrusiveRefCntPtr.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/StringSet.h" +#include "llvm/CAS/CASProvidingFileSystem.h" +#include "llvm/CAS/CASReference.h" +#include "llvm/CAS/CachingOnDiskFileSystem.h" +#include "llvm/CAS/ObjectStore.h" #include "llvm/Support/Mutex.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/VirtualFileSystem.h" #include #include #include @@ -99,8 +106,10 @@ class ModuleDependencyInfoStorageBase { const ModuleDependencyKind dependencyKind; ModuleDependencyInfoStorageBase(ModuleDependencyKind dependencyKind, + StringRef moduleCacheKey = "", bool resolved = false) - : dependencyKind(dependencyKind), resolved(resolved) { } + : dependencyKind(dependencyKind), moduleCacheKey(moduleCacheKey.str()), + resolved(resolved) {} virtual ModuleDependencyInfoStorageBase *clone() const = 0; @@ -117,12 +126,20 @@ class ModuleDependencyInfoStorageBase { /// The set of modules on which this module depends, resolved /// to Module IDs, qualified by module kind: Swift, Clang, etc. std::vector resolvedModuleDependencies; + + /// The cache key for the produced module. + std::string moduleCacheKey; + bool resolved; }; struct CommonSwiftTextualModuleDependencyDetails { - CommonSwiftTextualModuleDependencyDetails(ArrayRef extraPCMArgs) - : extraPCMArgs(extraPCMArgs.begin(), extraPCMArgs.end()) {} + CommonSwiftTextualModuleDependencyDetails( + ArrayRef extraPCMArgs, ArrayRef buildCommandLine, + const std::string &CASFileSystemRootID) + : extraPCMArgs(extraPCMArgs.begin(), extraPCMArgs.end()), + buildCommandLine(buildCommandLine.begin(), buildCommandLine.end()), + CASFileSystemRootID(CASFileSystemRootID) {} /// To build a PCM to be used by this Swift module, we need to append these /// arguments to the generic PCM build arguments reported from the dependency @@ -141,6 +158,16 @@ struct CommonSwiftTextualModuleDependencyDetails { /// Dependencies comprised of Swift overlay modules of direct and /// transitive Clang dependencies. std::vector swiftOverlayDependencies; + + /// The Swift frontend invocation arguments to build the Swift module from the + /// interface. + std::vector buildCommandLine; + + /// CASID for the Root of CASFS. Empty if CAS is not used. + std::string CASFileSystemRootID; + + /// CASID for the Root of bridgingHeaderClangIncludeTree. Empty if not used. + std::string CASBridgingHeaderIncludeTreeRootID; }; /// Describes the dependencies of a Swift module described by an Swift interface file. @@ -158,10 +185,6 @@ class SwiftInterfaceModuleDependenciesStorage : /// Potentially ready-to-use compiled modules for the interface file. const std::vector compiledModuleCandidates; - /// The Swift frontend invocation arguments to build the Swift module from the - /// interface. - std::vector buildCommandLine; - /// The hash value that will be used for the generated module const std::string contextHash; @@ -172,22 +195,20 @@ class SwiftInterfaceModuleDependenciesStorage : CommonSwiftTextualModuleDependencyDetails textualModuleDetails; SwiftInterfaceModuleDependenciesStorage( - const std::string moduleOutputPath, - const std::string swiftInterfaceFile, + const std::string &moduleOutputPath, + const std::string &swiftInterfaceFile, ArrayRef compiledModuleCandidates, - ArrayRef buildCommandLine, - ArrayRef extraPCMArgs, - StringRef contextHash, - bool isFramework - ) : ModuleDependencyInfoStorageBase(ModuleDependencyKind::SwiftInterface), - moduleOutputPath(moduleOutputPath), - swiftInterfaceFile(swiftInterfaceFile), - compiledModuleCandidates(compiledModuleCandidates.begin(), - compiledModuleCandidates.end()), - buildCommandLine(buildCommandLine.begin(), buildCommandLine.end()), - contextHash(contextHash), isFramework(isFramework), - textualModuleDetails(extraPCMArgs) - {} + ArrayRef buildCommandLine, ArrayRef extraPCMArgs, + StringRef contextHash, bool isFramework, const std::string &RootID, + const std::string &moduleCacheKey) + : ModuleDependencyInfoStorageBase(ModuleDependencyKind::SwiftInterface, + moduleCacheKey), + moduleOutputPath(moduleOutputPath), + swiftInterfaceFile(swiftInterfaceFile), + compiledModuleCandidates(compiledModuleCandidates.begin(), + compiledModuleCandidates.end()), + contextHash(contextHash), isFramework(isFramework), + textualModuleDetails(extraPCMArgs, buildCommandLine, RootID) {} ModuleDependencyInfoStorageBase *clone() const override { return new SwiftInterfaceModuleDependenciesStorage(*this); @@ -198,7 +219,7 @@ class SwiftInterfaceModuleDependenciesStorage : } void updateCommandLine(const std::vector &newCommandLine) { - buildCommandLine = newCommandLine; + textualModuleDetails.buildCommandLine = newCommandLine; } }; @@ -218,11 +239,18 @@ class SwiftSourceModuleDependenciesStorage : /// Collection of module imports that were detected to be `@Testable` llvm::StringSet<> testableImports; + /// The Swift frontend invocation arguments to build bridging header. + std::vector bridgingHeaderBuildCommandLine; + SwiftSourceModuleDependenciesStorage( - ArrayRef extraPCMArgs - ) : ModuleDependencyInfoStorageBase(ModuleDependencyKind::SwiftSource), - textualModuleDetails(extraPCMArgs), - testableImports(llvm::StringSet<>()) {} + const std::string &RootID, ArrayRef buildCommandLine, + ArrayRef bridgingHeaderBuildCommandLine, + ArrayRef extraPCMArgs) + : ModuleDependencyInfoStorageBase(ModuleDependencyKind::SwiftSource), + textualModuleDetails(extraPCMArgs, buildCommandLine, RootID), + testableImports(llvm::StringSet<>()), + bridgingHeaderBuildCommandLine(bridgingHeaderBuildCommandLine.begin(), + bridgingHeaderBuildCommandLine.end()) {} ModuleDependencyInfoStorageBase *clone() const override { return new SwiftSourceModuleDependenciesStorage(*this); @@ -232,6 +260,15 @@ class SwiftSourceModuleDependenciesStorage : return base->dependencyKind == ModuleDependencyKind::SwiftSource; } + void updateCommandLine(const std::vector &newCommandLine) { + textualModuleDetails.buildCommandLine = newCommandLine; + } + + void updateBridgingHeaderCommandLine( + const std::vector &newCommandLine) { + bridgingHeaderBuildCommandLine = newCommandLine; + } + void addTestableImport(ImportPath::Module module) { testableImports.insert(module.front().Item.str()); } @@ -245,12 +282,12 @@ class SwiftBinaryModuleDependencyStorage : public ModuleDependencyInfoStorageBas SwiftBinaryModuleDependencyStorage(const std::string &compiledModulePath, const std::string &moduleDocPath, const std::string &sourceInfoPath, - const bool isFramework) - : ModuleDependencyInfoStorageBase(ModuleDependencyKind::SwiftBinary), - compiledModulePath(compiledModulePath), - moduleDocPath(moduleDocPath), - sourceInfoPath(sourceInfoPath), - isFramework(isFramework) {} + const bool isFramework, + const std::string &moduleCacheKey) + : ModuleDependencyInfoStorageBase(ModuleDependencyKind::SwiftBinary, + moduleCacheKey), + compiledModulePath(compiledModulePath), moduleDocPath(moduleDocPath), + sourceInfoPath(sourceInfoPath), isFramework(isFramework) {} ModuleDependencyInfoStorageBase *clone() const override { return new SwiftBinaryModuleDependencyStorage(*this); @@ -288,7 +325,7 @@ class ClangModuleDependencyStorage : public ModuleDependencyInfoStorageBase { const std::string contextHash; /// Partial (Clang) command line that can be used to build this module. - const std::vector nonPathCommandLine; + std::vector buildCommandLine; /// The file dependencies const std::vector fileDependencies; @@ -297,20 +334,28 @@ class ClangModuleDependencyStorage : public ModuleDependencyInfoStorageBase { /// as found by the scanning action that discovered it const std::vector capturedPCMArgs; - ClangModuleDependencyStorage( - const std::string &pcmOutputPath, - const std::string &moduleMapFile, - const std::string &contextHash, - const std::vector &nonPathCommandLine, - const std::vector &fileDependencies, - const std::vector &capturedPCMArgs - ) : ModuleDependencyInfoStorageBase(ModuleDependencyKind::Clang), - pcmOutputPath(pcmOutputPath), - moduleMapFile(moduleMapFile), - contextHash(contextHash), - nonPathCommandLine(nonPathCommandLine), - fileDependencies(fileDependencies), - capturedPCMArgs(capturedPCMArgs) {} + /// CASID for the Root of CASFS. Empty if CAS is not used. + std::string CASFileSystemRootID; + + /// CASID for the Root of ClangIncludeTree. Empty if not used. + std::string CASClangIncludeTreeRootID; + + ClangModuleDependencyStorage(const std::string &pcmOutputPath, + const std::string &moduleMapFile, + const std::string &contextHash, + const std::vector &buildCommandLine, + const std::vector &fileDependencies, + const std::vector &capturedPCMArgs, + const std::string &CASFileSystemRootID, + const std::string &clangIncludeTreeRoot, + const std::string &moduleCacheKey) + : ModuleDependencyInfoStorageBase(ModuleDependencyKind::Clang, + moduleCacheKey), + pcmOutputPath(pcmOutputPath), moduleMapFile(moduleMapFile), + contextHash(contextHash), buildCommandLine(buildCommandLine), + fileDependencies(fileDependencies), capturedPCMArgs(capturedPCMArgs), + CASFileSystemRootID(CASFileSystemRootID), + CASClangIncludeTreeRootID(clangIncludeTreeRoot) {} ModuleDependencyInfoStorageBase *clone() const override { return new ClangModuleDependencyStorage(*this); @@ -319,6 +364,10 @@ class ClangModuleDependencyStorage : public ModuleDependencyInfoStorageBase { static bool classof(const ModuleDependencyInfoStorageBase *base) { return base->dependencyKind == ModuleDependencyKind::Clang; } + + void updateCommandLine(const std::vector &newCommandLine) { + buildCommandLine = newCommandLine; + } }; /// Describes an placeholder Swift module dependency module stub. @@ -381,35 +430,44 @@ class ModuleDependencyInfo { /// Describe the module dependencies for a Swift module that can be /// built from a Swift interface file (\c .swiftinterface). - static ModuleDependencyInfo forSwiftInterfaceModule( - const std::string &moduleOutputPath, - const std::string &swiftInterfaceFile, - ArrayRef compiledCandidates, - ArrayRef buildCommands, - ArrayRef extraPCMArgs, - StringRef contextHash, - bool isFramework) { + static ModuleDependencyInfo + forSwiftInterfaceModule(const std::string &moduleOutputPath, + const std::string &swiftInterfaceFile, + ArrayRef compiledCandidates, + ArrayRef buildCommands, + ArrayRef extraPCMArgs, + StringRef contextHash, bool isFramework, + const std::string &CASFileSystemRootID, + const std::string &moduleCacheKey) { return ModuleDependencyInfo( std::make_unique( - moduleOutputPath, swiftInterfaceFile, compiledCandidates, buildCommands, - extraPCMArgs, contextHash, isFramework)); + moduleOutputPath, swiftInterfaceFile, compiledCandidates, + buildCommands, extraPCMArgs, contextHash, isFramework, + CASFileSystemRootID, moduleCacheKey)); } /// Describe the module dependencies for a serialized or parsed Swift module. - static ModuleDependencyInfo forSwiftBinaryModule( - const std::string &compiledModulePath, - const std::string &moduleDocPath, - const std::string &sourceInfoPath, - bool isFramework) { + static ModuleDependencyInfo + forSwiftBinaryModule(const std::string &compiledModulePath, + const std::string &moduleDocPath, + const std::string &sourceInfoPath, bool isFramework, + const std::string &moduleCacheKey) { return ModuleDependencyInfo( std::make_unique( - compiledModulePath, moduleDocPath, sourceInfoPath, isFramework)); + compiledModulePath, moduleDocPath, sourceInfoPath, isFramework, + moduleCacheKey)); } /// Describe the main Swift module. - static ModuleDependencyInfo forSwiftSourceModule(ArrayRef extraPCMArgs) { + static ModuleDependencyInfo + forSwiftSourceModule(const std::string &CASFileSystemRootID, + ArrayRef buildCommands, + ArrayRef bridgingHeaderBuildCommands, + ArrayRef extraPCMArgs) { return ModuleDependencyInfo( - std::make_unique(extraPCMArgs)); + std::make_unique( + CASFileSystemRootID, buildCommands, bridgingHeaderBuildCommands, + extraPCMArgs)); } /// Describe the module dependencies for a Clang module that can be @@ -420,11 +478,15 @@ class ModuleDependencyInfo { const std::string &contextHash, const std::vector &nonPathCommandLine, const std::vector &fileDependencies, - const std::vector &capturedPCMArgs) { + const std::vector &capturedPCMArgs, + const std::string &CASFileSystemRootID, + const std::string &clangIncludeTreeRoot, + const std::string &moduleCacheKey) { return ModuleDependencyInfo( std::make_unique( pcmOutputPath, moduleMapFile, contextHash, - nonPathCommandLine, fileDependencies, capturedPCMArgs)); + nonPathCommandLine, fileDependencies, capturedPCMArgs, + CASFileSystemRootID, clangIncludeTreeRoot, moduleCacheKey)); } /// Describe a placeholder dependency swift module. @@ -453,6 +515,15 @@ class ModuleDependencyInfo { return storage->resolvedModuleDependencies; } + std::string getModuleCacheKey() const { + assert(storage->resolved); + return storage->moduleCacheKey; + } + + void updateModuleCacheKey(const std::string &key) { + storage->moduleCacheKey = key; + } + /// Resolve a dependency's set of `imports` with qualified Module IDs void resolveDependencies(const ArrayRef dependencyIDs) { assert(!storage->resolved && "Resolving an already-resolved dependency"); @@ -474,9 +545,41 @@ class ModuleDependencyInfo { textualModuleDetails->swiftOverlayDependencies.assign(dependencyIDs.begin(), dependencyIDs.end()); } + std::vector getCommandline() const { + if (auto *detail = getAsClangModule()) + return detail->buildCommandLine; + else if (auto *detail = getAsSwiftInterfaceModule()) + return detail->textualModuleDetails.buildCommandLine; + else if (auto *detail = getAsSwiftSourceModule()) + return detail->textualModuleDetails.buildCommandLine; + return {}; + } + void updateCommandLine(const std::vector &newCommandLine) { - assert(isSwiftInterfaceModule() && "Can only update command line on Swift interface dependency"); - cast(storage.get())->updateCommandLine(newCommandLine); + if (isSwiftInterfaceModule()) + return cast(storage.get()) + ->updateCommandLine(newCommandLine); + else if (isSwiftSourceModule()) + return cast(storage.get()) + ->updateCommandLine(newCommandLine); + else if (isClangModule()) + return cast(storage.get()) + ->updateCommandLine(newCommandLine); + llvm_unreachable("Unexpected type"); + } + + std::vector getBridgingHeaderCommandline() const { + if (auto *detail = getAsSwiftSourceModule()) + return detail->bridgingHeaderBuildCommandLine; + return {}; + } + + void updateBridgingHeaderCommandLine( + const std::vector &newCommandLine) { + if (isSwiftSourceModule()) + return cast(storage.get()) + ->updateBridgingHeaderCommandLine(newCommandLine); + llvm_unreachable("Unexpected type"); } bool isResolved() const { @@ -568,6 +671,18 @@ class ModuleDependencyInfo { /// Get the bridging header. Optional getBridgingHeader() const; + /// Get CAS Filesystem RootID. + Optional getCASFSRootID() const; + + /// Get Clang Include Tree ID. + Optional getClangIncludeTree() const; + + /// Get bridging header Include Tree ID. + Optional getBridgingHeaderIncludeTree() const; + + /// Get module output path. + std::string getModuleOutputPath() const; + /// Add a bridging header to a Swift module's dependencies. void addBridgingHeader(StringRef bridgingHeader); @@ -581,6 +696,9 @@ class ModuleDependencyInfo { void addBridgingModuleDependency(StringRef module, llvm::StringSet<> &alreadyAddedModules); + /// Add bridging header include tree. + void addBridgingHeaderIncludeTree(StringRef ID); + /// Collect a map from a secondary module name to a list of cross-import /// overlays, when this current module serves as the primary module. llvm::StringMap> @@ -597,6 +715,23 @@ using ModuleDependenciesKindRefMap = llvm::StringMap, ModuleDependencyKindHash>; +// MARK: SwiftDependencyTracker +/// Track swift dependency +class SwiftDependencyTracker { +public: + SwiftDependencyTracker(llvm::cas::CachingOnDiskFileSystem &FS, + const std::vector &CommonFiles) + : FS(FS.createProxyFS()), Files(CommonFiles) {} + + void startTracking(); + void trackFile(const Twine &path) { (void)FS->status(path); } + llvm::Expected createTreeFromDependencies(); + +private: + llvm::IntrusiveRefCntPtr FS; + const std::vector &Files; +}; + // MARK: SwiftDependencyScanningService /// A carrier of state shared among possibly multiple invocations of the dependency /// scanner. Acts as a global cache of discovered module dependencies and @@ -620,7 +755,21 @@ class SwiftDependencyScanningService { }; /// The persistent Clang dependency scanner service - clang::tooling::dependencies::DependencyScanningService ClangScanningService; + Optional + ClangScanningService; + + /// CachingOnDiskFileSystem for dependency tracking. + llvm::IntrusiveRefCntPtr CacheFS; + + /// If use clang include tree. + bool UseClangIncludeTree = false; + + /// CAS ObjectStore Instance. + std::shared_ptr CAS; + + /// The common dependencies that is needed for every swift compiler instance. + std::vector CommonDependencyFiles; + /// The global file system cache. Optional< clang::tooling::dependencies::DependencyScanningFilesystemSharedCache> @@ -671,9 +820,37 @@ class SwiftDependencyScanningService { return getCacheForScanningContextHash(scanningContextHash)->alreadySeenClangModules; } + bool usingCachingFS() const { return !UseClangIncludeTree && (bool)CacheFS; } + + llvm::cas::CachingOnDiskFileSystem &getSharedCachingFS() const { + assert(CacheFS && "Expect CachingOnDiskFileSystem"); + return *CacheFS; + } + + Optional createSwiftDependencyTracker() const { + if (!CacheFS) + return None; + + return SwiftDependencyTracker(*CacheFS, CommonDependencyFiles); + } + + llvm::IntrusiveRefCntPtr getClangScanningFS() const { + if (usingCachingFS()) + return CacheFS->createProxyFS(); + + if (UseClangIncludeTree) + return llvm::cas::createCASProvidingFileSystem( + CAS, llvm::vfs::createPhysicalFileSystem()); + + return llvm::vfs::createPhysicalFileSystem(); + } + /// Wrap the filesystem on the specified `CompilerInstance` with a /// caching `DependencyScanningWorkerFilesystem` void overlaySharedFilesystemCacheForCompilation(CompilerInstance &Instance); + + /// Setup caching service. + void setupCachingDependencyScanningService(CompilerInstance &Instance); private: /// Enforce clients not being allowed to query this cache directly, it must be /// wrapped in an instance of `ModuleDependenciesCache`. @@ -769,6 +946,9 @@ class ModuleDependenciesCache { clang::tooling::dependencies::DependencyScanningTool& getClangScannerTool() { return clangScanningTool; } + SwiftDependencyScanningService &getScanService() { + return globalScanningService; + } llvm::StringSet<>& getAlreadySeenClangModules() { return globalScanningService.getAlreadySeenClangModules(scannerContextHash); } diff --git a/include/swift/Basic/LangOptions.h b/include/swift/Basic/LangOptions.h index 8f77bc68ae512..ccd39bb2a26cd 100644 --- a/include/swift/Basic/LangOptions.h +++ b/include/swift/Basic/LangOptions.h @@ -822,6 +822,9 @@ namespace swift { /// clang CASOptions. std::string CASPath; + /// Cache key for imported bridging header. + std::string BridgingHeaderPCHCacheKey; + /// Disable validating the persistent PCH. bool PCHDisableValidation = false; @@ -891,6 +894,9 @@ namespace swift { /// built and provided to the compiler invocation. bool DisableImplicitClangModules = false; + /// Enable ClangIncludeTree for explicit module builds. + bool UseClangIncludeTree = false; + /// Return a hash code of any components from these options that should /// contribute to a Swift Bridging PCH hash. llvm::hash_code getPCHHashComponents() const { diff --git a/include/swift/ClangImporter/ClangImporter.h b/include/swift/ClangImporter/ClangImporter.h index 70fe747dd012f..7b6d817c107c3 100644 --- a/include/swift/ClangImporter/ClangImporter.h +++ b/include/swift/ClangImporter/ClangImporter.h @@ -54,6 +54,7 @@ namespace clang { namespace tooling { namespace dependencies { struct ModuleDeps; + struct TranslationUnitDeps; using ModuleDepsGraph = std::vector; } } @@ -431,6 +432,10 @@ class ClangImporter final : public ClangModuleLoader { ModuleDependenciesCache &cache, const clang::tooling::dependencies::ModuleDepsGraph &clangDependencies); + void recordBridgingHeaderOptions( + ModuleDependencyInfo &MDI, + const clang::tooling::dependencies::TranslationUnitDeps &deps); + Optional getModuleDependencies( StringRef moduleName, ModuleDependenciesCache &cache, InterfaceSubContextDelegate &delegate, diff --git a/include/swift/DependencyScan/DependencyScanImpl.h b/include/swift/DependencyScan/DependencyScanImpl.h index dd0463e502e44..92b3d45851a8a 100644 --- a/include/swift/DependencyScan/DependencyScanImpl.h +++ b/include/swift/DependencyScan/DependencyScanImpl.h @@ -86,6 +86,9 @@ typedef struct { /// Options to the compile command required to build this module interface swiftscan_string_set_t *command_line; + /// Options to the compile command required to build bridging header. + swiftscan_string_set_t *bridging_pch_command_line; + /// To build a PCM to be used by this Swift module, we need to append these /// arguments to the generic PCM build arguments reported from the dependency /// graph. @@ -96,6 +99,15 @@ typedef struct { /// A flag to indicate whether or not this module is a framework. bool is_framework; + + /// The CASID for CASFileSystemRoot + swiftscan_string_ref_t cas_fs_root_id; + + /// The CASID for bridging header include tree + swiftscan_string_ref_t bridging_header_include_tree; + + /// ModuleCacheKey + swiftscan_string_ref_t module_cache_key; } swiftscan_swift_textual_details_t; /// Swift modules with only a binary module file. @@ -111,6 +123,9 @@ typedef struct { /// A flag to indicate whether or not this module is a framework. bool is_framework; + + /// ModuleCacheKey + swiftscan_string_ref_t module_cache_key; } swiftscan_swift_binary_details_t; /// Swift placeholder modules carry additional details that specify their @@ -139,6 +154,15 @@ typedef struct { /// The swift-specific PCM arguments captured by this dependencies object swiftscan_string_set_t *captured_pcm_args; + + /// The CASID for CASFileSystemRoot + swiftscan_string_ref_t cas_fs_root_id; + + /// The CASID for CASFileSystemRoot + swiftscan_string_ref_t clang_include_tree; + + /// ModuleCacheKey + swiftscan_string_ref_t module_cache_key; } swiftscan_clang_details_t; struct swiftscan_module_details_s { diff --git a/include/swift/DependencyScan/SerializedModuleDependencyCacheFormat.h b/include/swift/DependencyScan/SerializedModuleDependencyCacheFormat.h index bad67c1e43bf1..3e9f4eeb4ca15 100644 --- a/include/swift/DependencyScan/SerializedModuleDependencyCacheFormat.h +++ b/include/swift/DependencyScan/SerializedModuleDependencyCacheFormat.h @@ -140,7 +140,10 @@ using SwiftInterfaceModuleDetailsLayout = FileIDArrayIDField, // sourceFiles FileIDArrayIDField, // bridgingSourceFiles FileIDArrayIDField, // bridgingModuleDependencies - DependencyIDArrayIDField // swiftOverlayDependencies + DependencyIDArrayIDField, // swiftOverlayDependencies + IdentifierIDField, // CASFileSystemRootID + IdentifierIDField, // bridgingHeaderIncludeTree + IdentifierIDField // moduleCacheKey >; using SwiftSourceModuleDetailsLayout = @@ -150,7 +153,11 @@ using SwiftSourceModuleDetailsLayout = FileIDArrayIDField, // sourceFiles FileIDArrayIDField, // bridgingSourceFiles FileIDArrayIDField, // bridgingModuleDependencies - DependencyIDArrayIDField // swiftOverlayDependencies + DependencyIDArrayIDField, // swiftOverlayDependencies + IdentifierIDField, // CASFileSystemRootID + IdentifierIDField, // bridgingHeaderIncludeTree + FlagIDArrayIDField, // buildCommandLine + FlagIDArrayIDField // bridgingHeaderBuildCommandLine >; using SwiftBinaryModuleDetailsLayout = @@ -158,7 +165,8 @@ using SwiftBinaryModuleDetailsLayout = FileIDField, // compiledModulePath FileIDField, // moduleDocPath FileIDField, // moduleSourceInfoPath - IsFrameworkField // isFramework + IsFrameworkField, // isFramework + IdentifierIDField // moduleCacheKey >; using SwiftPlaceholderModuleDetailsLayout = @@ -175,7 +183,10 @@ using ClangModuleDetailsLayout = ContextHashIDField, // contextHash FlagIDArrayIDField, // commandLine FileIDArrayIDField, // fileDependencies - FlagIDArrayIDField // capturedPCMArgs + FlagIDArrayIDField, // capturedPCMArgs + IdentifierIDField, // CASFileSystemRootID + IdentifierIDField, // clangIncludeTreeRoot + IdentifierIDField // moduleCacheKey >; } // namespace graph_block diff --git a/include/swift/Frontend/CachingUtils.h b/include/swift/Frontend/CachingUtils.h index 36709d8c3a38e..501a65415d38e 100644 --- a/include/swift/Frontend/CachingUtils.h +++ b/include/swift/Frontend/CachingUtils.h @@ -19,6 +19,7 @@ #include "llvm/CAS/ActionCache.h" #include "llvm/CAS/ObjectStore.h" #include "llvm/CAS/CASReference.h" +#include "llvm/Support/VirtualFileSystem.h" #include "llvm/Support/VirtualOutputBackend.h" #include @@ -54,6 +55,32 @@ llvm::Error storeCachedCompilerOutput(llvm::cas::ObjectStore &CAS, StringRef CorrespondingInput, file_types::ID OutputKind); +llvm::Expected> +createCASFileSystem(llvm::cas::ObjectStore &CAS, ArrayRef FSRoots, + ArrayRef IncludeTreeRoots); + +namespace cas { +/// Helper class to manage CAS/Caching from libSwiftScan C APIs. +class CachingTool { +public: + // Create the tool with a list of arguments from compiler invocation. + CachingTool(llvm::StringRef Path); + + // Compute the CASID for PCH output from invocation. + std::string computeCacheKey(llvm::ArrayRef Args, + StringRef InputPath, file_types::ID OutputKind); + + // Store content into CAS. + std::string storeContent(llvm::StringRef Content); + + // Check if the tool is correctly initialized. + bool isValid() const { return CAS && Cache; } + +private: + std::unique_ptr CAS; + std::unique_ptr Cache; +}; +} // namespace cas } #endif diff --git a/include/swift/Frontend/FrontendOptions.h b/include/swift/Frontend/FrontendOptions.h index 8809316ee9ca9..d19af926aafc8 100644 --- a/include/swift/Frontend/FrontendOptions.h +++ b/include/swift/Frontend/FrontendOptions.h @@ -129,7 +129,10 @@ class FrontendOptions { std::string CASPath; /// CASFS Root. - std::string CASFSRootID; + std::vector CASFSRootIDs; + + /// Clang Include Trees. + std::vector ClangIncludeTrees; /// Number of retry opening an input file if the previous opening returns /// bad file descriptor error. diff --git a/include/swift/Frontend/ModuleInterfaceLoader.h b/include/swift/Frontend/ModuleInterfaceLoader.h index d5533b10ec14e..3c0d148ba62e0 100644 --- a/include/swift/Frontend/ModuleInterfaceLoader.h +++ b/include/swift/Frontend/ModuleInterfaceLoader.h @@ -111,9 +111,17 @@ #include "swift/Frontend/Frontend.h" #include "swift/Frontend/ModuleInterfaceSupport.h" #include "swift/Serialization/SerializedModuleLoader.h" +#include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/StringSaver.h" #include "llvm/Support/YAMLTraits.h" +namespace llvm { +namespace cas { +class ObjectStore; +class ActionCache; +} // namespace cas +} // namespace llvm + namespace clang { class CompilerInstance; } @@ -178,6 +186,55 @@ class ExplicitSwiftModuleLoader: public SerializedModuleLoaderBase { ~ExplicitSwiftModuleLoader(); }; +class ExplicitCASModuleLoader : public SerializedModuleLoaderBase { + explicit ExplicitCASModuleLoader(ASTContext &ctx, llvm::cas::ObjectStore &CAS, + llvm::cas::ActionCache &cache, + DependencyTracker *tracker, + ModuleLoadingMode loadMode, + bool IgnoreSwiftSourceInfoFile); + + bool findModule(ImportPath::Element moduleID, + SmallVectorImpl *moduleInterfacePath, + SmallVectorImpl *moduleInterfaceSourcePath, + std::unique_ptr *moduleBuffer, + std::unique_ptr *moduleDocBuffer, + std::unique_ptr *moduleSourceInfoBuffer, + bool skipBuildingInterface, bool isTestableDependencyLookup, + bool &isFramework, bool &isSystemModule) override; + + std::error_code findModuleFilesInDirectory( + ImportPath::Element ModuleID, const SerializedModuleBaseName &BaseName, + SmallVectorImpl *ModuleInterfacePath, + SmallVectorImpl *ModuleInterfaceSourcePath, + std::unique_ptr *ModuleBuffer, + std::unique_ptr *ModuleDocBuffer, + std::unique_ptr *ModuleSourceInfoBuffer, + bool SkipBuildingInterface, bool IsFramework, + bool IsTestableDependencyLookup = false) override; + + bool canImportModule(ImportPath::Module named, + ModuleVersionInfo *versionInfo, + bool isTestableDependencyLookup = false) override; + + struct Implementation; + Implementation &Impl; + +public: + static std::unique_ptr + create(ASTContext &ctx, llvm::cas::ObjectStore &CAS, + llvm::cas::ActionCache &cache, DependencyTracker *tracker, + ModuleLoadingMode loadMode, StringRef ExplicitSwiftModuleMap, + const std::vector> + &ExplicitSwiftModuleInputs, + bool IgnoreSwiftSourceInfoFile); + + /// Append visible module names to \p names. Note that names are possibly + /// duplicated, and not guaranteed to be ordered in any way. + void collectVisibleTopLevelModuleNames( + SmallVectorImpl &names) const override; + + ~ExplicitCASModuleLoader(); +}; // Explicitly-specified Swift module inputs struct ExplicitSwiftModuleInputInfo { @@ -185,12 +242,14 @@ struct ExplicitSwiftModuleInputInfo { llvm::Optional moduleDocPath, llvm::Optional moduleSourceInfoPath, bool isFramework = false, - bool isSystem = false) + bool isSystem = false, + llvm::Optional moduleCacheKey = None) : modulePath(modulePath), moduleDocPath(moduleDocPath), moduleSourceInfoPath(moduleSourceInfoPath), isFramework(isFramework), - isSystem(isSystem) {} + isSystem(isSystem), + moduleCacheKey(moduleCacheKey) {} // Path of the .swiftmodule file. std::string modulePath; // Path of the .swiftmoduledoc file. @@ -201,6 +260,8 @@ struct ExplicitSwiftModuleInputInfo { bool isFramework = false; // A flag that indicates whether this module is a system module bool isSystem = false; + // The cache key for clang module. + llvm::Optional moduleCacheKey; }; // Explicitly-specified Clang module inputs @@ -208,11 +269,13 @@ struct ExplicitClangModuleInputInfo { ExplicitClangModuleInputInfo(std::string moduleMapPath, std::string modulePath, bool isFramework = false, - bool isSystem = false) + bool isSystem = false, + llvm::Optional moduleCacheKey = None) : moduleMapPath(moduleMapPath), modulePath(modulePath), isFramework(isFramework), - isSystem(isSystem) {} + isSystem(isSystem), + moduleCacheKey(moduleCacheKey) {} // Path of the Clang module map file. std::string moduleMapPath; // Path of a compiled Clang explicit module file (pcm). @@ -221,6 +284,8 @@ struct ExplicitClangModuleInputInfo { bool isFramework = false; // A flag that indicates whether this module is a system module bool isSystem = false; + // The cache key for clang module. + llvm::Optional moduleCacheKey; }; /// Parser of explicit module maps passed into the compiler. @@ -233,6 +298,8 @@ struct ExplicitClangModuleInputInfo { // "isFramework": false, // "clangModuleMapPath": "A/module.modulemap", // "clangModulePath": "A.pcm", +// "moduleCacheKey": "llvmcas://", +// "clangModuleCacheKey": "llvmcas://", // }, // { // "moduleName": "B", @@ -242,6 +309,8 @@ struct ExplicitClangModuleInputInfo { // "isFramework": false, // "clangModuleMapPath": "B/module.modulemap", // "clangModulePath": "B.pcm", +// "moduleCacheKey": "llvmcas://", +// "clangModuleCacheKey": "llvmcas://", // } // ] class ExplicitModuleMapParser { @@ -249,21 +318,14 @@ class ExplicitModuleMapParser { ExplicitModuleMapParser(llvm::BumpPtrAllocator &Allocator) : Saver(Allocator) {} std::error_code - parseSwiftExplicitModuleMap(llvm::StringRef fileName, + parseSwiftExplicitModuleMap(llvm::MemoryBufferRef BufferRef, llvm::StringMap &swiftModuleMap, llvm::StringMap &clangModuleMap) { using namespace llvm::yaml; - // Load the input file. - llvm::ErrorOr> fileBufOrErr = - llvm::MemoryBuffer::getFile(fileName); - if (!fileBufOrErr) { - return std::make_error_code(std::errc::no_such_file_or_directory); - } - StringRef Buffer = fileBufOrErr->get()->getBuffer(); // Use a new source manager instead of the one from ASTContext because we // don't want the JSON file to be persistent. llvm::SourceMgr SM; - Stream Stream(llvm::MemoryBufferRef(Buffer, fileName), SM); + Stream Stream(BufferRef, SM); for (auto DI = Stream.begin(); DI != Stream.end(); ++DI) { assert(DI != Stream.end() && "Failed to read a document"); if (auto *MN = dyn_cast_or_null(DI->getRoot())) { @@ -305,7 +367,8 @@ class ExplicitModuleMapParser { return true; StringRef moduleName; llvm::Optional swiftModulePath, swiftModuleDocPath, - swiftModuleSourceInfoPath; + swiftModuleSourceInfoPath, swiftModuleCacheKey, + clangModuleCacheKey; std::string clangModuleMapPath = "", clangModulePath = ""; bool isFramework = false, isSystem = false; for (auto &entry : *mapNode) { @@ -327,6 +390,10 @@ class ExplicitModuleMapParser { clangModuleMapPath = val.str(); } else if (key == "clangModulePath") { clangModulePath = val.str(); + } else if (key == "moduleCacheKey") { + swiftModuleCacheKey = val.str(); + } else if (key == "clangModuleCacheKey") { + clangModuleCacheKey = val.str(); } else { // Being forgiving for future fields. continue; @@ -343,7 +410,8 @@ class ExplicitModuleMapParser { swiftModuleDocPath, swiftModuleSourceInfoPath, isFramework, - isSystem); + isSystem, + swiftModuleCacheKey); swiftModuleMap.try_emplace(moduleName, std::move(entry)); } else { assert((!clangModuleMapPath.empty() || @@ -352,7 +420,8 @@ class ExplicitModuleMapParser { ExplicitClangModuleInputInfo entry(clangModuleMapPath, clangModulePath, isFramework, - isSystem); + isSystem, + clangModuleCacheKey); clangModuleMap.try_emplace(moduleName, std::move(entry)); } diff --git a/include/swift/Option/Options.td b/include/swift/Option/Options.td index 984d69949697f..1069d3ea2b10f 100644 --- a/include/swift/Option/Options.td +++ b/include/swift/Option/Options.td @@ -1829,6 +1829,15 @@ def allow_unstable_cache_key_for_testing: Flag<["-"], "allow-unstable-cache-key- Flags<[FrontendOption, HelpHidden, NoDriverOption]>, HelpText<"Allow compilation caching with unstable inputs for testing purpose">; +def bridging_header_pch_key : Separate<["-"], "bridging-header-pch-key">, + Flags<[FrontendOption, HelpHidden, ArgumentIsPath]>, + HelpText<"Cache Key for bridging header pch">; + +def clang_include_tree: Flag<["-"], "clang-include-tree">, + Flags<[FrontendOption, NoDriverOption]>, + HelpText<"Use clang include tree">; + + // END ONLY SUPPORTED IN NEW DRIVER def enable_cas: Flag<["-"], "enable-cas">, @@ -1839,6 +1848,10 @@ def cas_fs: Separate<["-"], "cas-fs">, Flags<[FrontendOption, NoDriverOption]>, HelpText<"Root CASID for CAS FileSystem">, MetaVarName<"">; +def clang_include_tree_root: Separate<["-"], "clang-include-tree-root">, + Flags<[FrontendOption, NoDriverOption]>, + HelpText<"Clang Include Tree CASID">, MetaVarName<"">; + def load_plugin_library: Separate<["-"], "load-plugin-library">, Flags<[FrontendOption, DoesNotAffectIncrementalBuild, ArgumentIsPath]>, diff --git a/include/swift/Serialization/ModuleDependencyScanner.h b/include/swift/Serialization/ModuleDependencyScanner.h index 0132c7ce58920..1567d63995281 100644 --- a/include/swift/Serialization/ModuleDependencyScanner.h +++ b/include/swift/Serialization/ModuleDependencyScanner.h @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// #include "swift/AST/ASTContext.h" +#include "swift/AST/ModuleDependencies.h" #include "swift/Frontend/ModuleInterfaceLoader.h" #include "swift/Serialization/SerializedModuleLoader.h" @@ -41,18 +42,22 @@ namespace swift { /// Location where pre-built moduels are to be built into. std::string moduleCachePath; + + Optional dependencyTracker; public: Optional dependencies; ModuleDependencyScanner(ASTContext &ctx, ModuleLoadingMode LoadMode, Identifier moduleName, InterfaceSubContextDelegate &astDelegate, - ScannerKind kind = MDS_plain) + ScannerKind kind = MDS_plain, + Optional tracker = None) : SerializedModuleLoaderBase(ctx, nullptr, LoadMode, /*IgnoreSwiftSourceInfoFile=*/true), kind(kind), moduleName(moduleName), astDelegate(astDelegate), moduleCachePath(getModuleCachePathFromClang( - ctx.getClangModuleLoader()->getClangInstance())) {} + ctx.getClangModuleLoader()->getClangInstance())), + dependencyTracker(tracker) {} std::error_code findModuleFilesInDirectory( ImportPath::Element ModuleID, @@ -87,9 +92,16 @@ namespace swift { void parsePlaceholderModuleMap(StringRef fileName) { ExplicitModuleMapParser parser(Allocator); llvm::StringMap ClangDependencyModuleMap; - auto result = - parser.parseSwiftExplicitModuleMap(fileName, PlaceholderDependencyModuleMap, - ClangDependencyModuleMap); + llvm::ErrorOr> fileBufOrErr = + llvm::MemoryBuffer::getFile(fileName); + if (!fileBufOrErr) { + Ctx.Diags.diagnose(SourceLoc(), + diag::explicit_swift_module_map_missing, fileName); + return; + } + auto result = parser.parseSwiftExplicitModuleMap( + (*fileBufOrErr)->getMemBufferRef(), PlaceholderDependencyModuleMap, + ClangDependencyModuleMap); if (result == std::errc::invalid_argument) { Ctx.Diags.diagnose(SourceLoc(), diag::placeholder_dependency_module_map_corrupted, @@ -109,9 +121,10 @@ namespace swift { PlaceholderSwiftModuleScanner(ASTContext &ctx, ModuleLoadingMode LoadMode, Identifier moduleName, StringRef PlaceholderDependencyModuleMap, - InterfaceSubContextDelegate &astDelegate) + InterfaceSubContextDelegate &astDelegate, + Optional tracker = None) : ModuleDependencyScanner(ctx, LoadMode, moduleName, astDelegate, - MDS_placeholder) { + MDS_placeholder, tracker) { // FIXME: Find a better place for this map to live, to avoid // doing the parsing on every module. diff --git a/lib/AST/ModuleDependencies.cpp b/lib/AST/ModuleDependencies.cpp index a9f5435d05d34..c3d3a59f590c2 100644 --- a/lib/AST/ModuleDependencies.cpp +++ b/lib/AST/ModuleDependencies.cpp @@ -15,8 +15,14 @@ //===----------------------------------------------------------------------===// #include "swift/AST/ModuleDependencies.h" #include "swift/AST/Decl.h" +#include "swift/AST/DiagnosticsFrontend.h" #include "swift/AST/SourceFile.h" #include "swift/Frontend/Frontend.h" +#include "llvm/CAS/CASProvidingFileSystem.h" +#include "llvm/CAS/CachingOnDiskFileSystem.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" +#include using namespace swift; ModuleDependencyInfoStorageBase::~ModuleDependencyInfoStorageBase() {} @@ -175,6 +181,108 @@ Optional ModuleDependencyInfo::getBridgingHeader() const { } } +Optional ModuleDependencyInfo::getCASFSRootID() const { + std::string Root; + switch (getKind()) { + case swift::ModuleDependencyKind::SwiftInterface: { + auto swiftInterfaceStorage = + cast(storage.get()); + Root = swiftInterfaceStorage->textualModuleDetails.CASFileSystemRootID; + break; + } + case swift::ModuleDependencyKind::SwiftSource: { + auto swiftSourceStorage = + cast(storage.get()); + Root = swiftSourceStorage->textualModuleDetails.CASFileSystemRootID; + break; + } + case swift::ModuleDependencyKind::Clang: { + auto clangModuleStorage = cast(storage.get()); + Root = clangModuleStorage->CASFileSystemRootID; + break; + } + default: + return None; + } + if (Root.empty()) + return None; + + return Root; +} + +Optional ModuleDependencyInfo::getClangIncludeTree() const { + std::string Root; + switch (getKind()) { + case swift::ModuleDependencyKind::Clang: { + auto clangModuleStorage = cast(storage.get()); + Root = clangModuleStorage->CASClangIncludeTreeRootID; + break; + } + default: + return None; + } + if (Root.empty()) + return None; + + return Root; +} + +Optional +ModuleDependencyInfo::getBridgingHeaderIncludeTree() const { + std::string Root; + switch (getKind()) { + case swift::ModuleDependencyKind::SwiftInterface: { + auto swiftInterfaceStorage = + cast(storage.get()); + Root = swiftInterfaceStorage->textualModuleDetails + .CASBridgingHeaderIncludeTreeRootID; + break; + } + case swift::ModuleDependencyKind::SwiftSource: { + auto swiftSourceStorage = + cast(storage.get()); + Root = swiftSourceStorage->textualModuleDetails + .CASBridgingHeaderIncludeTreeRootID; + break; + } + default: + return None; + } + if (Root.empty()) + return None; + + return Root; +} + +std::string ModuleDependencyInfo::getModuleOutputPath() const { + switch (getKind()) { + case swift::ModuleDependencyKind::SwiftInterface: { + auto swiftInterfaceStorage = + cast(storage.get()); + return swiftInterfaceStorage->moduleOutputPath; + } + case swift::ModuleDependencyKind::SwiftSource: { + return ""; + } + case swift::ModuleDependencyKind::Clang: { + auto clangModuleStorage = cast(storage.get()); + return clangModuleStorage->pcmOutputPath; + } + case swift::ModuleDependencyKind::SwiftBinary: { + auto swiftBinaryStorage = + cast(storage.get()); + return swiftBinaryStorage->compiledModulePath; + } + case swift::ModuleDependencyKind::SwiftPlaceholder: { + auto swiftPlaceholderStorage = + cast(storage.get()); + return swiftPlaceholderStorage->compiledModulePath; + } + default: + llvm_unreachable("Unexpected dependency kind"); + } +} + void ModuleDependencyInfo::addBridgingHeader(StringRef bridgingHeader) { switch (getKind()) { case swift::ModuleDependencyKind::SwiftInterface: { @@ -217,6 +325,27 @@ void ModuleDependencyInfo::addBridgingSourceFile(StringRef bridgingSourceFile) { } } +void ModuleDependencyInfo::addBridgingHeaderIncludeTree(StringRef ID) { + switch (getKind()) { + case swift::ModuleDependencyKind::SwiftInterface: { + auto swiftInterfaceStorage = + cast(storage.get()); + swiftInterfaceStorage->textualModuleDetails + .CASBridgingHeaderIncludeTreeRootID = ID.str(); + break; + } + case swift::ModuleDependencyKind::SwiftSource: { + auto swiftSourceStorage = + cast(storage.get()); + swiftSourceStorage->textualModuleDetails + .CASBridgingHeaderIncludeTreeRootID = ID.str(); + break; + } + default: + llvm_unreachable("Unexpected dependency kind"); + } +} + void ModuleDependencyInfo::addSourceFile(StringRef sourceFile) { switch (getKind()) { case swift::ModuleDependencyKind::SwiftSource: { @@ -253,25 +382,97 @@ void ModuleDependencyInfo::addBridgingModuleDependency( } } -SwiftDependencyScanningService::SwiftDependencyScanningService() - : ClangScanningService(clang::tooling::dependencies::ScanningMode::DependencyDirectivesScan, - clang::tooling::dependencies::ScanningOutputFormat::Full, - clang::CASOptions(), - /* CAS (llvm::cas::ObjectStore) */ nullptr, - /* Cache (llvm::cas::ActionCache) */ nullptr, - /* SharedFS */ nullptr, - /* OptimizeArgs */ true) { - SharedFilesystemCache.emplace(); +SwiftDependencyScanningService::SwiftDependencyScanningService() { + ClangScanningService.emplace( + clang::tooling::dependencies::ScanningMode::DependencyDirectivesScan, + clang::tooling::dependencies::ScanningOutputFormat::FullTree, + clang::CASOptions(), + /* CAS (llvm::cas::ObjectStore) */ nullptr, + /* Cache (llvm::cas::ActionCache) */ nullptr, + /* SharedFS */ nullptr, + /* OptimizeArgs */ true); + SharedFilesystemCache.emplace(); +} + +void SwiftDependencyTracker::startTracking() { + FS->trackNewAccesses(); + + for (auto &file : Files) + (void)FS->status(file); +} + +llvm::Expected +SwiftDependencyTracker::createTreeFromDependencies() { + return FS->createTreeFromNewAccesses(); } -void SwiftDependencyScanningService::overlaySharedFilesystemCacheForCompilation(CompilerInstance &Instance) { - auto existingFS = Instance.getSourceMgr().getFileSystem(); - llvm::IntrusiveRefCntPtr< - clang::tooling::dependencies::DependencyScanningWorkerFilesystem> - depFS = - new clang::tooling::dependencies::DependencyScanningWorkerFilesystem( - getSharedFilesystemCache(), existingFS); - Instance.getSourceMgr().setFileSystem(depFS); +void SwiftDependencyScanningService::overlaySharedFilesystemCacheForCompilation( + CompilerInstance &Instance) { + auto existingFS = Instance.getSourceMgr().getFileSystem(); + llvm::IntrusiveRefCntPtr< + clang::tooling::dependencies::DependencyScanningWorkerFilesystem> + depFS = + new clang::tooling::dependencies::DependencyScanningWorkerFilesystem( + getSharedFilesystemCache(), existingFS); + Instance.getSourceMgr().setFileSystem(depFS); +} + +void SwiftDependencyScanningService::setupCachingDependencyScanningService( + CompilerInstance &Instance) { + if (!Instance.getInvocation().getFrontendOptions().EnableCAS) + return; + + // Setup CAS. + CAS = Instance.getSharedCASInstance(); + + // Add SDKSetting file. + SmallString<256> SDKSettingPath; + llvm::sys::path::append( + SDKSettingPath, + Instance.getInvocation().getSearchPathOptions().getSDKPath(), + "SDKSettings.json"); + CommonDependencyFiles.emplace_back(SDKSettingPath.data(), + SDKSettingPath.size()); + + // Add Legacy layout file (maybe just hard code instead of searching). + for (auto RuntimeLibPath : + Instance.getInvocation().getSearchPathOptions().RuntimeLibraryPaths) { + auto &FS = Instance.getFileSystem(); + std::error_code EC; + for (auto F = FS.dir_begin(RuntimeLibPath, EC); + !EC && F != llvm::vfs::directory_iterator(); F.increment(EC)) { + if (F->path().endswith(".yaml")) + CommonDependencyFiles.emplace_back(F->path().str()); + } + } + + auto CachingFS = + llvm::cas::createCachingOnDiskFileSystem(Instance.getObjectStore()); + if (!CachingFS) { + Instance.getDiags().diagnose(SourceLoc(), diag::error_create_cas, + "CachingOnDiskFS", + toString(CachingFS.takeError())); + return; + } + CacheFS = std::move(*CachingFS); + + clang::CASOptions CASOpts; + CASOpts.CASPath = Instance.getInvocation().getFrontendOptions().CASPath; + CASOpts.ensurePersistentCAS(); + + UseClangIncludeTree = + Instance.getInvocation().getClangImporterOptions().UseClangIncludeTree; + const clang::tooling::dependencies::ScanningOutputFormat ClangScanningFormat = + UseClangIncludeTree + ? clang::tooling::dependencies::ScanningOutputFormat::FullIncludeTree + : clang::tooling::dependencies::ScanningOutputFormat::FullTree; + + ClangScanningService.emplace( + clang::tooling::dependencies::ScanningMode::DependencyDirectivesScan, + ClangScanningFormat, CASOpts, Instance.getSharedCASInstance(), + Instance.getSharedCacheInstance(), + UseClangIncludeTree ? nullptr : CacheFS, + /* ReuseFileManager */ false, /* OptimizeArgs */ false); } SwiftDependencyScanningService::ContextSpecificGlobalCacheState * @@ -385,12 +586,12 @@ ModuleDependenciesCache::getDependencyReferencesMap( ModuleDependenciesCache::ModuleDependenciesCache( SwiftDependencyScanningService &globalScanningService, - std::string mainScanModuleName, - std::string scannerContextHash) + std::string mainScanModuleName, std::string scannerContextHash) : globalScanningService(globalScanningService), mainScanModuleName(mainScanModuleName), scannerContextHash(scannerContextHash), - clangScanningTool(globalScanningService.ClangScanningService) { + clangScanningTool(*globalScanningService.ClangScanningService, + globalScanningService.getClangScanningFS()) { globalScanningService.configureForContextHash(scannerContextHash); for (auto kind = ModuleDependencyKind::FirstKind; kind != ModuleDependencyKind::LastKind; ++kind) { @@ -399,8 +600,7 @@ ModuleDependenciesCache::ModuleDependenciesCache( } } -Optional -ModuleDependenciesCache::findDependency( +Optional ModuleDependenciesCache::findDependency( StringRef moduleName, Optional kind) const { auto optionalDep = globalScanningService.findDependency(moduleName, kind, scannerContextHash); diff --git a/lib/AST/ModuleLoader.cpp b/lib/AST/ModuleLoader.cpp index 643082931a7dc..5480c40ed6268 100644 --- a/lib/AST/ModuleLoader.cpp +++ b/lib/AST/ModuleLoader.cpp @@ -94,7 +94,9 @@ static bool findOverlayFilesInDirectory(ASTContext &ctx, StringRef path, callback(file); } - if (error && error != std::errc::no_such_file_or_directory) { + // A CAS file list returns operation not permitted on directory iterations. + if (error && error != std::errc::no_such_file_or_directory && + error != std::errc::operation_not_permitted) { ctx.Diags.diagnose(diagLoc, diag::cannot_list_swiftcrossimport_dir, moduleName, error.message(), path); } diff --git a/lib/ClangImporter/ClangImporter.cpp b/lib/ClangImporter/ClangImporter.cpp index 86ed63dbe3ba8..8dacf49cfd5a2 100644 --- a/lib/ClangImporter/ClangImporter.cpp +++ b/lib/ClangImporter/ClangImporter.cpp @@ -708,6 +708,15 @@ importer::getNormalInvocationArguments( invocationArgStrs.push_back((llvm::Twine(searchPathOpts.RuntimeResourcePath) + llvm::sys::path::get_separator() + "apinotes").str()); + + if (!importerOpts.CASPath.empty()) { + invocationArgStrs.push_back("-Xclang"); + invocationArgStrs.push_back("-fcas-path"); + invocationArgStrs.push_back("-Xclang"); + invocationArgStrs.push_back(importerOpts.CASPath); + invocationArgStrs.push_back("-Xclang"); + invocationArgStrs.push_back("-fno-pch-timestamp"); + } } static void @@ -1721,7 +1730,8 @@ ClangImporter::cloneCompilerInstanceForPrecompiling() { auto &FrontendOpts = invocation->getFrontendOpts(); FrontendOpts.DisableFree = false; - FrontendOpts.Inputs.clear(); + if (FrontendOpts.CASIncludeTreeID.empty()) + FrontendOpts.Inputs.clear(); auto clonedInstance = std::make_unique( Impl.Instance->getPCHContainerOperations(), @@ -1752,7 +1762,8 @@ bool ClangImporter::emitBridgingPCH( auto inputFile = clang::FrontendInputFile(headerPath, language); auto &FrontendOpts = invocation.getFrontendOpts(); - FrontendOpts.Inputs = {inputFile}; + if (invocation.getFrontendOpts().CASIncludeTreeID.empty()) + FrontendOpts.Inputs = {inputFile}; FrontendOpts.OutputFile = outputPCHPath.str(); FrontendOpts.ProgramAction = clang::frontend::GeneratePCH; @@ -1784,7 +1795,8 @@ bool ClangImporter::runPreprocessor( auto inputFile = clang::FrontendInputFile(inputPath, language); auto &FrontendOpts = invocation.getFrontendOpts(); - FrontendOpts.Inputs = {inputFile}; + if (invocation.getFrontendOpts().CASIncludeTreeID.empty()) + FrontendOpts.Inputs = {inputFile}; FrontendOpts.OutputFile = outputPath.str(); FrontendOpts.ProgramAction = clang::frontend::PrintPreprocessedInput; @@ -1807,11 +1819,13 @@ bool ClangImporter::emitPrecompiledModule( auto language = getLanguageFromOptions(LangOpts); auto &FrontendOpts = invocation.getFrontendOpts(); - auto inputFile = clang::FrontendInputFile( - moduleMapPath, clang::InputKind( - language, clang::InputKind::ModuleMap, false), - FrontendOpts.IsSystemModule); - FrontendOpts.Inputs = {inputFile}; + if (invocation.getFrontendOpts().CASIncludeTreeID.empty()) { + auto inputFile = clang::FrontendInputFile( + moduleMapPath, + clang::InputKind(language, clang::InputKind::ModuleMap, false), + FrontendOpts.IsSystemModule); + FrontendOpts.Inputs = {inputFile}; + } FrontendOpts.OriginalModuleMap = moduleMapPath.str(); FrontendOpts.OutputFile = outputPath.str(); FrontendOpts.ProgramAction = clang::frontend::GenerateModule; @@ -1839,7 +1853,8 @@ bool ClangImporter::dumpPrecompiledModule( clang::Language::Unknown, clang::InputKind::Precompiled, false)); auto &FrontendOpts = invocation.getFrontendOpts(); - FrontendOpts.Inputs = {inputFile}; + if (invocation.getFrontendOpts().CASIncludeTreeID.empty()) + FrontendOpts.Inputs = {inputFile}; FrontendOpts.OutputFile = outputPath.str(); auto action = std::make_unique(); diff --git a/lib/ClangImporter/ClangModuleDependencyScanner.cpp b/lib/ClangImporter/ClangModuleDependencyScanner.cpp index 4633a050c18d5..0855acffb882a 100644 --- a/lib/ClangImporter/ClangModuleDependencyScanner.cpp +++ b/lib/ClangImporter/ClangModuleDependencyScanner.cpp @@ -18,11 +18,17 @@ #include "swift/AST/ModuleDependencies.h" #include "swift/Basic/SourceManager.h" #include "swift/ClangImporter/ClangImporter.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Frontend/CompilerInvocation.h" +#include "clang/Frontend/FrontendOptions.h" #include "clang/Tooling/DependencyScanning/DependencyScanningService.h" #include "clang/Tooling/DependencyScanning/DependencyScanningTool.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/Support/Allocator.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Signals.h" #include "llvm/Support/Path.h" +#include "llvm/Support/StringSaver.h" using namespace swift; @@ -175,18 +181,86 @@ void ClangImporter::recordModuleDependencies( // Swift frontend option for input file path (Foo.modulemap). swiftArgs.push_back(clangModuleDep.ClangModuleMapFile); + // Handle VFSOverlay. + if (!ctx.SearchPathOpts.VFSOverlayFiles.empty()) { + for (auto &overlay : ctx.SearchPathOpts.VFSOverlayFiles) { + swiftArgs.push_back("-vfsoverlay"); + swiftArgs.push_back(overlay); + } + } + // Add args reported by the scanner. - llvm::for_each(clangModuleDep.BuildArguments, addClangArg); + + // Round-trip clang args to canonicalize and clear the options that swift + // compiler doesn't need. + clang::CompilerInvocation depsInvocation; + clang::DiagnosticsEngine clangDiags(new clang::DiagnosticIDs(), + new clang::DiagnosticOptions(), + new clang::IgnoringDiagConsumer()); + + llvm::SmallVector clangArgs; + llvm::for_each(clangModuleDep.BuildArguments, [&](const std::string &Arg) { + clangArgs.push_back(Arg.c_str()); + }); + + bool success = clang::CompilerInvocation::CreateFromArgs( + depsInvocation, clangArgs, clangDiags); + (void)success; + assert(success && "clang option from dep scanner round trip failed"); + + // Clear the cache key for module. The module key is computed from clang + // invocation, not swift invocation. + depsInvocation.getFrontendOpts().ModuleCacheKeys.clear(); + + // FIXME: workaround for rdar://105684525: find the -ivfsoverlay option + // from clang scanner and pass to swift. + for (auto overlay : depsInvocation.getHeaderSearchOpts().VFSOverlayFiles) { + if (llvm::is_contained(ctx.SearchPathOpts.VFSOverlayFiles, overlay)) + continue; + swiftArgs.push_back("-vfsoverlay"); + swiftArgs.push_back(overlay); + } + + llvm::BumpPtrAllocator allocator; + llvm::StringSaver saver(allocator); + clangArgs.clear(); + depsInvocation.generateCC1CommandLine( + clangArgs, + [&saver](const llvm::Twine &T) { return saver.save(T).data(); }); + + llvm::for_each(clangArgs, addClangArg); + + // CASFileSystemRootID. + std::string RootID = clangModuleDep.CASFileSystemRootID + ? clangModuleDep.CASFileSystemRootID->toString() + : ""; + + std::string IncludeTree = + clangModuleDep.IncludeTreeID ? *clangModuleDep.IncludeTreeID : ""; + + if (!RootID.empty() || !IncludeTree.empty()) { + swiftArgs.push_back("-enable-cas"); + swiftArgs.push_back("-cas-path"); + swiftArgs.push_back(ctx.ClangImporterOpts.CASPath); + } + + if (!RootID.empty()) { + swiftArgs.push_back("-cas-fs"); + swiftArgs.push_back(RootID); + } + + if (!IncludeTree.empty()) { + swiftArgs.push_back("-clang-include-tree"); + swiftArgs.push_back("-clang-include-tree-root"); + swiftArgs.push_back(IncludeTree); + } // Module-level dependencies. llvm::StringSet<> alreadyAddedModules; auto dependencies = ModuleDependencyInfo::forClangModule( - pcmPath, - clangModuleDep.ClangModuleMapFile, - clangModuleDep.ID.ContextHash, - swiftArgs, - fileDeps, - capturedPCMArgs); + pcmPath, clangModuleDep.ClangModuleMapFile, + clangModuleDep.ID.ContextHash, swiftArgs, fileDeps, capturedPCMArgs, + RootID, IncludeTree, /*module-cache-key*/ ""); for (const auto &moduleName : clangModuleDep.ClangModuleDeps) { dependencies.addModuleImport(moduleName.ModuleName, &alreadyAddedModules); // It is safe to assume that all dependencies of a Clang module are Clang modules. @@ -200,6 +274,85 @@ void ClangImporter::recordModuleDependencies( } } +void ClangImporter::recordBridgingHeaderOptions( + ModuleDependencyInfo &MDI, + const clang::tooling::dependencies::TranslationUnitDeps &deps) { + auto &ctx = Impl.SwiftContext; + + std::vector swiftArgs; + auto addClangArg = [&](Twine arg) { + swiftArgs.push_back("-Xcc"); + swiftArgs.push_back(arg.str()); + }; + + // We are using Swift frontend mode. + swiftArgs.push_back("-frontend"); + + // Swift frontend action: -emit-pcm + swiftArgs.push_back("-emit-pch"); + + // We pass the entire argument list via -Xcc, so the invocation should + // use extra clang options alone. + swiftArgs.push_back("-only-use-extra-clang-opts"); + + // Ensure that the resulting PCM build invocation uses Clang frontend + // directly + swiftArgs.push_back("-direct-clang-cc1-module-build"); + + // Add args reported by the scanner. + + // Round-trip clang args to canonicalize and clear the options that swift + // compiler doesn't need. + clang::CompilerInvocation depsInvocation; + clang::DiagnosticsEngine clangDiags(new clang::DiagnosticIDs(), + new clang::DiagnosticOptions(), + new clang::IgnoringDiagConsumer()); + + llvm::SmallVector clangArgs; + llvm::for_each(deps.Commands[0].Arguments, [&](const std::string &Arg) { + clangArgs.push_back(Arg.c_str()); + }); + + bool success = clang::CompilerInvocation::CreateFromArgs( + depsInvocation, clangArgs, clangDiags); + (void)success; + assert(success && "clang option from dep scanner round trip failed"); + + // Clear the cache key for module. The module key is computed from clang + // invocation, not swift invocation. + depsInvocation.getFrontendOpts().ProgramAction = + clang::frontend::ActionKind::GeneratePCH; + depsInvocation.getFrontendOpts().ModuleCacheKeys.clear(); + depsInvocation.getFrontendOpts().OutputFile = ""; + + llvm::BumpPtrAllocator allocator; + llvm::StringSaver saver(allocator); + clangArgs.clear(); + depsInvocation.generateCC1CommandLine( + clangArgs, + [&saver](const llvm::Twine &T) { return saver.save(T).data(); }); + + llvm::for_each(clangArgs, addClangArg); + + if (!ctx.ClangImporterOpts.CASPath.empty()) { + swiftArgs.push_back("-enable-cas"); + swiftArgs.push_back("-cas-path"); + swiftArgs.push_back(ctx.ClangImporterOpts.CASPath); + } + + if (auto Tree = deps.IncludeTreeID) { + swiftArgs.push_back("-clang-include-tree"); + swiftArgs.push_back("-clang-include-tree-root"); + swiftArgs.push_back(*Tree); + } + if (auto CASFS = deps.CASFileSystemRootID) { + swiftArgs.push_back("-cas-fs"); + swiftArgs.push_back(*CASFS); + } + + MDI.updateBridgingHeaderCommandLine(swiftArgs); +} + // The Swift compiler does not have a concept of a working directory. // It is instead handled by the Swift driver by resolving relative paths // according to the driver's notion of a working directory. On the other hand, @@ -337,6 +490,11 @@ bool ClangImporter::addBridgingHeaderDependencies( alreadyAddedModules); } + if (auto TreeID = clangModuleDependencies->IncludeTreeID) + targetModule.addBridgingHeaderIncludeTree(*TreeID); + + recordBridgingHeaderOptions(targetModule, *clangModuleDependencies); + // Update the cache with the new information for the module. cache.updateDependency({moduleName.str(), moduleKind}, targetModule); diff --git a/lib/DependencyScan/DependencyScanningTool.cpp b/lib/DependencyScan/DependencyScanningTool.cpp index 084922efbcf64..6f67370390588 100644 --- a/lib/DependencyScan/DependencyScanningTool.cpp +++ b/lib/DependencyScan/DependencyScanningTool.cpp @@ -236,9 +236,6 @@ DependencyScanningTool::initCompilerInstanceForScan( auto Instance = std::make_unique(); Instance->addDiagnosticConsumer(&CDC); - // Wrap the filesystem with a caching `DependencyScanningWorkerFilesystem` - ScanningService->overlaySharedFilesystemCacheForCompilation(*Instance); - // Basic error checking on the arguments if (CommandArgs.empty()) { Instance->getDiags().diagnose(SourceLoc(), diag::error_no_frontend_args); @@ -280,6 +277,10 @@ DependencyScanningTool::initCompilerInstanceForScan( if (Instance->setup(Invocation, InstanceSetupError)) { return std::make_error_code(std::errc::not_supported); } + + // Setup the caching service after the instance finishes setup. + ScanningService->setupCachingDependencyScanningService(*Instance); + (void)Instance->getMainModule(); return Instance; diff --git a/lib/DependencyScan/ModuleDependencyCacheSerialization.cpp b/lib/DependencyScan/ModuleDependencyCacheSerialization.cpp index 6cf39b6fb96b9..184f356ef78c4 100644 --- a/lib/DependencyScan/ModuleDependencyCacheSerialization.cpp +++ b/lib/DependencyScan/ModuleDependencyCacheSerialization.cpp @@ -235,17 +235,19 @@ bool ModuleDependenciesCacheDeserializer::readGraph(SwiftDependencyScanningServi llvm::report_fatal_error( "Unexpected SWIFT_TEXTUAL_MODULE_DETAILS_NODE record"); cache.configureForContextHash(getContextHash()); - unsigned outputPathFileID, interfaceFileID, compiledModuleCandidatesArrayID, - buildCommandLineArrayID, extraPCMArgsArrayID, contextHashID, - isFramework, bridgingHeaderFileID, sourceFilesArrayID, - bridgingSourceFilesArrayID, bridgingModuleDependenciesArrayID, - overlayDependencyIDArrayID; + unsigned outputPathFileID, interfaceFileID, + compiledModuleCandidatesArrayID, buildCommandLineArrayID, + extraPCMArgsArrayID, contextHashID, isFramework, bridgingHeaderFileID, + sourceFilesArrayID, bridgingSourceFilesArrayID, + bridgingModuleDependenciesArrayID, overlayDependencyIDArrayID, + CASFileSystemRootID, bridgingHeaderIncludeTreeID, moduleCacheKeyID; SwiftInterfaceModuleDetailsLayout::readRecord( - Scratch, outputPathFileID, interfaceFileID, compiledModuleCandidatesArrayID, - buildCommandLineArrayID, extraPCMArgsArrayID, contextHashID, - isFramework, bridgingHeaderFileID, sourceFilesArrayID, - bridgingSourceFilesArrayID, bridgingModuleDependenciesArrayID, - overlayDependencyIDArrayID); + Scratch, outputPathFileID, interfaceFileID, + compiledModuleCandidatesArrayID, buildCommandLineArrayID, + extraPCMArgsArrayID, contextHashID, isFramework, bridgingHeaderFileID, + sourceFilesArrayID, bridgingSourceFilesArrayID, + bridgingModuleDependenciesArrayID, overlayDependencyIDArrayID, + CASFileSystemRootID, bridgingHeaderIncludeTreeID, moduleCacheKeyID); auto outputModulePath = getIdentifier(outputPathFileID); if (!outputModulePath) @@ -278,11 +280,18 @@ bool ModuleDependenciesCacheDeserializer::readGraph(SwiftDependencyScanningServi for (auto &arg : *extraPCMArgs) extraPCMRefs.push_back(arg); + auto rootFileSystemID = getIdentifier(CASFileSystemRootID); + if (!rootFileSystemID) + llvm::report_fatal_error("Bad CASFileSystem RootID"); + auto moduleCacheKey = getIdentifier(moduleCacheKeyID); + if (!moduleCacheKeyID) + llvm::report_fatal_error("Bad moduleCacheKey"); + // Form the dependencies storage object auto moduleDep = ModuleDependencyInfo::forSwiftInterfaceModule( - outputModulePath.value(), - optionalSwiftInterfaceFile.value(), *compiledModuleCandidates, - buildCommandRefs, extraPCMRefs, *contextHash, isFramework); + outputModulePath.value(), optionalSwiftInterfaceFile.value(), + *compiledModuleCandidates, buildCommandRefs, extraPCMRefs, + *contextHash, isFramework, *rootFileSystemID, *moduleCacheKey); // Add imports of this module for (const auto &moduleName : *currentModuleImports) @@ -328,6 +337,14 @@ bool ModuleDependenciesCacheDeserializer::readGraph(SwiftDependencyScanningServi llvm::report_fatal_error("Bad overlay dependencies: no qualified dependencies"); moduleDep.setOverlayDependencies(overlayModuleDependencyIDs.value()); + // Add bridging header include tree + auto bridgingHeaderIncludeTree = + getIdentifier(bridgingHeaderIncludeTreeID); + if (!bridgingHeaderIncludeTree) + llvm::report_fatal_error("Bad bridging header include tree"); + if (!bridgingHeaderIncludeTree->empty()) + moduleDep.addBridgingHeaderIncludeTree(*bridgingHeaderIncludeTree); + cache.recordDependency(currentModuleName, std::move(moduleDep), getContextHash()); hasCurrentModule = false; @@ -345,11 +362,15 @@ bool ModuleDependenciesCacheDeserializer::readGraph(SwiftDependencyScanningServi "SWIFT_SOURCE_MODULE_DETAILS_NODE record"); unsigned extraPCMArgsArrayID, bridgingHeaderFileID, sourceFilesArrayID, bridgingSourceFilesArrayID, bridgingModuleDependenciesArrayID, - overlayDependencyIDArrayID; + overlayDependencyIDArrayID, CASFileSystemRootID, + bridgingHeaderIncludeTreeID, buildCommandLineArrayID, + bridgingHeaderBuildCommandLineArrayID; SwiftSourceModuleDetailsLayout::readRecord( Scratch, extraPCMArgsArrayID, bridgingHeaderFileID, sourceFilesArrayID, bridgingSourceFilesArrayID, - bridgingModuleDependenciesArrayID, overlayDependencyIDArrayID); + bridgingModuleDependenciesArrayID, overlayDependencyIDArrayID, + CASFileSystemRootID, bridgingHeaderIncludeTreeID, + buildCommandLineArrayID, bridgingHeaderBuildCommandLineArrayID); auto extraPCMArgs = getStringArray(extraPCMArgsArrayID); if (!extraPCMArgs) @@ -358,8 +379,27 @@ bool ModuleDependenciesCacheDeserializer::readGraph(SwiftDependencyScanningServi for (auto &arg : *extraPCMArgs) extraPCMRefs.push_back(arg); + auto rootFileSystemID = getIdentifier(CASFileSystemRootID); + if (!rootFileSystemID) + llvm::report_fatal_error("Bad CASFileSystem RootID"); + auto commandLine = getStringArray(buildCommandLineArrayID); + if (!commandLine) + llvm::report_fatal_error("Bad command line"); + std::vector buildCommandRefs; + for (auto &arg : *commandLine) + buildCommandRefs.push_back(arg); + std::vector bridgingHeaderBuildCommandRefs; + auto bridgingHeaderCommandLine = + getStringArray(bridgingHeaderBuildCommandLineArrayID); + if (!bridgingHeaderCommandLine) + llvm::report_fatal_error("Bad bridging header command line"); + for (auto &arg : *bridgingHeaderCommandLine) + bridgingHeaderBuildCommandRefs.push_back(arg); + // Form the dependencies storage object - auto moduleDep = ModuleDependencyInfo::forSwiftSourceModule(extraPCMRefs); + auto moduleDep = ModuleDependencyInfo::forSwiftSourceModule( + *rootFileSystemID, buildCommandRefs, bridgingHeaderBuildCommandRefs, + extraPCMRefs); // Add dependencies of this module for (const auto &moduleName : *currentModuleImports) @@ -402,6 +442,14 @@ bool ModuleDependenciesCacheDeserializer::readGraph(SwiftDependencyScanningServi llvm::report_fatal_error("Bad overlay dependencies: no qualified dependencies"); moduleDep.setOverlayDependencies(overlayModuleDependencyIDs.value()); + // Add bridging header include tree + auto bridgingHeaderIncludeTree = + getIdentifier(bridgingHeaderIncludeTreeID); + if (!bridgingHeaderIncludeTree) + llvm::report_fatal_error("Bad bridging header include tree"); + if (!bridgingHeaderIncludeTree->empty()) + moduleDep.addBridgingHeaderIncludeTree(*bridgingHeaderIncludeTree); + cache.recordDependency(currentModuleName, std::move(moduleDep), getContextHash()); hasCurrentModule = false; @@ -414,10 +462,10 @@ bool ModuleDependenciesCacheDeserializer::readGraph(SwiftDependencyScanningServi "Unexpected SWIFT_BINARY_MODULE_DETAILS_NODE record"); cache.configureForContextHash(getContextHash()); unsigned compiledModulePathID, moduleDocPathID, moduleSourceInfoPathID, - isFramework; + isFramework, moduleCacheKeyID; SwiftBinaryModuleDetailsLayout::readRecord( Scratch, compiledModulePathID, moduleDocPathID, - moduleSourceInfoPathID, isFramework); + moduleSourceInfoPathID, isFramework, moduleCacheKeyID); auto compiledModulePath = getIdentifier(compiledModulePathID); if (!compiledModulePath) @@ -428,11 +476,14 @@ bool ModuleDependenciesCacheDeserializer::readGraph(SwiftDependencyScanningServi auto moduleSourceInfoPath = getIdentifier(moduleSourceInfoPathID); if (!moduleSourceInfoPath) llvm::report_fatal_error("Bad module source info path"); + auto moduleCacheKey = getIdentifier(moduleCacheKeyID); + if (!moduleCacheKeyID) + llvm::report_fatal_error("Bad moduleCacheKey"); // Form the dependencies storage object auto moduleDep = ModuleDependencyInfo::forSwiftBinaryModule( *compiledModulePath, *moduleDocPath, *moduleSourceInfoPath, - isFramework); + isFramework, *moduleCacheKey); // Add dependencies of this module for (const auto &moduleName : *currentModuleImports) moduleDep.addModuleImport(moduleName); @@ -481,11 +532,15 @@ bool ModuleDependenciesCacheDeserializer::readGraph(SwiftDependencyScanningServi llvm::report_fatal_error("Unexpected CLANG_MODULE_DETAILS_NODE record"); cache.configureForContextHash(getContextHash()); unsigned pcmOutputPathID, moduleMapPathID, contextHashID, commandLineArrayID, - fileDependenciesArrayID, capturedPCMArgsArrayID; + fileDependenciesArrayID, capturedPCMArgsArrayID, CASFileSystemRootID, + clangIncludeTreeRootID, moduleCacheKeyID; ClangModuleDetailsLayout::readRecord(Scratch, pcmOutputPathID, moduleMapPathID, contextHashID, commandLineArrayID, fileDependenciesArrayID, - capturedPCMArgsArrayID); + capturedPCMArgsArrayID, + CASFileSystemRootID, + clangIncludeTreeRootID, + moduleCacheKeyID); auto pcmOutputPath = getIdentifier(pcmOutputPathID); if (!pcmOutputPath) llvm::report_fatal_error("Bad pcm output path"); @@ -504,11 +559,21 @@ bool ModuleDependenciesCacheDeserializer::readGraph(SwiftDependencyScanningServi auto capturedPCMArgs = getStringArray(capturedPCMArgsArrayID); if (!capturedPCMArgs) llvm::report_fatal_error("Bad captured PCM Args"); + auto rootFileSystemID = getIdentifier(CASFileSystemRootID); + if (!rootFileSystemID) + llvm::report_fatal_error("Bad CASFileSystem RootID"); + auto clangIncludeTreeRoot = getIdentifier(clangIncludeTreeRootID); + if (!clangIncludeTreeRoot) + llvm::report_fatal_error("Bad clang include tree ID"); + auto moduleCacheKey = getIdentifier(moduleCacheKeyID); + if (!moduleCacheKeyID) + llvm::report_fatal_error("Bad moduleCacheKey"); // Form the dependencies storage object - auto moduleDep = ModuleDependencyInfo::forClangModule(*pcmOutputPath, - *moduleMapPath, *contextHash, *commandLineArgs, *fileDependencies, - *capturedPCMArgs); + auto moduleDep = ModuleDependencyInfo::forClangModule( + *pcmOutputPath, *moduleMapPath, *contextHash, *commandLineArgs, + *fileDependencies, *capturedPCMArgs, *rootFileSystemID, + *clangIncludeTreeRoot, *moduleCacheKey); // Add dependencies of this module for (const auto &moduleName : *currentModuleImports) @@ -647,6 +712,7 @@ enum ModuleIdentifierArrayKind : uint8_t { BridgingSourceFiles, BridgingModuleDependencies, SwiftOverlayDependencyIDs, + BridgingHeaderBuildCommandLine, NonPathCommandLine, FileDependencies, CapturedPCMArgs, @@ -852,18 +918,23 @@ void ModuleDependenciesCacheSerializer::writeModuleInfo(ModuleDependencyID modul : 0; SwiftInterfaceModuleDetailsLayout::emitRecord( Out, ScratchRecord, AbbrCodes[SwiftInterfaceModuleDetailsLayout::Code], - outputModulePathFileId, - swiftInterfaceFileId, - getArrayID(moduleID, ModuleIdentifierArrayKind::CompiledModuleCandidates), + outputModulePathFileId, swiftInterfaceFileId, + getArrayID(moduleID, + ModuleIdentifierArrayKind::CompiledModuleCandidates), getArrayID(moduleID, ModuleIdentifierArrayKind::BuildCommandLine), getArrayID(moduleID, ModuleIdentifierArrayKind::ExtraPCMArgs), - getIdentifier(swiftTextDeps->contextHash), - swiftTextDeps->isFramework, + getIdentifier(swiftTextDeps->contextHash), swiftTextDeps->isFramework, bridgingHeaderFileId, getArrayID(moduleID, ModuleIdentifierArrayKind::SourceFiles), getArrayID(moduleID, ModuleIdentifierArrayKind::BridgingSourceFiles), - getArrayID(moduleID, ModuleIdentifierArrayKind::BridgingModuleDependencies), - getArrayID(moduleID, ModuleIdentifierArrayKind::SwiftOverlayDependencyIDs)); + getArrayID(moduleID, + ModuleIdentifierArrayKind::BridgingModuleDependencies), + getArrayID(moduleID, + ModuleIdentifierArrayKind::SwiftOverlayDependencyIDs), + getIdentifier(swiftTextDeps->textualModuleDetails.CASFileSystemRootID), + getIdentifier(swiftTextDeps->textualModuleDetails + .CASBridgingHeaderIncludeTreeRootID), + getIdentifier(swiftTextDeps->moduleCacheKey)); break; } case swift::ModuleDependencyKind::SwiftSource: { @@ -882,8 +953,17 @@ void ModuleDependenciesCacheSerializer::writeModuleInfo(ModuleDependencyID modul bridgingHeaderFileId, getArrayID(moduleID, ModuleIdentifierArrayKind::SourceFiles), getArrayID(moduleID, ModuleIdentifierArrayKind::BridgingSourceFiles), - getArrayID(moduleID, ModuleIdentifierArrayKind::BridgingModuleDependencies), - getArrayID(moduleID, ModuleIdentifierArrayKind::SwiftOverlayDependencyIDs)); + getArrayID(moduleID, + ModuleIdentifierArrayKind::BridgingModuleDependencies), + getArrayID(moduleID, + ModuleIdentifierArrayKind::SwiftOverlayDependencyIDs), + getIdentifier( + swiftSourceDeps->textualModuleDetails.CASFileSystemRootID), + getIdentifier(swiftSourceDeps->textualModuleDetails + .CASBridgingHeaderIncludeTreeRootID), + getArrayID(moduleID, ModuleIdentifierArrayKind::BuildCommandLine), + getArrayID(moduleID, + ModuleIdentifierArrayKind::BridgingHeaderBuildCommandLine)); break; } case swift::ModuleDependencyKind::SwiftBinary: { @@ -895,7 +975,8 @@ void ModuleDependenciesCacheSerializer::writeModuleInfo(ModuleDependencyID modul getIdentifier(swiftBinDeps->compiledModulePath), getIdentifier(swiftBinDeps->moduleDocPath), getIdentifier(swiftBinDeps->sourceInfoPath), - swiftBinDeps->isFramework); + swiftBinDeps->isFramework, + getIdentifier(swiftBinDeps->moduleCacheKey)); break; } @@ -922,7 +1003,10 @@ void ModuleDependenciesCacheSerializer::writeModuleInfo(ModuleDependencyID modul getIdentifier(clangDeps->contextHash), getArrayID(moduleID, ModuleIdentifierArrayKind::NonPathCommandLine), getArrayID(moduleID, ModuleIdentifierArrayKind::FileDependencies), - getArrayID(moduleID, ModuleIdentifierArrayKind::CapturedPCMArgs)); + getArrayID(moduleID, ModuleIdentifierArrayKind::CapturedPCMArgs), + getIdentifier(clangDeps->CASFileSystemRootID), + getIdentifier(clangDeps->CASClangIncludeTreeRootID), + getIdentifier(clangDeps->moduleCacheKey)); break; } @@ -1035,26 +1119,30 @@ void ModuleDependenciesCacheSerializer::collectStringsAndArrays( addIdentifier(swiftTextDeps->moduleOutputPath); addIdentifier(swiftTextDeps->swiftInterfaceFile); addStringArray(moduleID, - ModuleIdentifierArrayKind::CompiledModuleCandidates, - swiftTextDeps->compiledModuleCandidates); + ModuleIdentifierArrayKind::CompiledModuleCandidates, + swiftTextDeps->compiledModuleCandidates); addStringArray(moduleID, ModuleIdentifierArrayKind::BuildCommandLine, - swiftTextDeps->buildCommandLine); + swiftTextDeps->textualModuleDetails.buildCommandLine); addStringArray(moduleID, ModuleIdentifierArrayKind::ExtraPCMArgs, - swiftTextDeps->textualModuleDetails.extraPCMArgs); + swiftTextDeps->textualModuleDetails.extraPCMArgs); addIdentifier(swiftTextDeps->contextHash); if (swiftTextDeps->textualModuleDetails.bridgingHeaderFile.has_value()) - addIdentifier( - swiftTextDeps->textualModuleDetails.bridgingHeaderFile.value()); + addIdentifier(swiftTextDeps->textualModuleDetails.bridgingHeaderFile + .value()); addStringArray(moduleID, ModuleIdentifierArrayKind::SourceFiles, - std::vector()); + std::vector()); addStringArray(moduleID, ModuleIdentifierArrayKind::BridgingSourceFiles, - swiftTextDeps->textualModuleDetails.bridgingSourceFiles); + swiftTextDeps->textualModuleDetails.bridgingSourceFiles); addStringArray( - moduleID, ModuleIdentifierArrayKind::BridgingModuleDependencies, - swiftTextDeps->textualModuleDetails.bridgingModuleDependencies); + moduleID, ModuleIdentifierArrayKind::BridgingModuleDependencies, + swiftTextDeps->textualModuleDetails.bridgingModuleDependencies); addDependencyIDArray( moduleID, ModuleIdentifierArrayKind::SwiftOverlayDependencyIDs, swiftTextDeps->textualModuleDetails.swiftOverlayDependencies); + addIdentifier(swiftTextDeps->textualModuleDetails.CASFileSystemRootID); + addIdentifier(swiftTextDeps->textualModuleDetails + .CASBridgingHeaderIncludeTreeRootID); + addIdentifier(swiftTextDeps->moduleCacheKey); break; } case swift::ModuleDependencyKind::SwiftBinary: { @@ -1063,6 +1151,7 @@ void ModuleDependenciesCacheSerializer::collectStringsAndArrays( addIdentifier(swiftBinDeps->compiledModulePath); addIdentifier(swiftBinDeps->moduleDocPath); addIdentifier(swiftBinDeps->sourceInfoPath); + addIdentifier(swiftBinDeps->moduleCacheKey); break; } case swift::ModuleDependencyKind::SwiftPlaceholder: { @@ -1093,6 +1182,14 @@ void ModuleDependenciesCacheSerializer::collectStringsAndArrays( addDependencyIDArray( moduleID, ModuleIdentifierArrayKind::SwiftOverlayDependencyIDs, swiftSourceDeps->textualModuleDetails.swiftOverlayDependencies); + addStringArray( + moduleID, ModuleIdentifierArrayKind::BuildCommandLine, + swiftSourceDeps->textualModuleDetails.buildCommandLine); + addStringArray( + moduleID, ModuleIdentifierArrayKind::BridgingHeaderBuildCommandLine, + swiftSourceDeps->bridgingHeaderBuildCommandLine); + addIdentifier( + swiftSourceDeps->textualModuleDetails.CASFileSystemRootID); break; } case swift::ModuleDependencyKind::Clang: { @@ -1102,11 +1199,14 @@ void ModuleDependenciesCacheSerializer::collectStringsAndArrays( addIdentifier(clangDeps->moduleMapFile); addIdentifier(clangDeps->contextHash); addStringArray(moduleID, ModuleIdentifierArrayKind::NonPathCommandLine, - clangDeps->nonPathCommandLine); + clangDeps->buildCommandLine); addStringArray(moduleID, ModuleIdentifierArrayKind::FileDependencies, clangDeps->fileDependencies); addStringArray(moduleID, ModuleIdentifierArrayKind::CapturedPCMArgs, clangDeps->capturedPCMArgs); + addIdentifier(clangDeps->CASFileSystemRootID); + addIdentifier(clangDeps->CASClangIncludeTreeRootID); + addIdentifier(clangDeps->moduleCacheKey); break; } default: diff --git a/lib/DependencyScan/ScanDependencies.cpp b/lib/DependencyScan/ScanDependencies.cpp index 9d94da4e784dd..a3a09efb75b30 100644 --- a/lib/DependencyScan/ScanDependencies.cpp +++ b/lib/DependencyScan/ScanDependencies.cpp @@ -12,14 +12,12 @@ #include "swift/Basic/PrettyStackTrace.h" -#include "swift/DependencyScan/ScanDependencies.h" -#include "swift/DependencyScan/SerializedModuleDependencyCacheFormat.h" #include "swift/AST/ASTContext.h" #include "swift/AST/Decl.h" #include "swift/AST/DiagnosticEngine.h" +#include "swift/AST/DiagnosticsDriver.h" #include "swift/AST/DiagnosticsFrontend.h" #include "swift/AST/DiagnosticsSema.h" -#include "swift/AST/DiagnosticsDriver.h" #include "swift/AST/FileSystem.h" #include "swift/AST/Module.h" #include "swift/AST/ModuleDependencies.h" @@ -30,28 +28,38 @@ #include "swift/Basic/STLExtras.h" #include "swift/ClangImporter/ClangImporter.h" #include "swift/DependencyScan/DependencyScanImpl.h" +#include "swift/DependencyScan/ScanDependencies.h" +#include "swift/DependencyScan/SerializedModuleDependencyCacheFormat.h" #include "swift/DependencyScan/StringUtils.h" +#include "swift/Frontend/CachingUtils.h" +#include "swift/Frontend/CompileJobCacheKey.h" #include "swift/Frontend/Frontend.h" #include "swift/Frontend/FrontendOptions.h" #include "swift/Frontend/ModuleInterfaceLoader.h" #include "swift/Strings.h" #include "clang/Basic/Module.h" -#include "llvm/ADT/SetVector.h" +#include "clang/Frontend/CompileJobCacheResult.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SetOperations.h" +#include "llvm/ADT/SetVector.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSet.h" +#include "llvm/CAS/ActionCache.h" +#include "llvm/CAS/CASReference.h" +#include "llvm/CAS/ObjectStore.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Support/Error.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/StringSaver.h" #include "llvm/Support/VirtualOutputBackend.h" #include "llvm/Support/YAMLParser.h" #include "llvm/Support/YAMLTraits.h" #include "llvm/Support/raw_ostream.h" +#include #include -#include #include -#include +#include using namespace swift; using namespace swift::dependencies; @@ -249,17 +257,56 @@ computeTransitiveClosureOfExplicitDependencies( return result; } -static void -resolveExplicitModuleInputs(ModuleDependencyID moduleID, - const ModuleDependencyInfo &resolvingDepInfo, - const std::set &dependencies, - ModuleDependenciesCache &cache) { - auto resolvingInterfaceDepDetails = - resolvingDepInfo.getAsSwiftInterfaceModule(); - assert(resolvingInterfaceDepDetails && - "Expected Swift Interface dependency."); +static llvm::Expected +updateModuleCacheKey(ModuleDependencyInfo &depInfo, + llvm::cas::ObjectStore &CAS) { + auto commandLine = depInfo.getCommandline(); + std::vector Args; + if (commandLine.size() > 1) + for (auto &c : ArrayRef(commandLine).drop_front(1)) + Args.push_back(c.c_str()); + + auto base = createCompileJobBaseCacheKey(CAS, Args); + if (!base) + return base.takeError(); + + StringRef InputPath; + file_types::ID OutputType = file_types::ID::TY_INVALID; + if (auto *dep = depInfo.getAsClangModule()) { + OutputType = file_types::ID::TY_ClangModuleFile; + InputPath = dep->moduleMapFile; + } else if (auto *dep = depInfo.getAsSwiftInterfaceModule()) { + OutputType = file_types::ID::TY_SwiftModuleFile; + InputPath = dep->swiftInterfaceFile; + } else + llvm_unreachable("Unhandled dependency kind"); + + auto key = + createCompileJobCacheKeyForOutput(CAS, *base, InputPath, OutputType); + if (!key) + return key.takeError(); + + depInfo.updateModuleCacheKey(CAS.getID(*key).toString()); + return *key; +} + +static llvm::Error resolveExplicitModuleInputs( + ModuleDependencyID moduleID, const ModuleDependencyInfo &resolvingDepInfo, + const std::set &dependencies, + ModuleDependenciesCache &cache, CompilerInstance &instance) { + // Only need to resolve dependency for following dependencies. + if (moduleID.second == ModuleDependencyKind::SwiftPlaceholder) + return llvm::Error::success(); - auto commandLine = resolvingInterfaceDepDetails->buildCommandLine; + std::vector rootIDs; + if (auto ID = resolvingDepInfo.getCASFSRootID()) + rootIDs.push_back(*ID); + + std::vector includeTrees; + if (auto ID = resolvingDepInfo.getClangIncludeTree()) + includeTrees.push_back(*ID); + + std::vector commandLine = resolvingDepInfo.getCommandline(); for (const auto &depModuleID : dependencies) { const auto optionalDepInfo = cache.findDependency(depModuleID.first, depModuleID.second); @@ -269,14 +316,20 @@ resolveExplicitModuleInputs(ModuleDependencyID moduleID, case swift::ModuleDependencyKind::SwiftInterface: { auto interfaceDepDetails = depInfo->getAsSwiftInterfaceModule(); assert(interfaceDepDetails && "Expected Swift Interface dependency."); + auto &path = interfaceDepDetails->moduleCacheKey.empty() + ? interfaceDepDetails->moduleOutputPath + : interfaceDepDetails->moduleCacheKey; commandLine.push_back("-swift-module-file=" + depModuleID.first + "=" + - interfaceDepDetails->moduleOutputPath); + path); } break; case swift::ModuleDependencyKind::SwiftBinary: { auto binaryDepDetails = depInfo->getAsSwiftBinaryModule(); assert(binaryDepDetails && "Expected Swift Binary Module dependency."); + auto &path = binaryDepDetails->moduleCacheKey.empty() + ? binaryDepDetails->compiledModulePath + : binaryDepDetails->moduleCacheKey; commandLine.push_back("-swift-module-file=" + depModuleID.first + "=" + - binaryDepDetails->compiledModulePath); + path); } break; case swift::ModuleDependencyKind::SwiftPlaceholder: { auto placeholderDetails = depInfo->getAsPlaceholderDependencyModule(); @@ -287,13 +340,65 @@ resolveExplicitModuleInputs(ModuleDependencyID moduleID, case swift::ModuleDependencyKind::Clang: { auto clangDepDetails = depInfo->getAsClangModule(); assert(clangDepDetails && "Expected Clang Module dependency."); - commandLine.push_back("-Xcc"); - commandLine.push_back("-fmodule-file=" + depModuleID.first + "=" + - clangDepDetails->pcmOutputPath); - commandLine.push_back("-Xcc"); - commandLine.push_back("-fmodule-map-file=" + - clangDepDetails->moduleMapFile); + if (!resolvingDepInfo.isClangModule()) { + commandLine.push_back("-Xcc"); + commandLine.push_back("-fmodule-file=" + depModuleID.first + "=" + + clangDepDetails->pcmOutputPath); + if (!instance.getInvocation() + .getClangImporterOptions() + .UseClangIncludeTree) { + commandLine.push_back("-Xcc"); + commandLine.push_back("-fmodule-map-file=" + + clangDepDetails->moduleMapFile); + } + } + if (!clangDepDetails->moduleCacheKey.empty()) { + auto appendXclang = [&]() { + if (!resolvingDepInfo.isClangModule()) { + // clang module build using cc1 arg so this is not needed. + commandLine.push_back("-Xcc"); + commandLine.push_back("-Xclang"); + } + commandLine.push_back("-Xcc"); + }; + appendXclang(); + commandLine.push_back("-fmodule-file-cache-key"); + appendXclang(); + commandLine.push_back(clangDepDetails->pcmOutputPath); + appendXclang(); + commandLine.push_back(clangDepDetails->moduleCacheKey); + } + + // Only need to merge the CASFS from clang importer. + if (auto ID = depInfo->getCASFSRootID()) + rootIDs.push_back(*ID); + if (auto ID = depInfo->getClangIncludeTree()) + includeTrees.push_back(*ID); } break; + case swift::ModuleDependencyKind::SwiftSource: { + auto sourceDepDetails = depInfo->getAsSwiftSourceModule(); + assert(sourceDepDetails && "Expected source dependency"); + if (sourceDepDetails->textualModuleDetails + .CASBridgingHeaderIncludeTreeRootID.empty()) { + if (!sourceDepDetails->textualModuleDetails.bridgingSourceFiles + .empty()) { + if (auto tracker = + cache.getScanService().createSwiftDependencyTracker()) { + tracker->startTracking(); + for (auto &file : + sourceDepDetails->textualModuleDetails.bridgingSourceFiles) + tracker->trackFile(file); + auto bridgeRoot = tracker->createTreeFromDependencies(); + if (!bridgeRoot) + return bridgeRoot.takeError(); + rootIDs.push_back(bridgeRoot->getID().toString()); + } + } + } else + includeTrees.push_back(sourceDepDetails->textualModuleDetails + .CASBridgingHeaderIncludeTreeRootID); + break; + } default: llvm_unreachable("Unhandled dependency kind."); } @@ -301,8 +406,88 @@ resolveExplicitModuleInputs(ModuleDependencyID moduleID, // Update the dependency in the cache with the modified command-line. auto dependencyInfoCopy = resolvingDepInfo; - dependencyInfoCopy.updateCommandLine(commandLine); + if (resolvingDepInfo.isSwiftInterfaceModule() || + resolvingDepInfo.isClangModule()) + dependencyInfoCopy.updateCommandLine(commandLine); + + // Handle CAS options. + if (instance.getInvocation().getFrontendOptions().EnableCAS) { + // Merge CASFS from clang dependency. + auto &CASFS = cache.getScanService().getSharedCachingFS(); + auto &CAS = CASFS.getCAS(); + + // Update build command line. + if (resolvingDepInfo.isSwiftInterfaceModule() || + resolvingDepInfo.isSwiftSourceModule()) { + // Update with casfs option. + std::vector newCommandLine = + dependencyInfoCopy.getCommandline(); + for (auto rootID : rootIDs) { + newCommandLine.push_back("-cas-fs"); + newCommandLine.push_back(rootID); + } + + for (auto tree : includeTrees) { + newCommandLine.push_back("-clang-include-tree-root"); + newCommandLine.push_back(tree); + } + dependencyInfoCopy.updateCommandLine(newCommandLine); + } + + if (auto *sourceDep = resolvingDepInfo.getAsSwiftSourceModule()) { + std::vector newCommandLine = + dependencyInfoCopy.getBridgingHeaderCommandline(); + for (auto bridgingDep : + sourceDep->textualModuleDetails.bridgingModuleDependencies) { + auto dep = + cache.findDependency(bridgingDep, ModuleDependencyKind::Clang); + assert(dep && "unknown clang dependency"); + auto *clangDep = (*dep)->getAsClangModule(); + assert(clangDep && "wrong module dependency kind"); + if (!clangDep->moduleCacheKey.empty()) { + newCommandLine.push_back("-Xcc"); + newCommandLine.push_back("-fmodule-file-cache-key"); + newCommandLine.push_back("-Xcc"); + newCommandLine.push_back(clangDep->pcmOutputPath); + newCommandLine.push_back("-Xcc"); + newCommandLine.push_back(clangDep->moduleCacheKey); + } + dependencyInfoCopy.updateBridgingHeaderCommandLine(newCommandLine); + } + } + + if (resolvingDepInfo.isClangModule() || + resolvingDepInfo.isSwiftInterfaceModule()) { + // Compute and update module cache key. + auto Key = updateModuleCacheKey(dependencyInfoCopy, CAS); + if (!Key) + return Key.takeError(); + } + + // For binary module, we need to make sure the lookup key is setup here in + // action cache. We just use the CASID of the binary module itself as key. + if (auto *binaryDep = dependencyInfoCopy.getAsSwiftBinaryModule()) { + auto Ref = + CASFS.getObjectRefForFileContent(binaryDep->compiledModulePath); + if (!Ref) + return llvm::errorCodeToError(Ref.getError()); + assert(*Ref && "Binary module should be loaded into CASFS already"); + dependencyInfoCopy.updateModuleCacheKey(CAS.getID(**Ref).toString()); + + clang::cas::CompileJobCacheResult::Builder Builder; + Builder.addOutput( + clang::cas::CompileJobCacheResult::OutputKind::MainOutput, **Ref); + auto Result = Builder.build(CAS); + if (!Result) + return Result.takeError(); + if (auto E = instance.getActionCache().put(CAS.getID(**Ref), + CAS.getID(*Result))) + return E; + } + } cache.updateDependency(moduleID, dependencyInfoCopy); + + return llvm::Error::success(); } /// Resolve the direct dependencies of the given module. @@ -363,11 +548,11 @@ resolveDirectDependencies(CompilerInstance &instance, ModuleDependencyID moduleI // A record of all of the Clang modules referenced from this Swift module. std::vector allClangModules; llvm::StringSet<> knownModules; + auto clangImporter = + static_cast(ctx.getClangModuleLoader()); // If the Swift module has a bridging header, add those dependencies. if (knownDependencies->getBridgingHeader()) { - auto clangImporter = - static_cast(ctx.getClangModuleLoader()); if (!clangImporter->addBridgingHeaderDependencies(moduleID.first, moduleID.second, cache)) { // Grab the updated module dependencies. @@ -477,7 +662,8 @@ static void discoverCrossImportOverlayDependencies( // Construct a dummy main to resolve the newly discovered cross import // overlays. StringRef dummyMainName = "DummyMainModuleForResolvingCrossImportOverlays"; - auto dummyMainDependencies = ModuleDependencyInfo::forSwiftSourceModule({}); + auto dummyMainDependencies = + ModuleDependencyInfo::forSwiftSourceModule({}, {}, {}, {}); std::for_each(newOverlays.begin(), newOverlays.end(), [&](Identifier modName) { dummyMainDependencies.addModuleImport(modName.str()); @@ -858,6 +1044,16 @@ static void writeJSON(llvm::raw_ostream &out, bool commaAfterFramework = swiftTextualDeps->extra_pcm_args->count != 0 || hasBridgingHeaderPath; + if (swiftTextualDeps->cas_fs_root_id.length != 0) { + writeJSONSingleField(out, "casFSRootID", + swiftTextualDeps->cas_fs_root_id, 5, + /*trailingComma=*/true); + } + if (swiftTextualDeps->module_cache_key.length != 0) { + writeJSONSingleField(out, "moduleCacheKey", + swiftTextualDeps->module_cache_key, 5, + /*trailingComma=*/true); + } writeJSONSingleField(out, "isFramework", swiftTextualDeps->is_framework, 5, commaAfterFramework); if (swiftTextualDeps->extra_pcm_args->count != 0) { @@ -886,16 +1082,36 @@ static void writeJSON(llvm::raw_ostream &out, writeJSONSingleField(out, "sourceFiles", swiftTextualDeps->bridging_source_files, 6, /*trailingComma=*/true); + if (swiftTextualDeps->bridging_header_include_tree.length != 0) { + writeJSONSingleField(out, "includeTree", + swiftTextualDeps->bridging_header_include_tree, + 6, /*trailingComma=*/true); + } writeJSONSingleField(out, "moduleDependencies", swiftTextualDeps->bridging_module_dependencies, 6, - /*trailingComma=*/false); + /*trailingComma=*/true); + out.indent(6 * 2); + out << "\"commandLine\": [\n"; + for (int i = 0, + count = swiftTextualDeps->bridging_pch_command_line->count; + i < count; ++i) { + const auto &arg = get_C_string( + swiftTextualDeps->bridging_pch_command_line->strings[i]); + out.indent(7 * 2); + out << "\"" << quote(arg) << "\""; + if (i != count - 1) + out << ","; + out << "\n"; + } + out.indent(6 * 2); + out << "]\n"; out.indent(5 * 2); out << (hasOverlayDependencies ? "},\n" : "}\n"); } if (hasOverlayDependencies) { writeDependencies(out, swiftTextualDeps->swift_overlay_module_dependencies, "swiftOverlayDependencies", 5, - /*trailingComma=*/true); + /*trailingComma=*/false); } } else if (swiftPlaceholderDeps) { out << "\"swiftPlaceholder\": {\n"; @@ -942,6 +1158,11 @@ static void writeJSON(llvm::raw_ostream &out, swiftBinaryDeps->module_source_info_path, /*indentLevel=*/5, /*trailingComma=*/true); + if (swiftBinaryDeps->module_cache_key.length != 0) { + writeJSONSingleField(out, "moduleCacheKey", + swiftBinaryDeps->module_cache_key, 5, + /*trailingComma=*/true); + } writeJSONSingleField(out, "isFramework", swiftBinaryDeps->is_framework, 5, /*trailingComma=*/false); } else { @@ -959,9 +1180,22 @@ static void writeJSON(llvm::raw_ostream &out, writeJSONSingleField(out, "commandLine", clangDeps->command_line, 5, /*trailingComma=*/true); + if (clangDeps->cas_fs_root_id.length != 0) + writeJSONSingleField(out, "casFSRootID", clangDeps->cas_fs_root_id, 5, + /*trailingComma=*/true); + if (clangDeps->clang_include_tree.length != 0) + writeJSONSingleField(out, "clangIncludeTree", + clangDeps->clang_include_tree, 5, + /*trailingComma=*/true); + if (clangDeps->module_cache_key.length != 0) + writeJSONSingleField(out, "moduleCacheKey", clangDeps->module_cache_key, + 5, + /*trailingComma=*/true); + // Captured PCM arguments. writeJSONSingleField(out, "capturedPCMArgs", clangDeps->captured_pcm_args, 5, /*trailingComma=*/false, /*nested=*/true); + } out.indent(4 * 2); @@ -1104,13 +1338,21 @@ generateFullDependencyGraph(CompilerInstance &instance, moduleInterfacePath, create_set(swiftTextualDeps->compiledModuleCandidates), bridgingHeaderPath, - create_set(swiftTextualDeps->textualModuleDetails.bridgingSourceFiles), - create_set(swiftTextualDeps->textualModuleDetails.bridgingModuleDependencies), + create_set( + swiftTextualDeps->textualModuleDetails.bridgingSourceFiles), + create_set(swiftTextualDeps->textualModuleDetails + .bridgingModuleDependencies), create_set(bridgedOverlayDependencyNames), - create_set(swiftTextualDeps->buildCommandLine), + create_set(swiftTextualDeps->textualModuleDetails.buildCommandLine), + /*bridgingHeaderBuildCommand*/ create_set({}), create_set(swiftTextualDeps->textualModuleDetails.extraPCMArgs), create_clone(swiftTextualDeps->contextHash.c_str()), - swiftTextualDeps->isFramework}; + swiftTextualDeps->isFramework, + create_clone(swiftTextualDeps->textualModuleDetails + .CASFileSystemRootID.c_str()), + create_clone(swiftTextualDeps->textualModuleDetails + .CASBridgingHeaderIncludeTreeRootID.c_str()), + create_clone(swiftTextualDeps->moduleCacheKey.c_str())}; } else if (swiftSourceDeps) { swiftscan_string_ref_t moduleInterfacePath = create_null(); swiftscan_string_ref_t bridgingHeaderPath = @@ -1128,13 +1370,23 @@ generateFullDependencyGraph(CompilerInstance &instance, moduleInterfacePath, create_empty_set(), bridgingHeaderPath, - create_set(swiftSourceDeps->textualModuleDetails.bridgingSourceFiles), - create_set(swiftSourceDeps->textualModuleDetails.bridgingModuleDependencies), + create_set( + swiftSourceDeps->textualModuleDetails.bridgingSourceFiles), + create_set(swiftSourceDeps->textualModuleDetails + .bridgingModuleDependencies), create_set(bridgedOverlayDependencyNames), - create_empty_set(), + create_set(swiftSourceDeps->textualModuleDetails.buildCommandLine), + create_set(swiftSourceDeps->bridgingHeaderBuildCommandLine), create_set(swiftSourceDeps->textualModuleDetails.extraPCMArgs), - /*contextHash*/create_null(), - /*isFramework*/false}; + /*contextHash*/ create_null(), + /*isFramework*/ false, + /*CASFS*/ + create_clone(swiftSourceDeps->textualModuleDetails + .CASFileSystemRootID.c_str()), + /*IncludeTree*/ + create_clone(swiftSourceDeps->textualModuleDetails + .CASBridgingHeaderIncludeTreeRootID.c_str()), + /*CacheKey*/ create_clone("")}; } else if (swiftPlaceholderDeps) { details->kind = SWIFTSCAN_DEPENDENCY_INFO_SWIFT_PLACEHOLDER; details->swift_placeholder_details = { @@ -1147,16 +1399,19 @@ generateFullDependencyGraph(CompilerInstance &instance, create_clone(swiftBinaryDeps->compiledModulePath.c_str()), create_clone(swiftBinaryDeps->moduleDocPath.c_str()), create_clone(swiftBinaryDeps->sourceInfoPath.c_str()), - swiftBinaryDeps->isFramework}; + swiftBinaryDeps->isFramework, + create_clone(swiftBinaryDeps->moduleCacheKey.c_str())}; } else { // Clang module details details->kind = SWIFTSCAN_DEPENDENCY_INFO_CLANG; details->clang_details = { create_clone(clangDeps->moduleMapFile.c_str()), create_clone(clangDeps->contextHash.c_str()), - create_set(clangDeps->nonPathCommandLine), - create_set(clangDeps->capturedPCMArgs) - }; + create_set(clangDeps->buildCommandLine), + create_set(clangDeps->capturedPCMArgs), + create_clone(clangDeps->CASFileSystemRootID.c_str()), + create_clone(clangDeps->CASClangIncludeTreeRootID.c_str()), + create_clone(clangDeps->moduleCacheKey.c_str())}; } return details; }; @@ -1353,8 +1608,9 @@ forEachBatchEntry(CompilerInstance &invocationInstance, return false; } -static ModuleDependencyInfo -identifyMainModuleDependencies(CompilerInstance &instance) { +static ModuleDependencyInfo identifyMainModuleDependencies( + CompilerInstance &instance, + Optional tracker = None) { ModuleDecl *mainModule = instance.getMainModule(); // Main module file name. auto newExt = file_types::getExtension(file_types::TY_SwiftModuleFile); @@ -1375,7 +1631,22 @@ identifyMainModuleDependencies(CompilerInstance &instance) { ExtraPCMArgs.insert(ExtraPCMArgs.begin(), {"-Xcc", "-target", "-Xcc", instance.getASTContext().LangOpts.Target.str()}); - auto mainDependencies = ModuleDependencyInfo::forSwiftSourceModule(ExtraPCMArgs); + + std::string rootID; + if (tracker) { + tracker->startTracking(); + for (auto fileUnit : mainModule->getFiles()) { + auto sf = dyn_cast(fileUnit); + if (!sf) + continue; + tracker->trackFile(sf->getFilename()); + } + auto root = cantFail(tracker->createTreeFromDependencies()); + rootID = root.getID().toString(); + } + + auto mainDependencies = + ModuleDependencyInfo::forSwiftSourceModule(rootID, {}, {}, ExtraPCMArgs); // Compute Implicit dependencies of the main module { @@ -1475,6 +1746,7 @@ bool swift::dependencies::scanDependencies(CompilerInstance &instance) { deserializeDependencyCache(instance, service); // Wrap the filesystem with a caching `DependencyScanningWorkerFilesystem` service.overlaySharedFilesystemCacheForCompilation(instance); + service.setupCachingDependencyScanningService(instance); ModuleDependenciesCache cache(service, instance.getMainModule()->getNameStr().str(), instance.getInvocation().getModuleScanningHash()); @@ -1542,6 +1814,7 @@ bool swift::dependencies::batchScanDependencies( SwiftDependencyScanningService singleUseService; singleUseService.overlaySharedFilesystemCacheForCompilation(instance); + singleUseService.setupCachingDependencyScanningService(instance); ModuleDependenciesCache cache(singleUseService, instance.getMainModule()->getNameStr().str(), instance.getInvocation().getModuleScanningHash()); @@ -1630,7 +1903,8 @@ swift::dependencies::performModuleScan(CompilerInstance &instance, ModuleDependenciesCache &cache) { ModuleDecl *mainModule = instance.getMainModule(); // First, identify the dependencies of the main module - auto mainDependencies = identifyMainModuleDependencies(instance); + auto mainDependencies = identifyMainModuleDependencies( + instance, cache.getScanService().createSwiftDependencyTracker()); auto &ctx = instance.getASTContext(); // Add the main module. @@ -1702,17 +1976,18 @@ swift::dependencies::performModuleScan(CompilerInstance &instance, auto moduleTransitiveClosures = computeTransitiveClosureOfExplicitDependencies(topoSortedModuleList, cache); - for (const auto &dependencyClosure : moduleTransitiveClosures) { - auto &modID = dependencyClosure.first; + for (const auto &modID : llvm::reverse(topoSortedModuleList)) { + auto dependencyClosure = moduleTransitiveClosures[modID]; // For main module or binary modules, no command-line to resolve. // For Clang modules, their dependencies are resolved by the clang Scanner // itself for us. - if (modID.second != ModuleDependencyKind::SwiftInterface) - continue; auto optionalDeps = cache.findDependency(modID.first, modID.second); assert(optionalDeps.has_value()); auto deps = optionalDeps.value(); - resolveExplicitModuleInputs(modID, *deps, dependencyClosure.second, cache); + if (auto E = resolveExplicitModuleInputs(modID, *deps, dependencyClosure, + cache, instance)) + instance.getDiags().diagnose(SourceLoc(), diag::error_cas, + toString(std::move(E))); } auto dependencyGraph = generateFullDependencyGraph( diff --git a/lib/Frontend/ArgsToFrontendOptionsConverter.cpp b/lib/Frontend/ArgsToFrontendOptionsConverter.cpp index 4074acd56a570..b7ff8bb6fb712 100644 --- a/lib/Frontend/ArgsToFrontendOptionsConverter.cpp +++ b/lib/Frontend/ArgsToFrontendOptionsConverter.cpp @@ -354,8 +354,11 @@ bool ArgsToFrontendOptionsConverter::convert( Opts.EnableCAS = Args.hasArg(OPT_enable_cas); Opts.CASPath = Args.getLastArgValue(OPT_cas_path, llvm::cas::getDefaultOnDiskCASPath()); - Opts.CASFSRootID = Args.getLastArgValue(OPT_cas_fs); - if (Opts.EnableCAS && Opts.CASFSRootID.empty() && + Opts.CASFSRootIDs = Args.getAllArgValues(OPT_cas_fs); + Opts.ClangIncludeTrees = Args.getAllArgValues(OPT_clang_include_tree_root); + + if (Opts.EnableCAS && Opts.CASFSRootIDs.empty() && + Opts.ClangIncludeTrees.empty() && FrontendOptions::supportCompilationCaching(Opts.RequestedAction)) { if (!Args.hasArg(OPT_allow_unstable_cache_key_for_testing)) { Diags.diagnose(SourceLoc(), diag::error_caching_no_cas_fs); diff --git a/lib/Frontend/CachingUtils.cpp b/lib/Frontend/CachingUtils.cpp index 721158a735701..cb6435d887120 100644 --- a/lib/Frontend/CachingUtils.cpp +++ b/lib/Frontend/CachingUtils.cpp @@ -15,13 +15,19 @@ #include "swift/AST/DiagnosticsFrontend.h" #include "swift/Basic/FileTypes.h" #include "swift/Frontend/CompileJobCacheKey.h" +#include "clang/CAS/IncludeTree.h" #include "clang/Frontend/CompileJobCacheResult.h" #include "llvm/ADT/STLExtras.h" #include "llvm/CAS/BuiltinUnifiedCASDatabases.h" +#include "llvm/CAS/CASFileSystem.h" +#include "llvm/CAS/HierarchicalTreeBuilder.h" #include "llvm/CAS/ObjectStore.h" +#include "llvm/CAS/TreeEntry.h" #include "llvm/Support/Debug.h" +#include "llvm/Support/Error.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Path.h" +#include "llvm/Support/VirtualFileSystem.h" #include "llvm/Support/VirtualOutputBackends.h" #include "llvm/Support/VirtualOutputFile.h" #include @@ -342,4 +348,121 @@ Error storeCachedCompilerOutput(llvm::cas::ObjectStore &CAS, return Error::success(); } +static llvm::Error createCASObjectNotFoundError(const llvm::cas::CASID &ID) { + return createStringError(llvm::inconvertibleErrorCode(), + "CASID missing from Object Store " + ID.toString()); +} + +static Expected mergeCASFileSystem(ObjectStore &CAS, + ArrayRef FSRoots) { + llvm::cas::HierarchicalTreeBuilder Builder; + for (auto &Root : FSRoots) { + auto ID = CAS.parseID(Root); + if (!ID) + return ID.takeError(); + + auto Ref = CAS.getReference(*ID); + if (!Ref) + return createCASObjectNotFoundError(*ID); + Builder.pushTreeContent(*Ref, ""); + } + + auto NewRoot = Builder.create(CAS); + if (!NewRoot) + return NewRoot.takeError(); + + return NewRoot->getRef(); +} + +Expected> +createCASFileSystem(ObjectStore &CAS, ArrayRef FSRoots, + ArrayRef IncludeTrees) { + assert(!FSRoots.empty() || !IncludeTrees.empty() && "no root ID provided"); + if (FSRoots.size() == 1 && IncludeTrees.empty()) { + auto ID = CAS.parseID(FSRoots.front()); + if (!ID) + return ID.takeError(); + auto Ref = CAS.getReference(*ID); + if (!Ref) + return createCASObjectNotFoundError(*ID); + } + + auto NewRoot = mergeCASFileSystem(CAS, FSRoots); + if (!NewRoot) + return NewRoot.takeError(); + + auto FS = createCASFileSystem(CAS, CAS.getID(*NewRoot)); + if (!FS) + return FS.takeError(); + + auto CASFS = makeIntrusiveRefCnt(std::move(*FS)); + // Push all Include File System onto overlay. + for (auto &Tree : IncludeTrees) { + auto ID = CAS.parseID(Tree); + if (!ID) + return ID.takeError(); + + auto Ref = CAS.getReference(*ID); + if (!Ref) + return createCASObjectNotFoundError(*ID); + auto IT = clang::cas::IncludeTreeRoot::get(CAS, *Ref); + if (!IT) + return IT.takeError(); + + auto ITFS = clang::cas::createIncludeTreeFileSystem(*IT); + if (!ITFS) + return ITFS.takeError(); + CASFS->pushOverlay(std::move(*ITFS)); + } + + return CASFS; +} + +namespace cas { + +CachingTool::CachingTool(StringRef Path) { + auto DB = llvm::cas::createOnDiskUnifiedCASDatabases(Path); + if (!DB) { + llvm::errs() << "Failed to create CAS at " << Path << ": " + << toString(DB.takeError()) << "\n"; + return; + } + + CAS = std::move(DB->first); + Cache = std::move(DB->second); +} + +std::string CachingTool::computeCacheKey(ArrayRef Args, + StringRef InputPath, + file_types::ID OutputKind) { + auto BaseKey = createCompileJobBaseCacheKey(*CAS, Args); + if (!BaseKey) { + llvm::errs() << "Failed to create cache key: " + << toString(BaseKey.takeError()) << "\n"; + return ""; + } + + auto Key = + createCompileJobCacheKeyForOutput(*CAS, *BaseKey, InputPath, OutputKind); + if (!Key) { + llvm::errs() << "Failed to create cache key: " << toString(Key.takeError()) + << "\n"; + return ""; + } + + return CAS->getID(*Key).toString(); +} + +std::string CachingTool::storeContent(StringRef Content) { + auto Result = CAS->storeFromString({}, Content); + if (!Result) { + llvm::errs() << "Failed to store to CAS: " << toString(Result.takeError()) + << "\n"; + return ""; + } + + return CAS->getID(*Result).toString(); +} + +} // namespace cas } // namespace swift diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index c75d5a467a4bd..d6c547c76d293 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -1438,12 +1438,15 @@ static bool ParseClangImporterArgs(ClangImporterOptions &Opts, Opts.ExtraArgs.push_back("-fdebug-prefix-map=" + Val); } - if (!workingDirectory.empty()) { - // Provide a working directory to Clang as well if there are any -Xcc - // options, in case some of them are search-related. But do it at the - // beginning, so that an explicit -Xcc -working-directory will win. - Opts.ExtraArgs.insert(Opts.ExtraArgs.begin(), - {"-working-directory", workingDirectory.str()}); + if (FrontendOpts.CASFSRootIDs.empty() && + FrontendOpts.ClangIncludeTrees.empty()) { + if (!workingDirectory.empty()) { + // Provide a working directory to Clang as well if there are any -Xcc + // options, in case some of them are search-related. But do it at the + // beginning, so that an explicit -Xcc -working-directory will win. + Opts.ExtraArgs.insert(Opts.ExtraArgs.begin(), + {"-working-directory", workingDirectory.str()}); + } } Opts.DumpClangDiagnostics |= Args.hasArg(OPT_dump_clang_diagnostics); @@ -1463,6 +1466,8 @@ static bool ParseClangImporterArgs(ClangImporterOptions &Opts, if (auto *A = Args.getLastArg(OPT_import_objc_header)) Opts.BridgingHeader = A->getValue(); + Opts.BridgingHeaderPCHCacheKey = + Args.getLastArgValue(OPT_bridging_header_pch_key); Opts.DisableSwiftBridgeAttr |= Args.hasArg(OPT_disable_swift_bridge_attr); Opts.DisableOverlayModules |= Args.hasArg(OPT_emit_imported_modules); @@ -1473,6 +1478,7 @@ static bool ParseClangImporterArgs(ClangImporterOptions &Opts, Opts.ExtraArgsOnly |= Args.hasArg(OPT_extra_clang_options_only); Opts.DirectClangCC1ModuleBuild |= Args.hasArg(OPT_direct_clang_cc1_module_build); + Opts.UseClangIncludeTree |= Args.hasArg(OPT_clang_include_tree); if (const Arg *A = Args.getLastArg(OPT_pch_output_dir)) { Opts.PrecompiledHeaderOutputDir = A->getValue(); diff --git a/lib/Frontend/Frontend.cpp b/lib/Frontend/Frontend.cpp index 461c34938b15c..b65e628b31953 100644 --- a/lib/Frontend/Frontend.cpp +++ b/lib/Frontend/Frontend.cpp @@ -439,22 +439,6 @@ bool CompilerInstance::setupCASIfNeeded(ArrayRef Args) { ResultCache = std::move(MaybeCache->second); // create baseline key. - llvm::Optional FSRef; - if (!Opts.CASFSRootID.empty()) { - auto CASFSID = CAS->parseID(Opts.CASFSRootID); - if (!CASFSID) { - Diagnostics.diagnose(SourceLoc(), diag::error_cas, - toString(CASFSID.takeError())); - return true; - } - FSRef = CAS->getReference(*CASFSID); - if (!FSRef) { - Diagnostics.diagnose(SourceLoc(), diag::error_cas, - "-cas-fs value does not exist in CAS"); - return true; - } - } - auto BaseKey = createCompileJobBaseCacheKey(*CAS, Args); if (!BaseKey) { Diagnostics.diagnose(SourceLoc(), diag::error_cas, @@ -561,25 +545,39 @@ bool CompilerInstance::setup(const CompilerInvocation &Invoke, bool CompilerInstance::setUpVirtualFileSystemOverlays() { if (Invocation.getFrontendOptions().EnableCAS && - !Invocation.getFrontendOptions().CASFSRootID.empty()) { + (!Invocation.getFrontendOptions().CASFSRootIDs.empty() || + !Invocation.getFrontendOptions().ClangIncludeTrees.empty())) { // Set up CASFS as BaseFS. - auto RootID = CAS->parseID(Invocation.getFrontendOptions().CASFSRootID); - if (!RootID) { - Diagnostics.diagnose(SourceLoc(), diag::error_invalid_cas_id, - Invocation.getFrontendOptions().CASFSRootID, - toString(RootID.takeError())); - return true; - } - auto FS = llvm::cas::createCASFileSystem(*CAS, *RootID); + const auto &Opts = getInvocation().getFrontendOptions(); + auto FS = + createCASFileSystem(*CAS, Opts.CASFSRootIDs, Opts.ClangIncludeTrees); if (!FS) { - Diagnostics.diagnose(SourceLoc(), diag::error_invalid_cas_id, - Invocation.getFrontendOptions().CASFSRootID, + Diagnostics.diagnose(SourceLoc(), diag::error_cas, toString(FS.takeError())); return true; } SourceMgr.setFileSystem(std::move(*FS)); } + // If we have a bridging header cache key, try load it now and overlay it. + if (!Invocation.getClangImporterOptions().BridgingHeaderPCHCacheKey.empty() && + Invocation.getFrontendOptions().EnableCAS) { + auto loadedBridgingBuffer = loadCachedCompileResultFromCacheKey( + getObjectStore(), getActionCache(), Diagnostics, + Invocation.getClangImporterOptions().BridgingHeaderPCHCacheKey, + Invocation.getClangImporterOptions().BridgingHeader); + if (loadedBridgingBuffer) { + llvm::IntrusiveRefCntPtr PCHFS = + new llvm::vfs::InMemoryFileSystem(); + PCHFS->addFile(Invocation.getClangImporterOptions().BridgingHeader, 0, + std::move(loadedBridgingBuffer)); + llvm::IntrusiveRefCntPtr OverlayVFS = + new llvm::vfs::OverlayFileSystem(SourceMgr.getFileSystem()); + OverlayVFS->pushOverlay(PCHFS); + SourceMgr.setFileSystem(std::move(OverlayVFS)); + } + } + auto ExpectedOverlay = Invocation.getSearchPathOptions().makeOverlayFileSystem( SourceMgr.getFileSystem()); @@ -701,17 +699,24 @@ bool CompilerInstance::setUpModuleLoaders() { // If using `-explicit-swift-module-map-file`, create the explicit loader // before creating `ClangImporter` because the entries in the map influence // the Clang flags. The loader is added to the context below. - std::unique_ptr ESML = nullptr; + std::unique_ptr ESML = nullptr; bool ExplicitModuleBuild = Invocation.getFrontendOptions().DisableImplicitModules; if (ExplicitModuleBuild || !Invocation.getSearchPathOptions().ExplicitSwiftModuleMap.empty() || !Invocation.getSearchPathOptions().ExplicitSwiftModuleInputs.empty()) { - ESML = ExplicitSwiftModuleLoader::create( - *Context, getDependencyTracker(), MLM, - Invocation.getSearchPathOptions().ExplicitSwiftModuleMap, - Invocation.getSearchPathOptions().ExplicitSwiftModuleInputs, - IgnoreSourceInfoFile); + if (Invocation.getFrontendOptions().EnableCAS) + ESML = ExplicitCASModuleLoader::create( + *Context, getObjectStore(), getActionCache(), getDependencyTracker(), + MLM, Invocation.getSearchPathOptions().ExplicitSwiftModuleMap, + Invocation.getSearchPathOptions().ExplicitSwiftModuleInputs, + IgnoreSourceInfoFile); + else + ESML = ExplicitSwiftModuleLoader::create( + *Context, getDependencyTracker(), MLM, + Invocation.getSearchPathOptions().ExplicitSwiftModuleMap, + Invocation.getSearchPathOptions().ExplicitSwiftModuleInputs, + IgnoreSourceInfoFile); } // Wire up the Clang importer. If the user has specified an SDK, use it. @@ -839,6 +844,12 @@ std::string CompilerInstance::getBridgingHeaderPath() const { } bool CompilerInstance::setUpInputs() { + // There is no input file when building PCM using ClangIncludeTree. + if (Invocation.getFrontendOptions().RequestedAction == + FrontendOptions::ActionType::EmitPCM && + Invocation.getClangImporterOptions().UseClangIncludeTree) + return false; + // Adds to InputSourceCodeBufferIDs, so may need to happen before the // per-input setup. const Optional ideInspectionTargetBufferID = diff --git a/lib/Frontend/ModuleInterfaceLoader.cpp b/lib/Frontend/ModuleInterfaceLoader.cpp index 437fa6090a0df..af9a42220d986 100644 --- a/lib/Frontend/ModuleInterfaceLoader.cpp +++ b/lib/Frontend/ModuleInterfaceLoader.cpp @@ -20,6 +20,7 @@ #include "swift/AST/FileSystem.h" #include "swift/AST/Module.h" #include "swift/Basic/Platform.h" +#include "swift/Frontend/CachingUtils.h" #include "swift/Frontend/Frontend.h" #include "swift/Frontend/ModuleInterfaceSupport.h" #include "swift/Parse/ParseVersion.h" @@ -28,6 +29,7 @@ #include "swift/Serialization/Validation.h" #include "swift/Strings.h" #include "clang/Basic/Module.h" +#include "clang/Frontend/CompileJobCacheResult.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Lex/HeaderSearch.h" #include "clang/Lex/Preprocessor.h" @@ -36,9 +38,12 @@ #include "llvm/ADT/Hashing.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/CAS/ActionCache.h" +#include "llvm/CAS/ObjectStore.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/Errc.h" +#include "llvm/Support/Error.h" #include "llvm/Support/Path.h" #include "llvm/Support/VirtualOutputBackend.h" #include "llvm/Support/YAMLParser.h" @@ -1572,6 +1577,20 @@ void InterfaceSubContextDelegateImpl::inheritOptionsForBuildingInterface( GenericArgs.push_back("-clang-build-session-file"); GenericArgs.push_back(clangImporterOpts.BuildSessionFilePath); } + + if (!clangImporterOpts.CASPath.empty()) { + genericSubInvocation.getClangImporterOptions().CASPath = + clangImporterOpts.CASPath; + GenericArgs.push_back("-enable-cas"); + GenericArgs.push_back("-cas-path"); + GenericArgs.push_back(clangImporterOpts.CASPath); + } + + if (clangImporterOpts.UseClangIncludeTree) { + genericSubInvocation.getClangImporterOptions().UseClangIncludeTree = + clangImporterOpts.UseClangIncludeTree; + GenericArgs.push_back("-clang-include-tree"); + } } bool InterfaceSubContextDelegateImpl::extractSwiftInterfaceVersionAndArgs( @@ -1661,6 +1680,7 @@ InterfaceSubContextDelegateImpl::InterfaceSubContextDelegateImpl( // required by sourcekitd. subClangImporterOpts.DetailedPreprocessingRecord = clangImporterOpts.DetailedPreprocessingRecord; + subClangImporterOpts.CASPath = clangImporterOpts.CASPath; // If the compiler has been asked to be strict with ensuring downstream dependencies // get the parent invocation's context, or this is an Explicit build, inherit the @@ -1941,15 +1961,22 @@ struct ExplicitSwiftModuleLoader::Implementation { void parseSwiftExplicitModuleMap(StringRef fileName) { ExplicitModuleMapParser parser(Allocator); llvm::StringMap ExplicitClangModuleMap; - auto result = - parser.parseSwiftExplicitModuleMap(fileName, ExplicitModuleMap, - ExplicitClangModuleMap); - if (result == std::errc::invalid_argument) - Ctx.Diags.diagnose(SourceLoc(), diag::explicit_swift_module_map_corrupted, - fileName); - else if (result == std::errc::no_such_file_or_directory) + // Load the input file. + llvm::ErrorOr> fileBufOrErr = + llvm::MemoryBuffer::getFile(fileName); + if (!fileBufOrErr) { Ctx.Diags.diagnose(SourceLoc(), diag::explicit_swift_module_map_missing, fileName); + return; + } + + auto hasError = parser.parseSwiftExplicitModuleMap( + (*fileBufOrErr)->getMemBufferRef(), ExplicitModuleMap, + ExplicitClangModuleMap); + + if (hasError) + Ctx.Diags.diagnose(SourceLoc(), diag::explicit_swift_module_map_corrupted, + fileName); // A single module map can define multiple modules; keep track of the ones // we've seen so that we don't generate duplicate flags. @@ -2154,3 +2181,333 @@ ExplicitSwiftModuleLoader::create(ASTContext &ctx, return result; } + +struct ExplicitCASModuleLoader::Implementation { + ASTContext &Ctx; + llvm::BumpPtrAllocator Allocator; + llvm::cas::ObjectStore &CAS; + llvm::cas::ActionCache &Cache; + + llvm::StringMap ExplicitModuleMap; + + Implementation(ASTContext &Ctx, llvm::cas::ObjectStore &CAS, + llvm::cas::ActionCache &Cache) + : Ctx(Ctx), CAS(CAS), Cache(Cache) {} + + llvm::Expected> loadBuffer(StringRef ID) { + auto key = CAS.parseID(ID); + if (!key) + return key.takeError(); + + auto ref = CAS.getReference(*key); + if (!ref) + return nullptr; + + auto loaded = CAS.getProxy(*ref); + if (!loaded) + return loaded.takeError(); + + return loaded->getMemoryBuffer(); + } + + // Same as the regular explicit module map but must be loaded from + // CAS, instead of a file that is not tracked by the dependency. + void parseSwiftExplicitModuleMap(StringRef ID) { + ExplicitModuleMapParser parser(Allocator); + llvm::StringMap ExplicitClangModuleMap; + auto buf = loadBuffer(ID); + if (!buf) { + Ctx.Diags.diagnose(SourceLoc(), diag::error_cas, + toString(buf.takeError())); + return; + } + if (!*buf) { + Ctx.Diags.diagnose(SourceLoc(), diag::explicit_swift_module_map_missing, + ID); + return; + } + llvm::ErrorOr> fileBufOrErr = + llvm::MemoryBuffer::getFile(ID); + + auto hasError = parser.parseSwiftExplicitModuleMap( + (*buf)->getMemBufferRef(), ExplicitModuleMap, ExplicitClangModuleMap); + + if (hasError) + Ctx.Diags.diagnose(SourceLoc(), diag::explicit_swift_module_map_corrupted, + ID); + + std::set moduleMapsSeen; + std::vector &extraClangArgs = Ctx.ClangImporterOpts.ExtraArgs; + for (auto &entry : ExplicitClangModuleMap) { + const auto &moduleMapPath = entry.getValue().moduleMapPath; + if (!moduleMapPath.empty() && + !Ctx.ClangImporterOpts.UseClangIncludeTree && + moduleMapsSeen.find(moduleMapPath) == moduleMapsSeen.end()) { + moduleMapsSeen.insert(moduleMapPath); + extraClangArgs.push_back( + (Twine("-fmodule-map-file=") + moduleMapPath).str()); + } + + const auto &modulePath = entry.getValue().modulePath; + if (!modulePath.empty()) { + extraClangArgs.push_back( + (Twine("-fmodule-file=") + entry.getKey() + "=" + modulePath) + .str()); + } + auto cachePath = entry.getValue().moduleCacheKey; + if (cachePath) { + extraClangArgs.push_back("-Xclang"); + extraClangArgs.push_back("-fmodule-file-cache-key"); + extraClangArgs.push_back("-Xclang"); + extraClangArgs.push_back(modulePath); + extraClangArgs.push_back("-Xclang"); + extraClangArgs.push_back(*cachePath); + } + } + } + + void addCommandLineExplicitInputs( + const std::vector> + &commandLineExplicitInputs) { + for (const auto &moduleInput : commandLineExplicitInputs) { + ExplicitSwiftModuleInputInfo entry(moduleInput.second, {}, {}); + ExplicitModuleMap.try_emplace(moduleInput.first, std::move(entry)); + } + } + + llvm::Expected> + loadFileBuffer(StringRef ID, StringRef Name) { + auto key = CAS.parseID(ID); + if (!key) + return key.takeError(); + + auto moduleLookup = Cache.get(*key); + if (!moduleLookup) + return moduleLookup.takeError(); + if (!*moduleLookup) + return nullptr; + + auto moduleRef = CAS.getReference(**moduleLookup); + if (!moduleRef) + return nullptr; + + clang::cas::CompileJobResultSchema schema(CAS); + auto result = schema.load(*moduleRef); + if (!result) + return result.takeError(); + auto output = result->getOutput( + clang::cas::CompileJobCacheResult::OutputKind::MainOutput); + if (!output) + return nullptr; + + auto buf = CAS.getProxy(output->Object); + if (!buf) + return buf.takeError(); + + return buf->getMemoryBuffer(Name); + } + + llvm::Expected> + loadModuleFromPath(StringRef Path, DiagnosticEngine &Diags) { + for (auto &Deps : ExplicitModuleMap) { + if (Deps.second.modulePath == Path) { + if (!Deps.second.moduleCacheKey) + return nullptr; + return loadCachedCompileResultFromCacheKey( + CAS, Cache, Diags, *Deps.second.moduleCacheKey, Path); + } + } + return nullptr; + } +}; + +ExplicitCASModuleLoader::ExplicitCASModuleLoader(ASTContext &ctx, + llvm::cas::ObjectStore &CAS, + llvm::cas::ActionCache &cache, + DependencyTracker *tracker, + ModuleLoadingMode loadMode, + bool IgnoreSwiftSourceInfoFile) + : SerializedModuleLoaderBase(ctx, tracker, loadMode, + IgnoreSwiftSourceInfoFile), + Impl(*new Implementation(ctx, CAS, cache)) {} + +ExplicitCASModuleLoader::~ExplicitCASModuleLoader() { delete &Impl; } + +bool ExplicitCASModuleLoader::findModule( + ImportPath::Element ModuleID, SmallVectorImpl *ModuleInterfacePath, + SmallVectorImpl *ModuleInterfaceSourcePath, + std::unique_ptr *ModuleBuffer, + std::unique_ptr *ModuleDocBuffer, + std::unique_ptr *ModuleSourceInfoBuffer, + bool skipBuildingInterface, bool isTestableDependencyLookup, + bool &IsFramework, bool &IsSystemModule) { + // Find a module with an actual, physical name on disk, in case + // -module-alias is used (otherwise same). + // + // For example, if '-module-alias Foo=Bar' is passed in to the frontend, and + // an input file has 'import Foo', a module called Bar (real name) should be + // searched. + StringRef moduleName = Ctx.getRealModuleName(ModuleID.Item).str(); + + auto it = Impl.ExplicitModuleMap.find(moduleName); + // If no explicit module path is given matches the name, return with an + // error code. + if (it == Impl.ExplicitModuleMap.end()) { + return false; + } + auto &moduleInfo = it->getValue(); + + // Set IsFramework bit according to the moduleInfo + IsFramework = moduleInfo.isFramework; + IsSystemModule = moduleInfo.isSystem; + + // Fallback check for module cache key passed on command-line as module path. + std::string moduleCASID = moduleInfo.moduleCacheKey + ? *moduleInfo.moduleCacheKey + : moduleInfo.modulePath; + + // FIXME: the loaded module buffer doesn't set an identifier so it + // is not tracked in dependency tracker, which doesn't handle modules + // that are not located on disk. + auto moduleBuf = loadCachedCompileResultFromCacheKey(Impl.CAS, Impl.Cache, + Ctx.Diags, moduleCASID); + if (!moduleBuf) { + // We cannot read the module content, diagnose. + Ctx.Diags.diagnose(SourceLoc(), diag::error_opening_explicit_module_file, + moduleInfo.modulePath); + return false; + } + + const bool isForwardingModule = + !serialization::isSerializedAST(moduleBuf->getBuffer()); + // If the module is a forwarding module, read the actual content from the path + // encoded in the forwarding module as the actual module content. + if (isForwardingModule) { + auto forwardingModule = ForwardingModule::load(*moduleBuf.get()); + if (forwardingModule) { + // Look through ExplicitModuleMap for paths. + // TODO: need to have dependency scanner reports forwarded module as + // dependency for this compilation and ingested into CAS. + auto moduleOrErr = Impl.loadModuleFromPath( + forwardingModule->underlyingModulePath, Ctx.Diags); + if (!moduleOrErr) { + llvm::consumeError(moduleOrErr.takeError()); + Ctx.Diags.diagnose(SourceLoc(), + diag::error_opening_explicit_module_file, + moduleInfo.modulePath); + return false; + } + moduleBuf = std::move(*moduleOrErr); + if (!moduleBuf) { + // We cannot read the module content, diagnose. + Ctx.Diags.diagnose(SourceLoc(), + diag::error_opening_explicit_module_file, + moduleInfo.modulePath); + return false; + } + } else { + // We cannot read the module content, diagnose. + Ctx.Diags.diagnose(SourceLoc(), diag::error_opening_explicit_module_file, + moduleInfo.modulePath); + return false; + } + } + assert(moduleBuf); + // Move the opened module buffer to the caller. + *ModuleBuffer = std::move(moduleBuf); + + // TODO: support .swiftdoc file and .swiftsourceinfo file + return true; +} + +std::error_code ExplicitCASModuleLoader::findModuleFilesInDirectory( + ImportPath::Element ModuleID, const SerializedModuleBaseName &BaseName, + SmallVectorImpl *ModuleInterfacePath, + SmallVectorImpl *ModuleInterfaceSourcePath, + std::unique_ptr *ModuleBuffer, + std::unique_ptr *ModuleDocBuffer, + std::unique_ptr *ModuleSourceInfoBuffer, + bool skipBuildingInterface, bool IsFramework, + bool IsTestableDependencyLookup) { + llvm_unreachable("Not supported in the Explicit Swift Module Loader."); + return std::make_error_code(std::errc::not_supported); +} + +bool ExplicitCASModuleLoader::canImportModule( + ImportPath::Module path, ModuleVersionInfo *versionInfo, + bool isTestableDependencyLookup) { + // FIXME: Swift submodules? + if (path.hasSubmodule()) + return false; + ImportPath::Element mID = path.front(); + // Look up the module with the real name (physical name on disk); + // in case `-module-alias` is used, the name appearing in source files + // and the real module name are different. For example, '-module-alias + // Foo=Bar' maps Foo appearing in source files, e.g. 'import Foo', to the real + // module name Bar (on-disk name), which should be searched for loading. + StringRef moduleName = Ctx.getRealModuleName(mID.Item).str(); + auto it = Impl.ExplicitModuleMap.find(moduleName); + // If no provided explicit module matches the name, then it cannot be + // imported. + if (it == Impl.ExplicitModuleMap.end()) { + return false; + } + + // If the caller doesn't want version info we're done. + if (!versionInfo) + return true; + + // Open .swiftmodule file and read out the version + std::string moduleCASID = it->second.moduleCacheKey + ? *it->second.moduleCacheKey + : it->second.modulePath; + auto moduleBuf = Impl.loadFileBuffer(moduleCASID, it->second.modulePath); + if (!moduleBuf) { + Ctx.Diags.diagnose(SourceLoc(), diag::error_cas, + toString(moduleBuf.takeError())); + return false; + } + if (!*moduleBuf) { + Ctx.Diags.diagnose(SourceLoc(), diag::error_opening_explicit_module_file, + it->second.modulePath); + return false; + } + auto metaData = serialization::validateSerializedAST( + (*moduleBuf)->getBuffer(), Ctx.SILOpts.EnableOSSAModules, + Ctx.LangOpts.SDKName, !Ctx.LangOpts.DebuggerSupport); + versionInfo->setVersion(metaData.userModuleVersion, + ModuleVersionSourceKind::SwiftBinaryModule); + return true; +} + +void ExplicitCASModuleLoader::collectVisibleTopLevelModuleNames( + SmallVectorImpl &names) const { + for (auto &entry : Impl.ExplicitModuleMap) { + names.push_back(Ctx.getIdentifier(entry.getKey())); + } +} + +std::unique_ptr ExplicitCASModuleLoader::create( + ASTContext &ctx, llvm::cas::ObjectStore &CAS, llvm::cas::ActionCache &cache, + DependencyTracker *tracker, ModuleLoadingMode loadMode, + StringRef ExplicitSwiftModuleMap, + const std::vector> + &ExplicitSwiftModuleInputs, + bool IgnoreSwiftSourceInfoFile) { + auto result = + std::unique_ptr(new ExplicitCASModuleLoader( + ctx, CAS, cache, tracker, loadMode, IgnoreSwiftSourceInfoFile)); + auto &Impl = result->Impl; + // If the explicit module map is given, try parse it. + if (!ExplicitSwiftModuleMap.empty()) { + // Parse a JSON file to collect explicitly built modules. + Impl.parseSwiftExplicitModuleMap(ExplicitSwiftModuleMap); + } + // If some modules are provided with explicit + // '-swift-module-file' options, add those as well. + if (!ExplicitSwiftModuleInputs.empty()) { + Impl.addCommandLineExplicitInputs(ExplicitSwiftModuleInputs); + } + + return result; +} diff --git a/lib/Serialization/ModuleDependencyScanner.cpp b/lib/Serialization/ModuleDependencyScanner.cpp index 2d3de471e0247..ecac3a5160d83 100644 --- a/lib/Serialization/ModuleDependencyScanner.cpp +++ b/lib/Serialization/ModuleDependencyScanner.cpp @@ -22,6 +22,10 @@ #include "swift/Serialization/SerializedModuleLoader.h" #include "swift/Serialization/ModuleDependencyScanner.h" #include "swift/Subsystems.h" +#include "llvm/ADT/IntrusiveRefCntPtr.h" +#include "llvm/CAS/CachingOnDiskFileSystem.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/VirtualFileSystem.h" #include "ModuleFileSharedCore.h" #include @@ -151,11 +155,6 @@ ErrorOr ModuleDependencyScanner::scanInterfaceFile( Args.push_back("-o"); Args.push_back(outputPathBase.str().str()); - std::vector ArgsRefs(Args.begin(), Args.end()); - Result = ModuleDependencyInfo::forSwiftInterfaceModule( - outputPathBase.str().str(), InPath, compiledCandidates, ArgsRefs, PCMArgs, - Hash, isFramework); - // Open the interface file. auto &fs = *Ctx.SourceMgr.getFileSystem(); auto interfaceBuf = fs.getBufferForFile(moduleInterfacePath); @@ -172,6 +171,21 @@ ErrorOr ModuleDependencyScanner::scanInterfaceFile( *moduleDecl, SourceFileKind::Interface, bufferID, parsingOpts); moduleDecl->addAuxiliaryFile(*sourceFile); + std::string RootID; + if (dependencyTracker) { + dependencyTracker->startTracking(); + dependencyTracker->trackFile(moduleInterfacePath); + auto RootOrError = dependencyTracker->createTreeFromDependencies(); + if (!RootOrError) + return llvm::errorToErrorCode(RootOrError.takeError()); + RootID = RootOrError->getID().toString(); + } + + std::vector ArgsRefs(Args.begin(), Args.end()); + Result = ModuleDependencyInfo::forSwiftInterfaceModule( + outputPathBase.str().str(), InPath, compiledCandidates, ArgsRefs, + PCMArgs, Hash, isFramework, RootID, /*module-cache-key*/ ""); + // Walk the source file to find the import declarations. llvm::StringSet<> alreadyAddedModules; Result->addModuleImport(*sourceFile, alreadyAddedModules); @@ -255,9 +269,10 @@ Optional SerializedModuleLoaderBase::getModuleDepen // FIXME: submodules? scanners.push_back(std::make_unique( Ctx, LoadMode, moduleId, Ctx.SearchPathOpts.PlaceholderDependencyModuleMap, - delegate)); + delegate, cache.getScanService().createSwiftDependencyTracker())); scanners.push_back(std::make_unique( - Ctx, LoadMode, moduleId, delegate)); + Ctx, LoadMode, moduleId, delegate, ModuleDependencyScanner::MDS_plain, + cache.getScanService().createSwiftDependencyTracker())); // Check whether there is a module with this name that we can import. assert(isa(scanners[0].get()) && diff --git a/lib/Serialization/SerializedModuleLoader.cpp b/lib/Serialization/SerializedModuleLoader.cpp index 6b952b96295ae..8a55635f35f69 100644 --- a/lib/Serialization/SerializedModuleLoader.cpp +++ b/lib/Serialization/SerializedModuleLoader.cpp @@ -442,7 +442,8 @@ SerializedModuleLoaderBase::scanModuleFile(Twine modulePath, bool isFramework) { const std::string sourceInfoPath; // Map the set of dependencies over to the "module dependencies". auto dependencies = ModuleDependencyInfo::forSwiftBinaryModule( - modulePath.str(), moduleDocPath, sourceInfoPath, isFramework); + modulePath.str(), moduleDocPath, sourceInfoPath, isFramework, + /*module-cache-key*/ ""); // Some transitive dependencies of binary modules are not required to be // imported during normal builds. // TODO: This is worth revisiting for debugger purposes where diff --git a/test/CAS/Inputs/SwiftDepsExtractor.py b/test/CAS/Inputs/SwiftDepsExtractor.py new file mode 100755 index 0000000000000..9666127c2ed86 --- /dev/null +++ b/test/CAS/Inputs/SwiftDepsExtractor.py @@ -0,0 +1,34 @@ +#!/usr/bin/env python3 +# +# Usage: SwiftDepsExtractor.py file.json ModuleName Key + +import json +import sys + +input_json = sys.argv[1] +module_name = sys.argv[2] +key = sys.argv[3] + +mode = 'swift' + +if module_name.startswith('clang:'): + mode = 'clang' + module_name = module_name[6:] +elif module_name.startswith('swiftPrebuiltExternal:'): + mode = 'swiftPrebuiltExternal' + module_name = module_name[22:] + +with open(input_json, 'r') as file: + deps = json.load(file) + module_names = deps['modules'][::2] + module_details = deps['modules'][1::2] + for name, detail in zip(module_names, module_details): + if name.get(mode, '') != module_name: + continue + + if key in detail.keys(): + print(detail[key]) + break + + print(detail['details'][mode][key]) + break diff --git a/test/CAS/binary_module_deps.swift b/test/CAS/binary_module_deps.swift new file mode 100644 index 0000000000000..e59a88e17c09f --- /dev/null +++ b/test/CAS/binary_module_deps.swift @@ -0,0 +1,41 @@ +// REQUIRES: objc_interop + +// RUN: %empty-directory(%t) +// RUN: mkdir -p %t/clang-module-cache +// RUN: mkdir -p %t/cas + +// RUN: %target-swift-frontend -emit-module -module-cache-path %t/clang-module-cache %S/../ScanDependencies/Inputs/Swift/E.swiftinterface -o %t/E.swiftmodule -I %S/../ScanDependencies/Inputs/CHeaders -I %S/../ScanDependencies/Inputs/Swift -swift-version 4 +// RUN: %target-swift-frontend -emit-module -module-cache-path %t/clang-module-cache %S/../ScanDependencies/Inputs/Swift/A.swiftinterface -o %t/A.swiftmodule -I %S/../ScanDependencies/Inputs/CHeaders -I %S/../ScanDependencies/Inputs/Swift -swift-version 4 +// RUN: %target-swift-frontend -scan-dependencies -module-cache-path %t/clang-module-cache %s -o %t/deps.json -I %t -swift-version 4 -enable-cas -cas-path %t/cas +// RUN: %FileCheck %s -DTEMP=%t < %t/deps.json + +/// Test binary module key: binary module key is the CASID of itself. +// RUN: %S/Inputs/SwiftDepsExtractor.py %t/deps.json swiftPrebuiltExternal:A moduleCacheKey > %t/A.key.casid +// RUN: llvm-cas --cas %t/cas --cat-blob @%t/A.key.casid > %t/Loaded.swiftmodule +// RUN: diff %t/A.swiftmodule %t/Loaded.swiftmodule + +import A +import E + + +/// Main module +// CHECK-LABEL: "swift": "deps" +// CHECK: "directDependencies": [ +// CHECK: "swiftPrebuiltExternal": "A" +// CHECK: "swiftPrebuiltExternal": "E" +// CHECK: "details": { +// CHECK: "casFSRootID" + +/// E.swiftmodule +// CHECK-LABEL: "modulePath": "{{.*}}{{/|\\}}E.swiftmodule", +// CHECK: "details": { +// CHECK: "swiftPrebuiltExternal": { +// CHECK: "compiledModulePath": +// CHECK: "moduleCacheKey": + +/// A.swiftmodule +// CHECK-LABEL: "modulePath": "{{.*}}{{/|\\}}A.swiftmodule", +// CHECK: "details": { +// CHECK: "swiftPrebuiltExternal": { +// CHECK: "compiledModulePath": +// CHECK: "moduleCacheKey": diff --git a/test/CAS/cas-explicit-module-map.swift b/test/CAS/cas-explicit-module-map.swift new file mode 100644 index 0000000000000..fec0dd188d2ec --- /dev/null +++ b/test/CAS/cas-explicit-module-map.swift @@ -0,0 +1,129 @@ +// RUN: %empty-directory(%t) +// RUN: mkdir -p %t/cas +// RUN: split-file %s %t +// RUN: %target-swift-emit-pcm -module-cache-path %t/clang-module-cache -module-name SwiftShims %swift-lib-dir/swift/shims/module.modulemap -o %t/SwiftShims.pcm +// RUN: %target-swift-emit-pcm -module-cache-path %t/clang-module-cache -module-name _SwiftConcurrencyShims %swift-lib-dir/swift/shims/module.modulemap -o %t/_SwiftConcurrencyShims.pcm +// RUN: %target-swift-frontend -emit-module -module-cache-path %t/clang-module-cache %t/A.swift -o %t/A.swiftmodule -swift-version 5 +// RUN: %target-swift-frontend -emit-module -module-cache-path %t/clang-module-cache %t/B.swift -o %t/B.swiftmodule -I %t -swift-version 5 +// RUN: %target-swift-frontend -scan-dependencies -module-cache-path %t/clang-module-cache %t/Test.swift -o %t/deps.json -I %t -swift-version 5 -enable-cas -cas-path %t/cas + +// RUN: %S/Inputs/SwiftDepsExtractor.py %t/deps.json swiftPrebuiltExternal:A moduleCacheKey | tr -d '\n' > %t/A.key +// RUN: %S/Inputs/SwiftDepsExtractor.py %t/deps.json swiftPrebuiltExternal:B moduleCacheKey | tr -d '\n' > %t/B.key + +/// Prepare the cas objects that can be used to construct CompileJobResultSchema object. +// RUN: llvm-cas --cas %t/cas --get-cache-result @%t/A.key > %t/A.result +// RUN: llvm-cas --cas %t/cas --ls-node-refs @%t/A.result | tail -n 1 > %t/schema.casid +// RUN: llvm-cas --cas %t/cas --cat-blob @%t/A.result > %t/kind.blob + +/// Make keys for module loads. The result casid construction is tied with the actual structure of CompilerJobResultSchema. +// RUN: llvm-cas --cas %t/cas --make-blob --data %stdlib_module | tr -d '\n' > %t/Swift.key +// RUN: llvm-cas --cas %t/cas --make-node --data %t/kind.blob @%t/Swift.key @%t/schema.casid > %t/Swift.casid +// RUN: llvm-cas --cas %t/cas --put-cache-key @%t/Swift.key @%t/Swift.casid + +// RUN: llvm-cas --cas %t/cas --make-blob --data %ononesupport_module | tr -d '\n' > %t/ONone.key +// RUN: llvm-cas --cas %t/cas --make-node --data %t/kind.blob @%t/ONone.key @%t/schema.casid > %t/ONone.casid +// RUN: llvm-cas --cas %t/cas --put-cache-key @%t/ONone.key @%t/ONone.casid + +// RUN: llvm-cas --cas %t/cas --make-blob --data %concurrency_module | tr -d '\n' > %t/Concurrency.key +// RUN: llvm-cas --cas %t/cas --make-node --data %t/kind.blob @%t/Concurrency.key @%t/schema.casid > %t/Concurrency.casid +// RUN: llvm-cas --cas %t/cas --put-cache-key @%t/Concurrency.key @%t/Concurrency.casid + +// RUN: llvm-cas --cas %t/cas --make-blob --data %string_processing_module | tr -d '\n' > %t/String.key +// RUN: llvm-cas --cas %t/cas --make-node --data %t/kind.blob @%t/String.key @%t/schema.casid > %t/String.casid +// RUN: llvm-cas --cas %t/cas --put-cache-key @%t/String.key @%t/String.casid + +// RUN: llvm-cas --cas %t/cas --make-blob --data %t/SwiftShims.pcm | tr -d '\n' > %t/Shims.key +// RUN: llvm-cas --cas %t/cas --make-node --data %t/kind.blob @%t/Shims.key @%t/schema.casid > %t/Shims.casid +// RUN: llvm-cas --cas %t/cas --put-cache-key @%t/Shims.key @%t/Shims.casid + +// RUN: llvm-cas --cas %t/cas --make-blob --data %t/_SwiftConcurrencyShims.pcm | tr -d '\n' > %t/ConcurrencyShims.key +// RUN: llvm-cas --cas %t/cas --make-node --data %t/kind.blob @%t/ConcurrencyShims.key @%t/schema.casid > %t/ConcurrencyShims.casid +// RUN: llvm-cas --cas %t/cas --put-cache-key @%t/ConcurrencyShims.key @%t/ConcurrencyShims.casid + +// RUN: echo "[{" > %/t/map.json +// RUN: echo "\"moduleName\": \"A\"," >> %/t/map.json +// RUN: echo "\"modulePath\": \"A.swiftmodule\"," >> %/t/map.json +// RUN: echo -n "\"moduleCacheKey\": \"" >> %/t/map.json +// RUN: cat %t/A.key >> %/t/map.json +// RUN: echo "\"," >> %/t/map.json +// RUN: echo "\"isFramework\": false" >> %/t/map.json +// RUN: echo "}," >> %/t/map.json +// RUN: echo "{" >> %/t/map.json +// RUN: echo "\"moduleName\": \"B\"," >> %/t/map.json +// RUN: echo "\"modulePath\": \"B.swiftmodule\"," >> %/t/map.json +// RUN: echo -n "\"moduleCacheKey\": \"" >> %/t/map.json +// RUN: cat %t/B.key >> %/t/map.json +// RUN: echo "\"," >> %/t/map.json +// RUN: echo "\"isFramework\": false" >> %/t/map.json +// RUN: echo "}," >> %/t/map.json +// RUN: echo "{" >> %/t/map.json +// RUN: echo "\"moduleName\": \"Swift\"," >> %/t/map.json +// RUN: echo "\"modulePath\": \"Swift.swiftmodule\"," >> %/t/map.json +// RUN: echo -n "\"moduleCacheKey\": \"" >> %/t/map.json +// RUN: cat %t/Swift.key >> %/t/map.json +// RUN: echo "\"," >> %/t/map.json +// RUN: echo "\"isFramework\": false" >> %/t/map.json +// RUN: echo "}," >> %/t/map.json +// RUN: echo "{" >> %/t/map.json +// RUN: echo "\"moduleName\": \"SwiftOnoneSupport\"," >> %/t/map.json +// RUN: echo "\"modulePath\": \"SwiftOnoneSupport.swiftmodule\"," >> %/t/map.json +// RUN: echo -n "\"moduleCacheKey\": \"" >> %/t/map.json +// RUN: cat %t/ONone.key >> %/t/map.json +// RUN: echo "\"," >> %/t/map.json +// RUN: echo "\"isFramework\": false" >> %/t/map.json +// RUN: echo "}," >> %/t/map.json +// RUN: echo "{" >> %/t/map.json +// RUN: echo "\"moduleName\": \"_Concurrency\"," >> %/t/map.json +// RUN: echo "\"modulePath\": \"_Concurrency.swiftmodule\"," >> %/t/map.json +// RUN: echo -n "\"moduleCacheKey\": \"" >> %/t/map.json +// RUN: cat %t/Concurrency.key >> %/t/map.json +// RUN: echo "\"," >> %/t/map.json +// RUN: echo "\"isFramework\": false" >> %/t/map.json +// RUN: echo "}," >> %/t/map.json +// RUN: echo "{" >> %/t/map.json +// RUN: echo "\"moduleName\": \"_StringProcessing\"," >> %/t/map.json +// RUN: echo "\"modulePath\": \"_StringProcessing.swiftmodule\"," >> %/t/map.json +// RUN: echo -n "\"moduleCacheKey\": \"" >> %/t/map.json +// RUN: cat %t/String.key >> %/t/map.json +// RUN: echo "\"," >> %/t/map.json +// RUN: echo "\"isFramework\": false" >> %/t/map.json +// RUN: echo "}," >> %/t/map.json +// RUN: echo "{" >> %/t/map.json +// RUN: echo "\"moduleName\": \"SwiftShims\"," >> %/t/map.json +// RUN: echo "\"clangModulePath\": \"SwiftShims.pcm\"," >> %/t/map.json +// RUN: echo -n "\"clangModuleCacheKey\": \"" >> %/t/map.json +// RUN: cat %t/Shims.key >> %/t/map.json +// RUN: echo "\"," >> %/t/map.json +// RUN: echo "\"isFramework\": false" >> %/t/map.json +// RUN: echo "}," >> %/t/map.json +// RUN: echo "{" >> %/t/map.json +// RUN: echo "\"moduleName\": \"_SwiftConcurrencyShims\"," >> %/t/map.json +// RUN: echo "\"clangModulePath\": \"_SwiftConcurrency.pcm\"," >> %/t/map.json +// RUN: echo -n "\"clangModuleCacheKey\": \"" >> %/t/map.json +// RUN: cat %t/ConcurrencyShims.key >> %/t/map.json +// RUN: echo "\"," >> %/t/map.json +// RUN: echo "\"isFramework\": false" >> %/t/map.json +// RUN: echo "}]" >> %/t/map.json + +// RUN: llvm-cas --cas %t/cas --make-blob --data %t/map.json > %t/map.casid + +// RUN: %target-swift-frontend -emit-module -emit-module-path %t/Foo.swiftmodule -disable-implicit-swift-modules -module-cache-path %t.module-cache -explicit-swift-module-map-file @%t/map.casid -Rmodule-loading -Xcc -Rmodule-import %s -enable-cas -cas-path %t/cas -allow-unstable-cache-key-for-testing 2>&1 | %FileCheck %s + +// CHECK-DAG: loaded module 'A' +// CHECK-DAG: loaded module 'B' +// CHECK-DAG: loaded module 'Swift' +// CHECK-DAG: loaded module '_StringProcessing' +// CHECK-DAG: loaded module '_Concurrency' +// CHECK-DAG: loaded module 'SwiftOnoneSupport' + +//--- A.swift +func test() {} + +//--- B.swift +import A +func myTest() {} + +//--- Test.swift +import B + + diff --git a/test/CAS/cas_fs.swift b/test/CAS/cas_fs.swift index 97bb238ae6c3d..8020d2963abee 100644 --- a/test/CAS/cas_fs.swift +++ b/test/CAS/cas_fs.swift @@ -8,7 +8,6 @@ // RUN: llvm-cas --cas %t/cas --ingest --data %s > %t/source.casid // RUN: not %target-swift-frontend -typecheck -enable-cas -cas-fs @%t/source.casid -cas-path %t/cas %s 2>&1 | %FileCheck %s --check-prefix NO-RESOURCES -// NO-RESOURCES: error: unable to set working directory // NO-RESOURCES: error: unable to load standard library /// Ingest the resource directory to satisfy the file system requirement. Also switch CWD to resource dir. diff --git a/test/CAS/module_deps.swift b/test/CAS/module_deps.swift new file mode 100644 index 0000000000000..4d646ad049415 --- /dev/null +++ b/test/CAS/module_deps.swift @@ -0,0 +1,195 @@ +// REQUIRES: objc_interop + +// RUN: %empty-directory(%t) +// RUN: mkdir -p %t/clang-module-cache +// RUN: mkdir -p %t/cas + +// RUN: %target-swift-frontend -scan-dependencies -module-cache-path %t/clang-module-cache %s -o %t/deps.json -I %S/../ScanDependencies/Inputs/CHeaders -I %S/../ScanDependencies/Inputs/Swift -emit-dependencies -emit-dependencies-path %t/deps.d -import-objc-header %S/../ScanDependencies/Inputs/CHeaders/Bridging.h -swift-version 4 -enable-cas -cas-path %t/cas +// Check the contents of the JSON output +// RUN: %FileCheck -check-prefix CHECK -check-prefix CHECK_NO_CLANG_TARGET %s < %t/deps.json + +// Check the contents of the JSON output +// RUN: %FileCheck %s -check-prefix CHECK -check-prefix CHECK-NO-SEARCH-PATHS < %t/deps.json + +// Check the make-style dependencies file +// RUN: %FileCheck %s -check-prefix CHECK-MAKE-DEPS < %t/deps.d + +// RUN: %target-swift-frontend -scan-dependencies -test-dependency-scan-cache-serialization -module-cache-path %t/clang-module-cache %s -o %t/deps.json -I %S/../ScanDependencies/Inputs/CHeaders -I %S/../ScanDependencies/Inputs/Swift -import-objc-header %S/../ScanDependencies/Inputs/CHeaders/Bridging.h -swift-version 4 -enable-cas -cas-path %t/cas +// RUN: %FileCheck -check-prefix CHECK -check-prefix CHECK_NO_CLANG_TARGET %s < %t/deps.json + +// Ensure that scanning with `-clang-target` makes sure that Swift modules' respective PCM-dependency-build-argument sets do not contain target triples. +// RUN: %target-swift-frontend -scan-dependencies -module-cache-path %t/clang-module-cache %s -o %t/deps_clang_target.json -I %S/../ScanDependencies/Inputs/CHeaders -I %S/../ScanDependencies/Inputs/Swift -import-objc-header %S/../ScanDependencies/Inputs/CHeaders/Bridging.h -swift-version 4 -clang-target %target-cpu-apple-macosx10.14 -enable-cas -cas-path %t/cas +// Check the contents of the JSON output +// RUN: %FileCheck -check-prefix CHECK_CLANG_TARGET %s < %t/deps_clang_target.json + +/// check cas-fs content +// RUN: %S/Inputs/SwiftDepsExtractor.py %t/deps.json E casFSRootID > %t/E_fs.casid +// RUN: llvm-cas --cas %t/cas --ls-tree-recursive @%t/E_fs.casid | %FileCheck %s -check-prefix FS_ROOT_E +// RUN: %S/Inputs/SwiftDepsExtractor.py %t/deps.json clang:F casFSRootID > %t/F_fs.casid +// RUN: llvm-cas --cas %t/cas --ls-tree-recursive @%t/F_fs.casid | %FileCheck %s -check-prefix FS_ROOT_F + +// FS_ROOT_E-DAG: E.swiftinterface +// FS_ROOT_E-DAG: SDKSettings.json + +// FS_ROOT_F: CHeaders/A.h +// FS_ROOT_F: CHeaders/B.h +// FS_ROOT_F: CHeaders/C.h +// FS_ROOT_F: CHeaders/D.h +// FS_ROOT_F: CHeaders/F.h +// FS_ROOT_F: CHeaders/G.h +// FS_ROOT_F: CHeaders/H.h +// FS_ROOT_F: CHeaders/I.h +// FS_ROOT_F: CHeaders/X.h +// FS_ROOT_F: CHeaders/module.modulemap + +import C +import E +import G +import SubE + +// CHECK: "mainModuleName": "deps" + +/// --------Main module +// CHECK-LABEL: "modulePath": "deps.swiftmodule", +// CHECK-NEXT: sourceFiles +// CHECK-NEXT: module_deps.swift +// CHECK-NEXT: ], +// CHECK-NEXT: "directDependencies": [ +// CHECK-DAG: "swift": "A" +// CHECK-DAG: "clang": "C" +// CHECK-DAG: "swift": "E" +// CHECK-DAG: "swift": "F" +// CHECK-DAG: "swift": "G" +// CHECK-DAG: "swift": "SubE" +// CHECK-DAG: "swift": "Swift" +// CHECK-DAG: "swift": "SwiftOnoneSupport" +// CHECK-DAG: "swift": "_Concurrency" +// CHECK-DAG: "swift": "_cross_import_E" +// CHECK: ], + +// CHECK: "extraPcmArgs": [ +// CHECK-NEXT: "-Xcc", +// CHECK-NEXT: "-target", +// CHECK-NEXT: "-Xcc", +// CHECK: "-fapinotes-swift-version=4" +// CHECK-NOT: "error: cannot open Swift placeholder dependency module map from" +// CHECK: "bridgingHeader": +// CHECK-NEXT: "path": +// CHECK-SAME: Bridging.h + +// CHECK-NEXT: "sourceFiles": +// CHECK-NEXT: Bridging.h +// CHECK-NEXT: BridgingOther.h + +// CHECK: "moduleDependencies": [ +// CHECK-NEXT: "F" +// CHECK-NEXT: ] + +/// --------Swift module A +// CHECK-LABEL: "modulePath": "{{.*}}{{/|\\}}A-{{.*}}.swiftmodule", + +// CHECK: directDependencies +// CHECK-NEXT: { +// CHECK-DAG: "clang": "A" +// CHECK-DAG: "swift": "Swift" +// CHECK-NEXT: }, +// CHECK: "details": +// CHECK: "moduleCacheKey": + +/// --------Swift module F +// CHECK: "modulePath": "{{.*}}{{/|\\}}F-{{.*}}.swiftmodule", +// CHECK-NEXT: "sourceFiles": [ +// CHECK-NEXT: ], +// CHECK-NEXT: "directDependencies": [ +// CHECK-NEXT: { +// CHECK-DAG: "clang": "F" +// CHECK-DAG: "swift": "Swift" +// CHECK-DAG: "swift": "SwiftOnoneSupport" +// CHECK-NEXT: } +// CHECK-NEXT: ], +// CHECK: "details": +// CHECK: "moduleCacheKey": + +/// --------Swift module G +// CHECK-LABEL: "modulePath": "{{.*}}{{/|\\}}G-{{.*}}.swiftmodule" +// CHECK: "directDependencies" +// CHECK-NEXT: { +// CHECK-DAG: "clang": "G" +// CHECK-DAG: "swift": "Swift" +// CHECK-DAG: "swift": "SwiftOnoneSupport" +// CHECK: ], +// CHECK-NEXT: "details": { + +// CHECK: "contextHash": "{{.*}}", +// CHECK: "commandLine": [ +// CHECK: "-compile-module-from-interface" +// CHECK: "-target" +// CHECK: "-module-name" +// CHECK: "G" +// CHECK: "-swift-version" +// CHECK: "5" +// CHECK: ], +// CHECK_NO_CLANG_TARGET: "extraPcmArgs": [ +// CHECK_NO_CLANG_TARGET-NEXT: "-Xcc", +// CHECK_NO_CLANG_TARGET-NEXT: "-target", +// CHECK_CLANG_TARGET: "extraPcmArgs": [ +// CHECK_CLANG_TARGET-NEXT: "-Xcc", +// CHECK_CLANG_TARGET-NEXT: "-fapinotes-swift-version={{.*}}" +// CHECK_CLANG_TARGET-NEXT: ] + +/// --------Swift module E +// CHECK: "swift": "E" +// CHECK-LABEL: modulePath": "{{.*}}{{/|\\}}E-{{.*}}.swiftmodule" +// CHECK: "directDependencies" +// CHECK-NEXT: { +// CHECK-NEXT: "swift": "Swift" + +// CHECK: "moduleInterfacePath" +// CHECK-SAME: E.swiftinterface + +/// --------Swift module Swift +// CHECK-LABEL: "modulePath": "{{.*}}{{/|\\}}Swift-{{.*}}.swiftmodule", + +// CHECK: directDependencies +// CHECK-NEXT: { +// CHECK-NEXT: "clang": "SwiftShims" + +/// --------Clang module SwiftShims +// CHECK-LABEL: "modulePath": "{{.*}}{{/|\\}}SwiftShims-{{.*}}.pcm", +// CHECK: "contextHash": "[[SHIMS_CONTEXT:.*]]", +// CHECK: "-o" +// CHECK-NEXT: SwiftShims-{{.*}}[[SHIMS_CONTEXT]].pcm +// CHECK-NO-SEARCH-PATHS-NOT: "-prebuilt-module-cache-path" + +/// --------Clang module C +// CHECK-LABEL: "modulePath": "{{.*}}{{/|\\}}C-{{.*}}.pcm", + +// CHECK: "sourceFiles": [ +// CHECK-DAG: module.modulemap +// CHECK-DAG: C.h + +// CHECK: directDependencies +// CHECK-NEXT: { +// CHECK-NEXT: "clang": "B" + +// CHECK: "moduleMapPath" +// CHECK-SAME: module.modulemap + +// CHECK: "contextHash" +// CHECK-SAME: "{{.*}}" + +/// --------Clang module B +// CHECK-LABEL: "modulePath": "{{.*}}{{/|\\}}B-{{.*}}.pcm", +// CHECK: "contextHash": "[[B_CONTEXT:.*]]", +// CHECK: "-o" +// CHECK-NEXT: B-{{.*}}[[B_CONTEXT]].pcm + +// Check make-style dependencies +// CHECK-MAKE-DEPS: module_deps.swift +// CHECK-MAKE-DEPS-SAME: A.swiftinterface +// CHECK-MAKE-DEPS-SAME: G.swiftinterface +// CHECK-MAKE-DEPS-SAME: B.h +// CHECK-MAKE-DEPS-SAME: F.h +// CHECK-MAKE-DEPS-SAME: Bridging.h +// CHECK-MAKE-DEPS-SAME: BridgingOther.h +// CHECK-MAKE-DEPS-SAME: module.modulemap diff --git a/test/CAS/module_deps_include_tree.swift b/test/CAS/module_deps_include_tree.swift new file mode 100644 index 0000000000000..85c113e361bd2 --- /dev/null +++ b/test/CAS/module_deps_include_tree.swift @@ -0,0 +1,190 @@ +// REQUIRES: objc_interop + +// RUN: %empty-directory(%t) +// RUN: mkdir -p %t/clang-module-cache +// RUN: mkdir -p %t/cas + +// RUN: %target-swift-frontend -scan-dependencies -module-cache-path %t/clang-module-cache %s -o %t/deps.json -I %S/../ScanDependencies/Inputs/CHeaders -I %S/../ScanDependencies/Inputs/Swift -emit-dependencies -emit-dependencies-path %t/deps.d -import-objc-header %S/../ScanDependencies/Inputs/CHeaders/Bridging.h -swift-version 4 -enable-cas -cas-path %t/cas -clang-include-tree +// Check the contents of the JSON output +// RUN: %FileCheck -check-prefix CHECK -check-prefix CHECK_NO_CLANG_TARGET %s < %t/deps.json + +// Check the contents of the JSON output +// RUN: %FileCheck %s -check-prefix CHECK -check-prefix CHECK-NO-SEARCH-PATHS < %t/deps.json + +// Check the make-style dependencies file +// RUN: %FileCheck %s -check-prefix CHECK-MAKE-DEPS < %t/deps.d + +// RUN: %target-swift-frontend -scan-dependencies -test-dependency-scan-cache-serialization -module-cache-path %t/clang-module-cache %s -o %t/deps.json -I %S/../ScanDependencies/Inputs/CHeaders -I %S/../ScanDependencies/Inputs/Swift -import-objc-header %S/../ScanDependencies/Inputs/CHeaders/Bridging.h -swift-version 4 -enable-cas -cas-path %t/cas -clang-include-tree +// RUN: %FileCheck -check-prefix CHECK -check-prefix CHECK_NO_CLANG_TARGET %s < %t/deps.json + +// Ensure that scanning with `-clang-target` makes sure that Swift modules' respective PCM-dependency-build-argument sets do not contain target triples. +// RUN: %target-swift-frontend -scan-dependencies -module-cache-path %t/clang-module-cache %s -o %t/deps_clang_target.json -I %S/../ScanDependencies/Inputs/CHeaders -I %S/../ScanDependencies/Inputs/Swift -import-objc-header %S/../ScanDependencies/Inputs/CHeaders/Bridging.h -swift-version 4 -clang-target %target-cpu-apple-macosx10.14 -enable-cas -cas-path %t/cas -clang-include-tree +// Check the contents of the JSON output +// RUN: %FileCheck -check-prefix CHECK_CLANG_TARGET %s < %t/deps_clang_target.json + +/// check cas-fs content +// RUN: %S/Inputs/SwiftDepsExtractor.py %t/deps.json E casFSRootID > %t/E_fs.casid +// RUN: llvm-cas --cas %t/cas --ls-tree-recursive @%t/E_fs.casid | %FileCheck %s -check-prefix FS_ROOT_E + +// RUN: %S/Inputs/SwiftDepsExtractor.py %t/deps.json clang:F clangIncludeTree > %t/F_tree.casid +// RUN: clang-cas-test --cas %t/cas --print-include-tree @%t/F_tree.casid | %FileCheck %s -check-prefix INCLUDE_TREE_F + +// FS_ROOT_E-DAG: E.swiftinterface +// FS_ROOT_E-DAG: SDKSettings.json + +// INCLUDE_TREE_F: +// INCLUDE_TREE_F: +// INCLUDE_TREE_F: Files: +// INCLUDE_TREE_F-NEXT: CHeaders/F.h + +import C +import E +import G +import SubE + +// CHECK: "mainModuleName": "deps" + +/// --------Main module +// CHECK-LABEL: "modulePath": "deps.swiftmodule", +// CHECK-NEXT: sourceFiles +// CHECK-NEXT: module_deps_include_tree.swift +// CHECK-NEXT: ], +// CHECK-NEXT: "directDependencies": [ +// CHECK-DAG: "swift": "A" +// CHECK-DAG: "clang": "C" +// CHECK-DAG: "swift": "E" +// CHECK-DAG: "swift": "F" +// CHECK-DAG: "swift": "G" +// CHECK-DAG: "swift": "SubE" +// CHECK-DAG: "swift": "Swift" +// CHECK-DAG: "swift": "SwiftOnoneSupport" +// CHECK-DAG: "swift": "_Concurrency" +// CHECK-DAG: "swift": "_cross_import_E" +// CHECK: ], + +// CHECK: "extraPcmArgs": [ +// CHECK-NEXT: "-Xcc", +// CHECK-NEXT: "-target", +// CHECK-NEXT: "-Xcc", +// CHECK: "-fapinotes-swift-version=4" +// CHECK-NOT: "error: cannot open Swift placeholder dependency module map from" +// CHECK: "bridgingHeader": +// CHECK-NEXT: "path": +// CHECK-SAME: Bridging.h + +// CHECK-NEXT: "sourceFiles": +// CHECK-NEXT: Bridging.h +// CHECK-NEXT: BridgingOther.h + +// CHECK: "moduleDependencies": [ +// CHECK-NEXT: "F" +// CHECK-NEXT: ] + +/// --------Swift module A +// CHECK-LABEL: "modulePath": "{{.*}}{{/|\\}}A-{{.*}}.swiftmodule", + +// CHECK: directDependencies +// CHECK-NEXT: { +// CHECK-DAG: "clang": "A" +// CHECK-DAG: "swift": "Swift" +// CHECK-NEXT: }, +// CHECK: "details": +// CHECK: "moduleCacheKey": + +/// --------Swift module F +// CHECK: "modulePath": "{{.*}}{{/|\\}}F-{{.*}}.swiftmodule", +// CHECK-NEXT: "sourceFiles": [ +// CHECK-NEXT: ], +// CHECK-NEXT: "directDependencies": [ +// CHECK-NEXT: { +// CHECK-DAG: "clang": "F" +// CHECK-DAG: "swift": "Swift" +// CHECK-DAG: "swift": "SwiftOnoneSupport" +// CHECK-NEXT: } +// CHECK-NEXT: ], +// CHECK: "details": +// CHECK: "moduleCacheKey": + +/// --------Swift module G +// CHECK-LABEL: "modulePath": "{{.*}}{{/|\\}}G-{{.*}}.swiftmodule" +// CHECK: "directDependencies" +// CHECK-NEXT: { +// CHECK-DAG: "clang": "G" +// CHECK-DAG: "swift": "Swift" +// CHECK-DAG: "swift": "SwiftOnoneSupport" +// CHECK: ], +// CHECK-NEXT: "details": { + +// CHECK: "contextHash": "{{.*}}", +// CHECK: "commandLine": [ +// CHECK: "-compile-module-from-interface" +// CHECK: "-target" +// CHECK: "-module-name" +// CHECK: "G" +// CHECK: "-swift-version" +// CHECK: "5" +// CHECK: ], +// CHECK_NO_CLANG_TARGET: "extraPcmArgs": [ +// CHECK_NO_CLANG_TARGET-NEXT: "-Xcc", +// CHECK_NO_CLANG_TARGET-NEXT: "-target", +// CHECK_CLANG_TARGET: "extraPcmArgs": [ +// CHECK_CLANG_TARGET-NEXT: "-Xcc", +// CHECK_CLANG_TARGET-NEXT: "-fapinotes-swift-version={{.*}}" +// CHECK_CLANG_TARGET-NEXT: ] + +/// --------Swift module E +// CHECK: "swift": "E" +// CHECK-LABEL: modulePath": "{{.*}}{{/|\\}}E-{{.*}}.swiftmodule" +// CHECK: "directDependencies" +// CHECK-NEXT: { +// CHECK-NEXT: "swift": "Swift" + +// CHECK: "moduleInterfacePath" +// CHECK-SAME: E.swiftinterface + +/// --------Swift module Swift +// CHECK-LABEL: "modulePath": "{{.*}}{{/|\\}}Swift-{{.*}}.swiftmodule", + +// CHECK: directDependencies +// CHECK-NEXT: { +// CHECK-NEXT: "clang": "SwiftShims" + +/// --------Clang module SwiftShims +// CHECK-LABEL: "modulePath": "{{.*}}{{/|\\}}SwiftShims-{{.*}}.pcm", +// CHECK: "contextHash": "[[SHIMS_CONTEXT:.*]]", +// CHECK: "-o" +// CHECK-NEXT: SwiftShims-{{.*}}[[SHIMS_CONTEXT]].pcm +// CHECK-NO-SEARCH-PATHS-NOT: "-prebuilt-module-cache-path" + +/// --------Clang module C +// CHECK-LABEL: "modulePath": "{{.*}}{{/|\\}}C-{{.*}}.pcm", + +// CHECK: "sourceFiles": [ +// CHECK-DAG: module.modulemap +// CHECK-DAG: C.h + +// CHECK: directDependencies +// CHECK-NEXT: { +// CHECK-NEXT: "clang": "B" + +// CHECK: "moduleMapPath" +// CHECK-SAME: module.modulemap + +// CHECK: "contextHash" +// CHECK-SAME: "{{.*}}" + +/// --------Clang module B +// CHECK-LABEL: "modulePath": "{{.*}}{{/|\\}}B-{{.*}}.pcm", +// CHECK: "contextHash": "[[B_CONTEXT:.*]]", +// CHECK: "-o" +// CHECK-NEXT: B-{{.*}}[[B_CONTEXT]].pcm + +// Check make-style dependencies +// CHECK-MAKE-DEPS: module_deps_include_tree.swift +// CHECK-MAKE-DEPS-SAME: A.swiftinterface +// CHECK-MAKE-DEPS-SAME: G.swiftinterface +// CHECK-MAKE-DEPS-SAME: B.h +// CHECK-MAKE-DEPS-SAME: F.h +// CHECK-MAKE-DEPS-SAME: Bridging.h +// CHECK-MAKE-DEPS-SAME: BridgingOther.h +// CHECK-MAKE-DEPS-SAME: module.modulemap diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 64dbbcaa0df45..cbbfdeffcbe74 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -71,6 +71,7 @@ function(get_test_dependencies SDK result_var_name) c-arcmt-test c-index-test clang + clang-cas-test count dsymutil FileCheck diff --git a/tools/libSwiftScan/libSwiftScan.cpp b/tools/libSwiftScan/libSwiftScan.cpp index 23c5b697ef26c..8e2e69e6c6820 100644 --- a/tools/libSwiftScan/libSwiftScan.cpp +++ b/tools/libSwiftScan/libSwiftScan.cpp @@ -20,11 +20,15 @@ #include "swift/DependencyScan/DependencyScanImpl.h" #include "swift/DependencyScan/DependencyScanningTool.h" #include "swift/DependencyScan/StringUtils.h" +#include "swift/Frontend/CachingUtils.h" #include "swift/Option/Options.h" +#include "llvm/CAS/ObjectStore.h" using namespace swift::dependencies; +using namespace swift::cas; DEFINE_SIMPLE_CONVERSION_FUNCTIONS(DependencyScanningTool, swiftscan_scanner_t) +DEFINE_SIMPLE_CONVERSION_FUNCTIONS(CachingTool, swiftscan_cas_t) //=== Private Cleanup Functions -------------------------------------------===// @@ -48,6 +52,12 @@ void swiftscan_dependency_info_details_dispose( swiftscan_string_set_dispose( details_impl->swift_textual_details.extra_pcm_args); swiftscan_string_dispose(details_impl->swift_textual_details.context_hash); + swiftscan_string_dispose( + details_impl->swift_textual_details.cas_fs_root_id); + swiftscan_string_dispose( + details_impl->swift_textual_details.bridging_header_include_tree); + swiftscan_string_dispose( + details_impl->swift_textual_details.module_cache_key); break; case SWIFTSCAN_DEPENDENCY_INFO_SWIFT_BINARY: swiftscan_string_dispose( @@ -56,6 +66,8 @@ void swiftscan_dependency_info_details_dispose( details_impl->swift_binary_details.module_doc_path); swiftscan_string_dispose( details_impl->swift_binary_details.module_source_info_path); + swiftscan_string_dispose( + details_impl->swift_binary_details.module_cache_key); break; case SWIFTSCAN_DEPENDENCY_INFO_SWIFT_PLACEHOLDER: swiftscan_string_dispose( @@ -70,6 +82,8 @@ void swiftscan_dependency_info_details_dispose( swiftscan_string_dispose(details_impl->clang_details.context_hash); swiftscan_string_set_dispose(details_impl->clang_details.command_line); swiftscan_string_set_dispose(details_impl->clang_details.captured_pcm_args); + swiftscan_string_dispose(details_impl->clang_details.cas_fs_root_id); + swiftscan_string_dispose(details_impl->clang_details.module_cache_key); break; } delete details_impl; @@ -276,6 +290,12 @@ swiftscan_string_set_t *swiftscan_swift_textual_detail_get_command_line( return details->swift_textual_details.command_line; } +swiftscan_string_set_t * +swiftscan_swift_textual_detail_get_bridging_pch_command_line( + swiftscan_module_details_t details) { + return details->swift_textual_details.bridging_pch_command_line; +} + swiftscan_string_set_t *swiftscan_swift_textual_detail_get_extra_pcm_args( swiftscan_module_details_t details) { return details->swift_textual_details.extra_pcm_args; @@ -296,6 +316,16 @@ swiftscan_string_set_t *swiftscan_swift_textual_detail_get_swift_overlay_depende return details->swift_textual_details.swift_overlay_module_dependencies; } +swiftscan_string_ref_t swiftscan_swift_textual_detail_get_cas_fs_root_id( + swiftscan_module_details_t details) { + return details->swift_textual_details.cas_fs_root_id; +} + +swiftscan_string_ref_t swiftscan_swift_textual_detail_get_module_cache_key( + swiftscan_module_details_t details) { + return details->swift_textual_details.module_cache_key; +} + //=== Swift Binary Module Details query APIs ------------------------------===// swiftscan_string_ref_t swiftscan_swift_binary_detail_get_compiled_module_path( @@ -319,6 +349,12 @@ bool swiftscan_swift_binary_detail_get_is_framework( return details->swift_binary_details.is_framework; } +swiftscan_string_ref_t swiftscan_swift_binary_detail_get_module_cache_key( + swiftscan_module_details_t details) { + return details->swift_binary_details.module_cache_key; +} + + //=== Swift Placeholder Module Details query APIs -------------------------===// swiftscan_string_ref_t @@ -360,6 +396,16 @@ swiftscan_clang_detail_get_captured_pcm_args(swiftscan_module_details_t details) return details->clang_details.captured_pcm_args; } +swiftscan_string_ref_t +swiftscan_clang_detail_get_cas_fs_root_id(swiftscan_module_details_t details) { + return details->clang_details.cas_fs_root_id; +} + +swiftscan_string_ref_t swiftscan_clang_detail_get_module_cache_key( + swiftscan_module_details_t details) { + return details->clang_details.module_cache_key; +} + //=== Batch Scan Input Functions ------------------------------------------===// swiftscan_batch_scan_input_t *swiftscan_batch_scan_input_create() { @@ -617,6 +663,60 @@ swiftscan_diagnostics_set_dispose(swiftscan_diagnostic_set_t* diagnostics){ delete diagnostics; } +//=== CAS Functions ----------------------------------------------------------// + +swiftscan_cas_t swiftscan_cas_create(const char *path) { + std::string CASPath(path); + if (CASPath.empty()) + CASPath = llvm::cas::getDefaultOnDiskCASPath(); + + CachingTool *tool = new CachingTool(CASPath); + if (!tool->isValid()) { + delete tool; + return nullptr; + } + return wrap(tool); +} + +void swiftscan_cas_dispose(swiftscan_cas_t cas) { delete unwrap(cas); } + +swiftscan_string_ref_t +swiftscan_cas_store(swiftscan_cas_t cas, uint8_t *data, unsigned size) { + llvm::StringRef StrContent((char*)data, size); + auto ID = unwrap(cas)->storeContent(StrContent); + return swift::c_string_utils::create_clone(ID.c_str()); +} + +static swift::file_types::ID +getFileTypeFromScanOutputKind(swiftscan_output_kind_t kind) { + switch (kind) { + case SWIFTSCAN_OUTPUT_TYPE_OBJECT: + return swift::file_types::ID::TY_Object; + case SWIFTSCAN_OUTPUT_TYPE_SWIFTMODULE: + return swift::file_types::ID::TY_SwiftModuleFile; + case SWIFTSCAN_OUTPUT_TYPE_SWIFTINTERFACE: + return swift::file_types::ID::TY_SwiftModuleInterfaceFile; + case SWIFTSCAN_OUTPUT_TYPE_SWIFTPRIAVEINTERFACE: + return swift::file_types::ID::TY_PrivateSwiftModuleInterfaceFile; + case SWIFTSCAN_OUTPUT_TYPE_CLANG_MODULE: + return swift::file_types::ID::TY_ClangModuleFile; + case SWIFTSCAN_OUTPUT_TYPE_CLANG_PCH: + return swift::file_types::ID::TY_PCH; + } +} + +swiftscan_string_ref_t +swiftscan_compute_cache_key(swiftscan_cas_t cas, int argc, const char **argv, + const char *input, swiftscan_output_kind_t kind) { + std::vector Compilation; + for (int i = 0; i < argc; ++i) + Compilation.push_back(argv[i]); + + auto ID = unwrap(cas)->computeCacheKey(Compilation, input, + getFileTypeFromScanOutputKind(kind)); + return swift::c_string_utils::create_clone(ID.c_str()); +} + //=== Experimental Compiler Invocation Functions ------------------------===// int invoke_swift_compiler(int argc, const char **argv) { diff --git a/tools/libSwiftScan/libSwiftScan.exports b/tools/libSwiftScan/libSwiftScan.exports index 4b940c96ea5f2..ff1d5337276fe 100644 --- a/tools/libSwiftScan/libSwiftScan.exports +++ b/tools/libSwiftScan/libSwiftScan.exports @@ -12,14 +12,18 @@ swiftscan_swift_textual_detail_get_bridging_header_path swiftscan_swift_textual_detail_get_bridging_source_files swiftscan_swift_textual_detail_get_bridging_module_dependencies swiftscan_swift_textual_detail_get_command_line +swiftscan_swift_textual_detail_get_bridging_pch_command_line swiftscan_swift_textual_detail_get_extra_pcm_args swiftscan_swift_textual_detail_get_context_hash swiftscan_swift_textual_detail_get_is_framework swiftscan_swift_textual_detail_get_swift_overlay_dependencies +swiftscan_swift_textual_detail_get_cas_fs_root_id +swiftscan_swift_textual_detail_get_module_cache_key swiftscan_swift_binary_detail_get_compiled_module_path swiftscan_swift_binary_detail_get_module_doc_path swiftscan_swift_binary_detail_get_module_source_info_path swiftscan_swift_binary_detail_get_is_framework +swiftscan_swift_binary_detail_get_module_cache_key swiftscan_swift_placeholder_detail_get_compiled_module_path swiftscan_swift_placeholder_detail_get_module_doc_path swiftscan_swift_placeholder_detail_get_module_source_info_path @@ -27,6 +31,8 @@ swiftscan_clang_detail_get_module_map_path swiftscan_clang_detail_get_context_hash swiftscan_clang_detail_get_command_line swiftscan_clang_detail_get_captured_pcm_args +swiftscan_clang_detail_get_cas_fs_root_id +swiftscan_clang_detail_get_module_cache_key swiftscan_batch_scan_input_set_modules swiftscan_batch_scan_entry_set_module_name swiftscan_batch_scan_entry_set_arguments @@ -68,4 +74,8 @@ swiftscan_scanner_diagnostics_reset swiftscan_diagnostic_get_message swiftscan_diagnostic_get_severity swiftscan_diagnostics_set_dispose +swiftscan_cas_create +swiftscan_cas_dispose +swiftscan_cas_store +swiftscan_compute_cache_key invoke_swift_compiler From 90a1bb812bea606b36f9612c96bc013a1cd041d5 Mon Sep 17 00:00:00 2001 From: Artem Chikin Date: Fri, 9 Jun 2023 08:39:28 -0700 Subject: [PATCH 23/37] [Dependency Scanning] Do not treat modules as their own dependencies --- lib/DependencyScan/ScanDependencies.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/DependencyScan/ScanDependencies.cpp b/lib/DependencyScan/ScanDependencies.cpp index a3a09efb75b30..b1246ae133573 100644 --- a/lib/DependencyScan/ScanDependencies.cpp +++ b/lib/DependencyScan/ScanDependencies.cpp @@ -254,6 +254,10 @@ computeTransitiveClosureOfExplicitDependencies( llvm::set_union(modReachableSet, succReachableSet); } } + // For ease of use down-the-line, remove the node's self from its set of reachable nodes + for (const auto &modID : topologicallySortedModuleList) + result[modID].erase(modID); + return result; } From 1141e59b314b9505b40a9793e8ffc8fc9156c78c Mon Sep 17 00:00:00 2001 From: Ben Barham Date: Mon, 12 Jun 2023 11:34:20 -0700 Subject: [PATCH 24/37] [Test] Update expected macro error https://github.com/apple/swift/pull/66497 and https://github.com/apple/swift/pull/66482 succeeded separately, then merged. But after 66497 the error now includes parentheses. Resolves rdar://110655182. --- test/Serialization/macros.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Serialization/macros.swift b/test/Serialization/macros.swift index 4933762698d3f..e700da4b6528b 100644 --- a/test/Serialization/macros.swift +++ b/test/Serialization/macros.swift @@ -21,7 +21,7 @@ func test(a: Int, b: Int) { struct TestStruct { @myWrapper var x: Int - // expected-error@-1{{expansion of macro 'myWrapper' did not produce a non-observing accessor}} + // expected-error@-1{{expansion of macro 'myWrapper()' did not produce a non-observing accessor}} } @ArbitraryMembers From b974d97879760611e376f284b8f510bd0a18a29d Mon Sep 17 00:00:00 2001 From: Artem Chikin Date: Fri, 9 Jun 2023 13:50:07 -0700 Subject: [PATCH 25/37] [Dependency Scanning] Record header dependencies of Binary Swift module dependencies These are meant to capture paths to the PCH files that a given module was built with. --- include/swift/AST/ModuleDependencies.h | 37 +++++++++----- .../SerializedModuleDependencyCacheFormat.h | 1 + .../Serialization/SerializedModuleLoader.h | 23 +++++---- .../ModuleDependencyCacheSerialization.cpp | 23 ++++++--- lib/Serialization/ModuleDependencyScanner.cpp | 15 +++--- lib/Serialization/SerializedModuleLoader.cpp | 49 +++++++++++++------ 6 files changed, 97 insertions(+), 51 deletions(-) diff --git a/include/swift/AST/ModuleDependencies.h b/include/swift/AST/ModuleDependencies.h index 98dbc1de8fda6..dde8b9ef26984 100644 --- a/include/swift/AST/ModuleDependencies.h +++ b/include/swift/AST/ModuleDependencies.h @@ -106,10 +106,15 @@ class ModuleDependencyInfoStorageBase { const ModuleDependencyKind dependencyKind; ModuleDependencyInfoStorageBase(ModuleDependencyKind dependencyKind, - StringRef moduleCacheKey = "", - bool resolved = false) + StringRef moduleCacheKey = "") : dependencyKind(dependencyKind), moduleCacheKey(moduleCacheKey.str()), - resolved(resolved) {} + resolved(false) { } + + ModuleDependencyInfoStorageBase(ModuleDependencyKind dependencyKind, + const std::vector &moduleImports, + StringRef moduleCacheKey = "") + : dependencyKind(dependencyKind), moduleImports(moduleImports), + moduleCacheKey(moduleCacheKey.str()), resolved(false) {} virtual ModuleDependencyInfoStorageBase *clone() const = 0; @@ -282,12 +287,15 @@ class SwiftBinaryModuleDependencyStorage : public ModuleDependencyInfoStorageBas SwiftBinaryModuleDependencyStorage(const std::string &compiledModulePath, const std::string &moduleDocPath, const std::string &sourceInfoPath, + const std::vector &moduleImports, + const std::vector &headerImports, const bool isFramework, const std::string &moduleCacheKey) : ModuleDependencyInfoStorageBase(ModuleDependencyKind::SwiftBinary, - moduleCacheKey), + moduleImports, moduleCacheKey), compiledModulePath(compiledModulePath), moduleDocPath(moduleDocPath), - sourceInfoPath(sourceInfoPath), isFramework(isFramework) {} + sourceInfoPath(sourceInfoPath), preCompiledBridgingHeaderPaths(headerImports), + isFramework(isFramework) {} ModuleDependencyInfoStorageBase *clone() const override { return new SwiftBinaryModuleDependencyStorage(*this); @@ -302,6 +310,9 @@ class SwiftBinaryModuleDependencyStorage : public ModuleDependencyInfoStorageBas /// The path to the .swiftSourceInfo file. const std::string sourceInfoPath; + /// The paths of all the .pch dependencies of this module. + const std::vector preCompiledBridgingHeaderPaths; + /// A flag that indicates this dependency is a framework const bool isFramework; @@ -447,15 +458,17 @@ class ModuleDependencyInfo { } /// Describe the module dependencies for a serialized or parsed Swift module. - static ModuleDependencyInfo - forSwiftBinaryModule(const std::string &compiledModulePath, - const std::string &moduleDocPath, - const std::string &sourceInfoPath, bool isFramework, - const std::string &moduleCacheKey) { + static ModuleDependencyInfo forSwiftBinaryModule( + const std::string &compiledModulePath, + const std::string &moduleDocPath, + const std::string &sourceInfoPath, + const std::vector &moduleImports, + const std::vector &headerImports, + bool isFramework, const std::string &moduleCacheKey) { return ModuleDependencyInfo( std::make_unique( - compiledModulePath, moduleDocPath, sourceInfoPath, isFramework, - moduleCacheKey)); + compiledModulePath, moduleDocPath, sourceInfoPath, + moduleImports, headerImports, isFramework, moduleCacheKey)); } /// Describe the main Swift module. diff --git a/include/swift/DependencyScan/SerializedModuleDependencyCacheFormat.h b/include/swift/DependencyScan/SerializedModuleDependencyCacheFormat.h index 3e9f4eeb4ca15..b702b07d79739 100644 --- a/include/swift/DependencyScan/SerializedModuleDependencyCacheFormat.h +++ b/include/swift/DependencyScan/SerializedModuleDependencyCacheFormat.h @@ -165,6 +165,7 @@ using SwiftBinaryModuleDetailsLayout = FileIDField, // compiledModulePath FileIDField, // moduleDocPath FileIDField, // moduleSourceInfoPath + ImportArrayIDField, // headerImports IsFrameworkField, // isFramework IdentifierIDField // moduleCacheKey >; diff --git a/include/swift/Serialization/SerializedModuleLoader.h b/include/swift/Serialization/SerializedModuleLoader.h index b13b2fb177798..085deabdda8c4 100644 --- a/include/swift/Serialization/SerializedModuleLoader.h +++ b/include/swift/Serialization/SerializedModuleLoader.h @@ -150,15 +150,20 @@ class SerializedModuleLoaderBase : public ModuleLoader { /// Scan the given serialized module file to determine dependencies. llvm::ErrorOr scanModuleFile(Twine modulePath, bool isFramework); - static llvm::ErrorOr> - getModuleImportsOfModule(Twine modulePath, - ModuleLoadingBehavior transitiveBehavior, - bool isFramework, - bool isRequiredOSSAModules, - StringRef SDKName, - StringRef packageName, - llvm::vfs::FileSystem *fileSystem, - PathObfuscator &recoverer); + struct BinaryModuleImports { + llvm::StringSet<> moduleImports; + llvm::StringSet<> headerImports; + }; + + static llvm::ErrorOr + getImportsOfModule(Twine modulePath, + ModuleLoadingBehavior transitiveBehavior, + bool isFramework, + bool isRequiredOSSAModules, + StringRef SDKName, + StringRef packageName, + llvm::vfs::FileSystem *fileSystem, + PathObfuscator &recoverer); /// Load the module file into a buffer and also collect its module name. static std::unique_ptr diff --git a/lib/DependencyScan/ModuleDependencyCacheSerialization.cpp b/lib/DependencyScan/ModuleDependencyCacheSerialization.cpp index 184f356ef78c4..e8c786323e5c7 100644 --- a/lib/DependencyScan/ModuleDependencyCacheSerialization.cpp +++ b/lib/DependencyScan/ModuleDependencyCacheSerialization.cpp @@ -462,10 +462,11 @@ bool ModuleDependenciesCacheDeserializer::readGraph(SwiftDependencyScanningServi "Unexpected SWIFT_BINARY_MODULE_DETAILS_NODE record"); cache.configureForContextHash(getContextHash()); unsigned compiledModulePathID, moduleDocPathID, moduleSourceInfoPathID, - isFramework, moduleCacheKeyID; + headerImportsArrayID, isFramework, moduleCacheKeyID; SwiftBinaryModuleDetailsLayout::readRecord( Scratch, compiledModulePathID, moduleDocPathID, - moduleSourceInfoPathID, isFramework, moduleCacheKeyID); + moduleSourceInfoPathID, headerImportsArrayID, isFramework, + moduleCacheKeyID); auto compiledModulePath = getIdentifier(compiledModulePathID); if (!compiledModulePath) @@ -477,16 +478,18 @@ bool ModuleDependenciesCacheDeserializer::readGraph(SwiftDependencyScanningServi if (!moduleSourceInfoPath) llvm::report_fatal_error("Bad module source info path"); auto moduleCacheKey = getIdentifier(moduleCacheKeyID); - if (!moduleCacheKeyID) + if (!moduleCacheKey) llvm::report_fatal_error("Bad moduleCacheKey"); + auto headerImports = getStringArray(headerImportsArrayID); + if (!headerImports) + llvm::report_fatal_error("Bad binary direct dependencies: no header imports"); + // Form the dependencies storage object auto moduleDep = ModuleDependencyInfo::forSwiftBinaryModule( - *compiledModulePath, *moduleDocPath, *moduleSourceInfoPath, - isFramework, *moduleCacheKey); - // Add dependencies of this module - for (const auto &moduleName : *currentModuleImports) - moduleDep.addModuleImport(moduleName); + *compiledModulePath, *moduleDocPath, *moduleSourceInfoPath, + *currentModuleImports, *headerImports, isFramework, + *moduleCacheKey); cache.recordDependency(currentModuleName, std::move(moduleDep), getContextHash()); @@ -704,6 +707,7 @@ bool swift::dependencies::module_dependency_cache_serialization:: enum ModuleIdentifierArrayKind : uint8_t { Empty = 0, DependencyImports, + DependencyHeaders, QualifiedModuleDependencyIDs, CompiledModuleCandidates, BuildCommandLine, @@ -975,6 +979,7 @@ void ModuleDependenciesCacheSerializer::writeModuleInfo(ModuleDependencyID modul getIdentifier(swiftBinDeps->compiledModulePath), getIdentifier(swiftBinDeps->moduleDocPath), getIdentifier(swiftBinDeps->sourceInfoPath), + getArrayID(moduleID, ModuleIdentifierArrayKind::DependencyHeaders), swiftBinDeps->isFramework, getIdentifier(swiftBinDeps->moduleCacheKey)); @@ -1152,6 +1157,8 @@ void ModuleDependenciesCacheSerializer::collectStringsAndArrays( addIdentifier(swiftBinDeps->moduleDocPath); addIdentifier(swiftBinDeps->sourceInfoPath); addIdentifier(swiftBinDeps->moduleCacheKey); + addStringArray(moduleID, ModuleIdentifierArrayKind::DependencyHeaders, + swiftBinDeps->preCompiledBridgingHeaderPaths); break; } case swift::ModuleDependencyKind::SwiftPlaceholder: { diff --git a/lib/Serialization/ModuleDependencyScanner.cpp b/lib/Serialization/ModuleDependencyScanner.cpp index ecac3a5160d83..335cfd1e185b4 100644 --- a/lib/Serialization/ModuleDependencyScanner.cpp +++ b/lib/Serialization/ModuleDependencyScanner.cpp @@ -208,38 +208,41 @@ ErrorOr ModuleDependencyScanner::scanInterfaceFile( }); if (adjacentBinaryModule != compiledCandidates.end()) { // Required modules. - auto adjacentBinaryModuleRequiredImports = getModuleImportsOfModule( + auto adjacentBinaryModuleRequiredImports = getImportsOfModule( *adjacentBinaryModule, ModuleLoadingBehavior::Required, isFramework, isRequiredOSSAModules(), Ctx.LangOpts.SDKName, Ctx.LangOpts.PackageName, Ctx.SourceMgr.getFileSystem().get(), Ctx.SearchPathOpts.DeserializedPathRecoverer); if (!adjacentBinaryModuleRequiredImports) return adjacentBinaryModuleRequiredImports.getError(); - + auto adjacentBinaryModuleRequiredModuleImports = + (*adjacentBinaryModuleRequiredImports).moduleImports; #ifndef NDEBUG // Verify that the set of required modules read out from the binary // module is a super-set of module imports identified in the // textual interface. for (const auto &requiredImport : Result->getModuleImports()) { - assert(adjacentBinaryModuleRequiredImports->contains(requiredImport) && + assert(adjacentBinaryModuleRequiredModuleImports.contains(requiredImport) && "Expected adjacent binary module's import set to contain all " "textual interface imports."); } #endif - for (const auto &requiredImport : *adjacentBinaryModuleRequiredImports) + for (const auto &requiredImport : adjacentBinaryModuleRequiredModuleImports) Result->addModuleImport(requiredImport.getKey(), &alreadyAddedModules); // Optional modules. Will be looked-up on a best-effort basis - auto adjacentBinaryModuleOptionalImports = getModuleImportsOfModule( + auto adjacentBinaryModuleOptionalImports = getImportsOfModule( *adjacentBinaryModule, ModuleLoadingBehavior::Optional, isFramework, isRequiredOSSAModules(), Ctx.LangOpts.SDKName, Ctx.LangOpts.PackageName, Ctx.SourceMgr.getFileSystem().get(), Ctx.SearchPathOpts.DeserializedPathRecoverer); if (!adjacentBinaryModuleOptionalImports) return adjacentBinaryModuleOptionalImports.getError(); - for (const auto &optionalImport : *adjacentBinaryModuleOptionalImports) + auto adjacentBinaryModuleOptionalModuleImports = + (*adjacentBinaryModuleOptionalImports).moduleImports; + for (const auto &optionalImport : adjacentBinaryModuleOptionalModuleImports) Result->addOptionalModuleImport(optionalImport.getKey(), &alreadyAddedModules); } diff --git a/lib/Serialization/SerializedModuleLoader.cpp b/lib/Serialization/SerializedModuleLoader.cpp index 8a55635f35f69..56327b501b71a 100644 --- a/lib/Serialization/SerializedModuleLoader.cpp +++ b/lib/Serialization/SerializedModuleLoader.cpp @@ -392,8 +392,8 @@ std::error_code SerializedModuleLoaderBase::openModuleFile( return std::error_code(); } -llvm::ErrorOr> -SerializedModuleLoaderBase::getModuleImportsOfModule( +llvm::ErrorOr +SerializedModuleLoaderBase::getImportsOfModule( Twine modulePath, ModuleLoadingBehavior transitiveBehavior, bool isFramework, bool isRequiredOSSAModules, StringRef SDKName, StringRef packageName, llvm::vfs::FileSystem *fileSystem, @@ -403,6 +403,7 @@ SerializedModuleLoaderBase::getModuleImportsOfModule( return moduleBuf.getError(); llvm::StringSet<> importedModuleNames; + llvm::StringSet<> importedHeaders; // Load the module file without validation. std::shared_ptr loadedModuleFile; serialization::ValidationInfo loadInfo = ModuleFileSharedCore::load( @@ -410,9 +411,10 @@ SerializedModuleLoaderBase::getModuleImportsOfModule( isRequiredOSSAModules, SDKName, recoverer, loadedModuleFile); for (const auto &dependency : loadedModuleFile->getDependencies()) { - // FIXME: Record header dependency? - if (dependency.isHeader()) + if (dependency.isHeader()) { + importedHeaders.insert(dependency.RawPath); continue; + } ModuleLoadingBehavior dependencyTransitiveBehavior = loadedModuleFile->getTransitiveLoadingBehavior( @@ -433,17 +435,13 @@ SerializedModuleLoaderBase::getModuleImportsOfModule( importedModuleNames.insert(moduleName); } - return importedModuleNames; + return SerializedModuleLoaderBase::BinaryModuleImports{importedModuleNames, importedHeaders}; } llvm::ErrorOr SerializedModuleLoaderBase::scanModuleFile(Twine modulePath, bool isFramework) { const std::string moduleDocPath; const std::string sourceInfoPath; - // Map the set of dependencies over to the "module dependencies". - auto dependencies = ModuleDependencyInfo::forSwiftBinaryModule( - modulePath.str(), moduleDocPath, sourceInfoPath, isFramework, - /*module-cache-key*/ ""); // Some transitive dependencies of binary modules are not required to be // imported during normal builds. // TODO: This is worth revisiting for debugger purposes where @@ -452,18 +450,37 @@ SerializedModuleLoaderBase::scanModuleFile(Twine modulePath, bool isFramework) { // optional. ModuleLoadingBehavior transitiveLoadingBehavior = ModuleLoadingBehavior::Required; - auto importedModuleNames = getModuleImportsOfModule( + auto binaryModuleImports = getImportsOfModule( modulePath, transitiveLoadingBehavior, isFramework, isRequiredOSSAModules(), Ctx.LangOpts.SDKName, Ctx.LangOpts.PackageName, Ctx.SourceMgr.getFileSystem().get(), Ctx.SearchPathOpts.DeserializedPathRecoverer); - if (!importedModuleNames) - return importedModuleNames.getError(); + if (!binaryModuleImports) + return binaryModuleImports.getError(); + + auto importedModuleSet = binaryModuleImports.get().moduleImports; + std::vector importedModuleNames; + importedModuleNames.reserve(importedModuleSet.size()); + llvm::transform(importedModuleSet.keys(), + std::back_inserter(importedModuleNames), + [](llvm::StringRef N) { + return N.str(); + }); + + auto importedHeaderSet = binaryModuleImports.get().headerImports; + std::vector importedHeaders; + importedHeaders.reserve(importedHeaderSet.size()); + llvm::transform(importedHeaderSet.keys(), + std::back_inserter(importedHeaders), + [](llvm::StringRef N) { + return N.str(); + }); - llvm::StringSet<> addedModuleNames; - for (const auto &importedModuleName : *importedModuleNames) - dependencies.addModuleImport(importedModuleName.getKey(), - &addedModuleNames); + // Map the set of dependencies over to the "module dependencies". + auto dependencies = ModuleDependencyInfo::forSwiftBinaryModule( + modulePath.str(), moduleDocPath, sourceInfoPath, + importedModuleNames, importedHeaders, isFramework, + /*module-cache-key*/ ""); return std::move(dependencies); } From 92d9e61d1aaf532176db7aa0493513213a779d11 Mon Sep 17 00:00:00 2001 From: Artem Chikin Date: Mon, 12 Jun 2023 10:35:00 -0400 Subject: [PATCH 26/37] [Dependency Scanning] Emit header dependencies of binary Swift module dependencies in output and provide libSwiftScan API to query it --- .../swift-c/DependencyScan/DependencyScan.h | 4 ++ .../swift/DependencyScan/DependencyScanImpl.h | 4 ++ .../swift/Frontend/ModuleInterfaceLoader.h | 56 +++++++++------ lib/DependencyScan/ScanDependencies.cpp | 14 ++++ lib/Frontend/ModuleInterfaceLoader.cpp | 4 +- .../Inputs/Swift/FooClient.swiftinterface | 5 ++ .../header_deps_of_binary.swift | 70 +++++++++++++++++++ tools/libSwiftScan/libSwiftScan.cpp | 6 ++ tools/libSwiftScan/libSwiftScan.exports | 1 + 9 files changed, 139 insertions(+), 25 deletions(-) create mode 100644 test/ScanDependencies/Inputs/Swift/FooClient.swiftinterface create mode 100644 test/ScanDependencies/header_deps_of_binary.swift diff --git a/include/swift-c/DependencyScan/DependencyScan.h b/include/swift-c/DependencyScan/DependencyScan.h index 998c8309bf352..07d6b2217e841 100644 --- a/include/swift-c/DependencyScan/DependencyScan.h +++ b/include/swift-c/DependencyScan/DependencyScan.h @@ -180,6 +180,10 @@ SWIFTSCAN_PUBLIC swiftscan_string_ref_t swiftscan_swift_binary_detail_get_module_source_info_path( swiftscan_module_details_t details); +SWIFTSCAN_PUBLIC swiftscan_string_set_t * +swiftscan_swift_binary_detail_get_header_dependencies( + swiftscan_module_details_t details); + SWIFTSCAN_PUBLIC bool swiftscan_swift_binary_detail_get_is_framework( swiftscan_module_details_t details); diff --git a/include/swift/DependencyScan/DependencyScanImpl.h b/include/swift/DependencyScan/DependencyScanImpl.h index 92b3d45851a8a..a0ac5751d298f 100644 --- a/include/swift/DependencyScan/DependencyScanImpl.h +++ b/include/swift/DependencyScan/DependencyScanImpl.h @@ -121,6 +121,10 @@ typedef struct { /// The path to the .swiftSourceInfo file. swiftscan_string_ref_t module_source_info_path; + /// (Clang) header dependencies of this binary module. + /// Typically pre-compiled bridging header. + swiftscan_string_set_t *header_dependencies; + /// A flag to indicate whether or not this module is a framework. bool is_framework; diff --git a/include/swift/Frontend/ModuleInterfaceLoader.h b/include/swift/Frontend/ModuleInterfaceLoader.h index 3c0d148ba62e0..4d61b939be13e 100644 --- a/include/swift/Frontend/ModuleInterfaceLoader.h +++ b/include/swift/Frontend/ModuleInterfaceLoader.h @@ -241,12 +241,14 @@ struct ExplicitSwiftModuleInputInfo { ExplicitSwiftModuleInputInfo(std::string modulePath, llvm::Optional moduleDocPath, llvm::Optional moduleSourceInfoPath, + llvm::Optional> headerDependencyPaths, bool isFramework = false, bool isSystem = false, llvm::Optional moduleCacheKey = None) : modulePath(modulePath), moduleDocPath(moduleDocPath), moduleSourceInfoPath(moduleSourceInfoPath), + headerDependencyPaths(headerDependencyPaths), isFramework(isFramework), isSystem(isSystem), moduleCacheKey(moduleCacheKey) {} @@ -256,6 +258,8 @@ struct ExplicitSwiftModuleInputInfo { llvm::Optional moduleDocPath; // Path of the .swiftsourceinfo file. llvm::Optional moduleSourceInfoPath; + // Paths of the precompiled header dependencies of this module. + llvm::Optional> headerDependencyPaths; // A flag that indicates whether this module is a framework bool isFramework = false; // A flag that indicates whether this module is a system module @@ -369,34 +373,39 @@ class ExplicitModuleMapParser { llvm::Optional swiftModulePath, swiftModuleDocPath, swiftModuleSourceInfoPath, swiftModuleCacheKey, clangModuleCacheKey; + llvm::Optional> headerDependencyPaths; std::string clangModuleMapPath = "", clangModulePath = ""; bool isFramework = false, isSystem = false; for (auto &entry : *mapNode) { auto key = getScalaNodeText(entry.getKey()); - auto val = getScalaNodeText(entry.getValue()); - if (key == "moduleName") { - moduleName = val; - } else if (key == "modulePath") { - swiftModulePath = val.str(); - } else if (key == "docPath") { - swiftModuleDocPath = val.str(); - } else if (key == "sourceInfoPath") { - swiftModuleSourceInfoPath = val.str(); - } else if (key == "isFramework") { - isFramework = parseBoolValue(val); - } else if (key == "isSystem") { - isSystem = parseBoolValue(val); - } else if (key == "clangModuleMapPath") { - clangModuleMapPath = val.str(); - } else if (key == "clangModulePath") { - clangModulePath = val.str(); - } else if (key == "moduleCacheKey") { - swiftModuleCacheKey = val.str(); - } else if (key == "clangModuleCacheKey") { - clangModuleCacheKey = val.str(); - } else { - // Being forgiving for future fields. + if (key == "prebuiltHeaderDependencyPaths") { continue; + } else { + auto val = getScalaNodeText(entry.getValue()); + if (key == "moduleName") { + moduleName = val; + } else if (key == "modulePath") { + swiftModulePath = val.str(); + } else if (key == "docPath") { + swiftModuleDocPath = val.str(); + } else if (key == "sourceInfoPath") { + swiftModuleSourceInfoPath = val.str(); + } else if (key == "isFramework") { + isFramework = parseBoolValue(val); + } else if (key == "isSystem") { + isSystem = parseBoolValue(val); + } else if (key == "clangModuleMapPath") { + clangModuleMapPath = val.str(); + } else if (key == "clangModulePath") { + clangModulePath = val.str(); + } else if (key == "moduleCacheKey") { + swiftModuleCacheKey = val.str(); + } else if (key == "clangModuleCacheKey") { + clangModuleCacheKey = val.str(); + } else { + // Being forgiving for future fields. + continue; + } } } if (moduleName.empty()) @@ -409,6 +418,7 @@ class ExplicitModuleMapParser { ExplicitSwiftModuleInputInfo entry(swiftModulePath.value(), swiftModuleDocPath, swiftModuleSourceInfoPath, + headerDependencyPaths, isFramework, isSystem, swiftModuleCacheKey); diff --git a/lib/DependencyScan/ScanDependencies.cpp b/lib/DependencyScan/ScanDependencies.cpp index b1246ae133573..396a965d1e4d1 100644 --- a/lib/DependencyScan/ScanDependencies.cpp +++ b/lib/DependencyScan/ScanDependencies.cpp @@ -334,6 +334,12 @@ static llvm::Error resolveExplicitModuleInputs( : binaryDepDetails->moduleCacheKey; commandLine.push_back("-swift-module-file=" + depModuleID.first + "=" + path); + for (const auto &headerDep : binaryDepDetails->preCompiledBridgingHeaderPaths) { + commandLine.push_back("-Xcc"); + commandLine.push_back("-include-pch"); + commandLine.push_back("-Xcc"); + commandLine.push_back(headerDep); + } } break; case swift::ModuleDependencyKind::SwiftPlaceholder: { auto placeholderDetails = depInfo->getAsPlaceholderDependencyModule(); @@ -1167,6 +1173,13 @@ static void writeJSON(llvm::raw_ostream &out, swiftBinaryDeps->module_cache_key, 5, /*trailingComma=*/true); } + + // Module Header Dependencies + if (swiftBinaryDeps->header_dependencies->count != 0) + writeJSONSingleField(out, "headerDependencies", + swiftBinaryDeps->header_dependencies, 5, + /*trailingComma=*/true); + writeJSONSingleField(out, "isFramework", swiftBinaryDeps->is_framework, 5, /*trailingComma=*/false); } else { @@ -1403,6 +1416,7 @@ generateFullDependencyGraph(CompilerInstance &instance, create_clone(swiftBinaryDeps->compiledModulePath.c_str()), create_clone(swiftBinaryDeps->moduleDocPath.c_str()), create_clone(swiftBinaryDeps->sourceInfoPath.c_str()), + create_set(swiftBinaryDeps->preCompiledBridgingHeaderPaths), swiftBinaryDeps->isFramework, create_clone(swiftBinaryDeps->moduleCacheKey.c_str())}; } else { diff --git a/lib/Frontend/ModuleInterfaceLoader.cpp b/lib/Frontend/ModuleInterfaceLoader.cpp index af9a42220d986..b12ac463d0efe 100644 --- a/lib/Frontend/ModuleInterfaceLoader.cpp +++ b/lib/Frontend/ModuleInterfaceLoader.cpp @@ -2004,7 +2004,7 @@ struct ExplicitSwiftModuleLoader::Implementation { const std::vector> &commandLineExplicitInputs) { for (const auto &moduleInput : commandLineExplicitInputs) { - ExplicitSwiftModuleInputInfo entry(moduleInput.second, {}, {}); + ExplicitSwiftModuleInputInfo entry(moduleInput.second, {}, {}, {}); ExplicitModuleMap.try_emplace(moduleInput.first, std::move(entry)); } } @@ -2270,7 +2270,7 @@ struct ExplicitCASModuleLoader::Implementation { const std::vector> &commandLineExplicitInputs) { for (const auto &moduleInput : commandLineExplicitInputs) { - ExplicitSwiftModuleInputInfo entry(moduleInput.second, {}, {}); + ExplicitSwiftModuleInputInfo entry(moduleInput.second, {}, {}, {}); ExplicitModuleMap.try_emplace(moduleInput.first, std::move(entry)); } } diff --git a/test/ScanDependencies/Inputs/Swift/FooClient.swiftinterface b/test/ScanDependencies/Inputs/Swift/FooClient.swiftinterface new file mode 100644 index 0000000000000..dbf1aa40270ea --- /dev/null +++ b/test/ScanDependencies/Inputs/Swift/FooClient.swiftinterface @@ -0,0 +1,5 @@ +// swift-interface-format-version: 1.0 +// swift-module-flags: -module-name FooClient +import Swift +import Foo +public func overlayFuncA() { } diff --git a/test/ScanDependencies/header_deps_of_binary.swift b/test/ScanDependencies/header_deps_of_binary.swift new file mode 100644 index 0000000000000..421840c21cce9 --- /dev/null +++ b/test/ScanDependencies/header_deps_of_binary.swift @@ -0,0 +1,70 @@ +// REQUIRES: objc_interop, OS=macosx +// RUN: %empty-directory(%t) +// RUN: %empty-directory(%t/clang-module-cache) +// RUN: %empty-directory(%t/PCH) +// RUN: %empty-directory(%t/SwiftModules) + +// - Set up Foo Swift dependency +// RUN: echo "extension Profiler {" >> %t/foo.swift +// RUN: echo " public static let count: Int = 42" >> %t/foo.swift +// RUN: echo "}" >> %t/foo.swift + +// - Set up Foo bridging header +// RUN: echo "struct Profiler { void* ptr; };" >> %t/foo.h + +// - Compile bridging header +// RUN: %target-swift-frontend -enable-objc-interop -emit-pch %t/foo.h -o %t/PCH/foo.pch -disable-implicit-swift-modules + +// - Set up explicit dependencies for Foo +// RUN: %target-swift-emit-pcm -module-name SwiftShims %swift-lib-dir/swift/shims/module.modulemap -o %t/inputs/SwiftShims.pcm +// RUN: %target-swift-emit-pcm -module-name _SwiftConcurrencyShims %swift-lib-dir/swift/shims/module.modulemap -o %t/inputs/_SwiftConcurrencyShims.pcm +// RUN: echo "[{" > %t/foo_inputs_map.json +// RUN: echo "\"moduleName\": \"Swift\"," >> %t/foo_inputs_map.json +// RUN: echo "\"modulePath\": \"%/stdlib_module\"," >> %t/foo_inputs_map.json +// RUN: echo "\"isFramework\": false" >> %t/foo_inputs_map.json +// RUN: echo "}," >> %t/foo_inputs_map.json +// RUN: echo "{" >> %t/foo_inputs_map.json +// RUN: echo "\"moduleName\": \"SwiftOnoneSupport\"," >> %t/foo_inputs_map.json +// RUN: echo "\"modulePath\": \"%/ononesupport_module\"," >> %t/foo_inputs_map.json +// RUN: echo "\"isFramework\": false" >> %t/foo_inputs_map.json +// RUN: echo "}," >> %t/foo_inputs_map.json +// RUN: echo "{" >> %t/foo_inputs_map.json +// RUN: echo "\"moduleName\": \"_StringProcessing\"," >> %t/foo_inputs_map.json +// RUN: echo "\"modulePath\": \"%/string_processing_module\"," >> %t/foo_inputs_map.json +// RUN: echo "\"isFramework\": false" >> %t/foo_inputs_map.json +// RUN: echo "}," >> %t/foo_inputs_map.json +// RUN: echo "{" >> %t/foo_inputs_map.json +// RUN: echo "\"moduleName\": \"SwiftShims\"," >> %t/foo_inputs_map.json +// RUN: echo "\"isFramework\": false," >> %t/foo_inputs_map.json +// RUN: echo "\"clangModuleMapPath\": \"%swift-lib-dir/swift/shims/module.modulemap\"," >> %t/foo_inputs_map.json +// RUN: echo "\"clangModulePath\": \"%t/inputs/SwiftShims.pcm\"" >> %t/foo_inputs_map.json +// RUN: echo "}," >> %t/foo_inputs_map.json +// RUN: echo "{" >> %t/foo_inputs_map.json +// RUN: echo "\"moduleName\": \"_SwiftConcurrencyShims\"," >> %t/foo_inputs_map.json +// RUN: echo "\"isFramework\": false," >> %t/foo_inputs_map.json +// RUN: echo "\"clangModuleMapPath\": \"%swift-lib-dir/swift/shims/module.modulemap\"," >> %t/foo_inputs_map.json +// RUN: echo "\"clangModulePath\": \"%t/inputs/_SwiftConcurrencyShims.pcm\"" >> %t/foo_inputs_map.json +// RUN: echo "}]" >> %t/foo_inputs_map.json + +// - Build Foo module dependency, explicitly +// RUN: %target-swift-frontend -emit-module -emit-module-path %t/SwiftModules/Foo.swiftmodule %t/foo.swift -module-name Foo -import-objc-header %t/PCH/foo.pch -disable-implicit-concurrency-module-import -disable-implicit-string-processing-module-import -disable-implicit-swift-modules -explicit-swift-module-map-file %t/foo_inputs_map.json + +// - Scan main module +// RUN: %target-swift-frontend -scan-dependencies %s -I %t/SwiftModules -I %S/Inputs/Swift -o %t/deps.json +// RUN: %FileCheck %s --input-file %t/deps.json + +// CHECK: "swift": "FooClient" +// CHECK: "swift": "FooClient" +// CHECK: "swiftPrebuiltExternal": "Foo" +// CHECK: "commandLine": [ +// CHECK: "-include-pch", +// CHECK-NEXT: "-Xcc", +// CHECK-NEXT: "{{.*}}{{/|\\}}PCH{{/|\\}}foo.pch" + + +// CHECK: "swiftPrebuiltExternal": "Foo" +// CHECK: "headerDependencies": [ +// CHECK: "{{.*}}{{/|\\}}PCH{{/|\\}}foo.pch" +// CHECK: ], + +import FooClient diff --git a/tools/libSwiftScan/libSwiftScan.cpp b/tools/libSwiftScan/libSwiftScan.cpp index 8e2e69e6c6820..1091ca4888d1e 100644 --- a/tools/libSwiftScan/libSwiftScan.cpp +++ b/tools/libSwiftScan/libSwiftScan.cpp @@ -344,6 +344,12 @@ swiftscan_swift_binary_detail_get_module_source_info_path( return details->swift_binary_details.module_source_info_path; } +swiftscan_string_set_t * +swiftscan_swift_binary_detail_get_header_dependencies( + swiftscan_module_details_t details) { + return details->swift_binary_details.header_dependencies; +} + bool swiftscan_swift_binary_detail_get_is_framework( swiftscan_module_details_t details) { return details->swift_binary_details.is_framework; diff --git a/tools/libSwiftScan/libSwiftScan.exports b/tools/libSwiftScan/libSwiftScan.exports index ff1d5337276fe..9e30dbb0aaa7a 100644 --- a/tools/libSwiftScan/libSwiftScan.exports +++ b/tools/libSwiftScan/libSwiftScan.exports @@ -22,6 +22,7 @@ swiftscan_swift_textual_detail_get_module_cache_key swiftscan_swift_binary_detail_get_compiled_module_path swiftscan_swift_binary_detail_get_module_doc_path swiftscan_swift_binary_detail_get_module_source_info_path +swiftscan_swift_binary_detail_get_header_dependencies swiftscan_swift_binary_detail_get_is_framework swiftscan_swift_binary_detail_get_module_cache_key swiftscan_swift_placeholder_detail_get_compiled_module_path From 775b4a47c0887431eb06f85ef73641139c66eaf0 Mon Sep 17 00:00:00 2001 From: Allan Shortlidge Date: Fri, 9 Jun 2023 14:34:31 -0700 Subject: [PATCH 27/37] AST: Inherit access level of opaque type decls from naming decl. When an `OpaqueTypeDecl` is constructed, the access level attributes of the decl that names the opaque type were copied on to it. However, the `@usableFromInline` attribute is not permitted on every decl, so it does not get copied. This in turn causes access level computations for opaque types to fail to take `@usableFromInline` into account and that results in the emitted symbol getting the wrong linkage during IRGen. The fix is to make access level computations take this quirk of opaque types into account directly (like they already to for several other kinds of decls), instead of relying on copying of attributes. Resolves rdar://110544170 --- lib/AST/AccessRequests.cpp | 7 +++++++ lib/AST/Decl.cpp | 9 +++++++++ lib/Sema/TypeCheckGeneric.cpp | 1 - test/IRGen/Inputs/AlwaysInlineIntoWithOpaque.swift | 13 +++++++++++++ .../AlwaysInlineIntoWithOpaqueReplacement.swift | 5 +++++ .../opaque_result_alwaysInlineIntoClient.swift | 12 ++++++++++-- test/TBD/opaque_result_type.swift | 5 +++++ 7 files changed, 49 insertions(+), 3 deletions(-) diff --git a/lib/AST/AccessRequests.cpp b/lib/AST/AccessRequests.cpp index a32ef4f720acb..4f36950dcbbcc 100644 --- a/lib/AST/AccessRequests.cpp +++ b/lib/AST/AccessRequests.cpp @@ -67,6 +67,13 @@ AccessLevelRequest::evaluate(Evaluator &evaluator, ValueDecl *D) const { } } + // Special case for opaque type decls, which inherit the access of their + // naming decls. + if (auto *opaqueType = dyn_cast(D)) { + if (auto *namingDecl = opaqueType->getNamingDecl()) + return namingDecl->getFormalAccess(); + } + DeclContext *DC = D->getDeclContext(); // Special case for generic parameters; we just give them a dummy diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index eb62453ce060b..5cdafc50f6642 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -3749,6 +3749,15 @@ bool ValueDecl::isUsableFromInline() const { return true; } + if (auto *opaqueType = dyn_cast(this)) { + if (auto *namingDecl = opaqueType->getNamingDecl()) { + if (namingDecl->getAttrs().hasAttribute() || + namingDecl->getAttrs().hasAttribute() || + namingDecl->getAttrs().hasAttribute()) + return true; + } + } + if (auto *EED = dyn_cast(this)) if (EED->getParentEnum()->getAttrs().hasAttribute()) return true; diff --git a/lib/Sema/TypeCheckGeneric.cpp b/lib/Sema/TypeCheckGeneric.cpp index 899d8b017ea0b..82be86ccf35bf 100644 --- a/lib/Sema/TypeCheckGeneric.cpp +++ b/lib/Sema/TypeCheckGeneric.cpp @@ -213,7 +213,6 @@ OpaqueResultTypeRequest::evaluate(Evaluator &evaluator, auto opaqueDecl = OpaqueTypeDecl::get( originatingDecl, genericParams, parentDC, interfaceSignature, opaqueReprs); - opaqueDecl->copyFormalAccessFrom(originatingDecl); if (auto originatingSig = originatingDC->getGenericSignatureOfContext()) { opaqueDecl->setGenericSignature(originatingSig); } else { diff --git a/test/IRGen/Inputs/AlwaysInlineIntoWithOpaque.swift b/test/IRGen/Inputs/AlwaysInlineIntoWithOpaque.swift index 09f572bb28ba1..b5ec362ecb8c7 100644 --- a/test/IRGen/Inputs/AlwaysInlineIntoWithOpaque.swift +++ b/test/IRGen/Inputs/AlwaysInlineIntoWithOpaque.swift @@ -14,3 +14,16 @@ public func testInlineWithOpaque() -> some P { } return 2.0 } + +@_alwaysEmitIntoClient +public func testInlineWithOpaqueUsableFromInline() -> some P { + if #available(macOS 9.0, *) { + return usableFromInline() + } + return 4.0 +} + +@usableFromInline +func usableFromInline() -> some P { + return 3 +} diff --git a/test/IRGen/Inputs/AlwaysInlineIntoWithOpaqueReplacement.swift b/test/IRGen/Inputs/AlwaysInlineIntoWithOpaqueReplacement.swift index 8ab8aa865d525..8201c853d1b78 100644 --- a/test/IRGen/Inputs/AlwaysInlineIntoWithOpaqueReplacement.swift +++ b/test/IRGen/Inputs/AlwaysInlineIntoWithOpaqueReplacement.swift @@ -6,3 +6,8 @@ extension Int : P { extension Double : P { } + +@usableFromInline +func usableFromInline() -> some P { + return 3 +} diff --git a/test/IRGen/opaque_result_alwaysInlineIntoClient.swift b/test/IRGen/opaque_result_alwaysInlineIntoClient.swift index 82674435a2fd3..c123861446a22 100644 --- a/test/IRGen/opaque_result_alwaysInlineIntoClient.swift +++ b/test/IRGen/opaque_result_alwaysInlineIntoClient.swift @@ -1,11 +1,11 @@ // RUN: %empty-directory(%t) -// RUN: %target-build-swift -target %target-cpu-apple-macosx10.15 -parse-as-library -emit-library -emit-module-path %t/AlwaysInlineIntoWithOpaque.swiftmodule -module-name AlwaysInlineIntoWithOpaque %S/Inputs/AlwaysInlineIntoWithOpaque.swift -o %t/%target-library-name(AlwaysInlineIntoWithOpaque) +// RUN: %target-build-swift -target %target-cpu-apple-macosx10.15 -parse-as-library -emit-library -emit-module-path %t/AlwaysInlineIntoWithOpaque.swiftmodule -module-name AlwaysInlineIntoWithOpaque -enable-library-evolution %S/Inputs/AlwaysInlineIntoWithOpaque.swift -o %t/%target-library-name(AlwaysInlineIntoWithOpaque) // RUN: %target-codesign %t/%target-library-name(AlwaysInlineIntoWithOpaque) // RUN: %target-build-swift -target %target-cpu-apple-macosx10.15 -lAlwaysInlineIntoWithOpaque -module-name main -I %t -L %t %s -o %t/a.out // RUN: %target-codesign %t/a.out // RUN: %target-run %t/a.out | %FileCheck %s -// RUN: %target-build-swift -target %target-cpu-apple-macosx10.15 -parse-as-library -emit-library -emit-module-path %t/AlwaysInlineIntoWithOpaque.swiftmodule -module-name AlwaysInlineIntoWithOpaque %S/Inputs/AlwaysInlineIntoWithOpaqueReplacement.swift -o %t/%target-library-name(AlwaysInlineIntoWithOpaque) +// RUN: %target-build-swift -target %target-cpu-apple-macosx10.15 -parse-as-library -emit-library -emit-module-path %t/AlwaysInlineIntoWithOpaque.swiftmodule -module-name AlwaysInlineIntoWithOpaque -enable-library-evolution %S/Inputs/AlwaysInlineIntoWithOpaqueReplacement.swift -o %t/%target-library-name(AlwaysInlineIntoWithOpaque) // RUN: %target-codesign %t/a.out // RUN: %target-run %t/a.out | %FileCheck %s @@ -27,3 +27,11 @@ public func test() { test() // CHECK: 1 + +public func testUsableFromInline() { + let p = testInlineWithOpaqueUsableFromInline() + print(p) +} + +testUsableFromInline() +// CHECK: 3 diff --git a/test/TBD/opaque_result_type.swift b/test/TBD/opaque_result_type.swift index f5c6b8b0ca0eb..8cfbf652aac5d 100644 --- a/test/TBD/opaque_result_type.swift +++ b/test/TBD/opaque_result_type.swift @@ -77,6 +77,11 @@ public func dynReplacement(x: String) -> some P { return "replaced" } +@usableFromInline +func ufi() -> some O { + return 1 +} + extension String: P { public func poo() -> some O { return 0 From b459fb5fc20eee7081c107f71f8ffc50d9d5ba08 Mon Sep 17 00:00:00 2001 From: Egor Zhdan Date: Mon, 12 Jun 2023 16:22:29 +0100 Subject: [PATCH 28/37] [cxx-interop] Avoid linker errors when calling a defaulted constructor When a default constructor is declared, but does not have a body because it is defaulted (`= default;`), Swift did not emit the IR for it. This was causing linker error for types such as `std::map` in libstdc++ when someone tried to initialize such types from Swift. rdar://110638499 / resolves https://github.com/apple/swift/issues/61412 --- lib/ClangImporter/ImportDecl.cpp | 46 ++++++++++++------- test/Interop/Cxx/class/Inputs/constructors.h | 5 ++ .../Cxx/class/constructors-executable.swift | 6 +++ .../class/constructors-module-interface.swift | 5 ++ test/Interop/Cxx/stdlib/use-std-map.swift | 2 - 5 files changed, 45 insertions(+), 19 deletions(-) diff --git a/lib/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp index 88d2a9a93dd3e..48ef2808303fd 100644 --- a/lib/ClangImporter/ImportDecl.cpp +++ b/lib/ClangImporter/ImportDecl.cpp @@ -2635,30 +2635,38 @@ namespace { } clang::CXXConstructorDecl *copyCtor = nullptr; clang::CXXConstructorDecl *moveCtor = nullptr; + clang::CXXConstructorDecl *defaultCtor = nullptr; if (decl->needsImplicitCopyConstructor()) { copyCtor = clangSema.DeclareImplicitCopyConstructor( const_cast(decl)); - } else if (decl->needsImplicitMoveConstructor()) { + } + if (decl->needsImplicitMoveConstructor()) { moveCtor = clangSema.DeclareImplicitMoveConstructor( const_cast(decl)); - } else { - // We may have a defaulted copy constructor that needs to be defined. - // Try to find it. - for (auto methods : decl->methods()) { - if (auto declCtor = dyn_cast(methods)) { - if (declCtor->isDefaulted() && - declCtor->getAccess() == clang::AS_public && - !declCtor->isDeleted() && - // Note: we use "doesThisDeclarationHaveABody" here because - // that's what "DefineImplicitCopyConstructor" checks. - !declCtor->doesThisDeclarationHaveABody()) { - if (declCtor->isCopyConstructor()) { + } + if (decl->needsImplicitDefaultConstructor()) { + defaultCtor = clangSema.DeclareImplicitDefaultConstructor( + const_cast(decl)); + } + // We may have a defaulted copy/move/default constructor that needs to + // be defined. Try to find it. + for (auto methods : decl->methods()) { + if (auto declCtor = dyn_cast(methods)) { + if (declCtor->isDefaulted() && + declCtor->getAccess() == clang::AS_public && + !declCtor->isDeleted() && + // Note: we use "doesThisDeclarationHaveABody" here because + // that's what "DefineImplicitCopyConstructor" checks. + !declCtor->doesThisDeclarationHaveABody()) { + if (declCtor->isCopyConstructor()) { + if (!copyCtor) copyCtor = declCtor; - break; - } else if (declCtor->isMoveConstructor()) { + } else if (declCtor->isMoveConstructor()) { + if (!moveCtor) moveCtor = declCtor; - break; - } + } else if (declCtor->isDefaultConstructor()) { + if (!defaultCtor) + defaultCtor = declCtor; } } } @@ -2671,6 +2679,10 @@ namespace { clangSema.DefineImplicitMoveConstructor(clang::SourceLocation(), moveCtor); } + if (defaultCtor) { + clangSema.DefineImplicitDefaultConstructor(clang::SourceLocation(), + defaultCtor); + } if (decl->needsImplicitDestructor()) { auto dtor = clangSema.DeclareImplicitDestructor( diff --git a/test/Interop/Cxx/class/Inputs/constructors.h b/test/Interop/Cxx/class/Inputs/constructors.h index 4421391fae127..7493fc91cf785 100644 --- a/test/Interop/Cxx/class/Inputs/constructors.h +++ b/test/Interop/Cxx/class/Inputs/constructors.h @@ -10,6 +10,11 @@ struct ImplicitDefaultConstructor { int x = 42; }; +struct DefaultedDefaultConstructor { + int x = 42; + DefaultedDefaultConstructor() = default; +}; + struct MemberOfClassType { ImplicitDefaultConstructor member; }; diff --git a/test/Interop/Cxx/class/constructors-executable.swift b/test/Interop/Cxx/class/constructors-executable.swift index 9a8eb852d46d2..1efbb2556b6cc 100644 --- a/test/Interop/Cxx/class/constructors-executable.swift +++ b/test/Interop/Cxx/class/constructors-executable.swift @@ -19,6 +19,12 @@ CxxConstructorTestSuite.test("ImplicitDefaultConstructor") { expectEqual(42, instance.x) } +CxxConstructorTestSuite.test("DefaultedDefaultConstructor") { + let instance = DefaultedDefaultConstructor() + + expectEqual(42, instance.x) +} + CxxConstructorTestSuite.test("MemberOfClassType") { let instance = MemberOfClassType() diff --git a/test/Interop/Cxx/class/constructors-module-interface.swift b/test/Interop/Cxx/class/constructors-module-interface.swift index fab9918de6771..5f39ea6e8c1aa 100644 --- a/test/Interop/Cxx/class/constructors-module-interface.swift +++ b/test/Interop/Cxx/class/constructors-module-interface.swift @@ -9,6 +9,11 @@ // CHECK-NEXT: init(x: Int32) // CHECK-NEXT: var x: Int32 // CHECK-NEXT: } +// CHECK-NEXT: struct DefaultedDefaultConstructor { +// CHECK-NEXT: init() +// CHECK-NEXT: init(x: Int32) +// CHECK-NEXT: var x: Int32 +// CHECK-NEXT: } // CHECK-NEXT: struct MemberOfClassType { // CHECK-NEXT: init() // CHECK-NEXT: init(member: ImplicitDefaultConstructor) diff --git a/test/Interop/Cxx/stdlib/use-std-map.swift b/test/Interop/Cxx/stdlib/use-std-map.swift index 189ca92c2692d..d3480bbe22db7 100644 --- a/test/Interop/Cxx/stdlib/use-std-map.swift +++ b/test/Interop/Cxx/stdlib/use-std-map.swift @@ -11,13 +11,11 @@ import Cxx var StdMapTestSuite = TestSuite("StdMap") -#if !os(Linux) // https://github.com/apple/swift/issues/61412 StdMapTestSuite.test("init") { let m = Map() expectEqual(m.size(), 0) expectTrue(m.empty()) } -#endif StdMapTestSuite.test("Map.subscript") { // This relies on the `std::map` conformance to `CxxDictionary` protocol. From cfbbb2807e27823380ab822c85fc9daa6ceaffab Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Mon, 12 Jun 2023 16:29:56 -0700 Subject: [PATCH 29/37] [ConstraintSystem] Allow generic parameters to bind to holes only in diagnostic mode If generic parameter gets opened during regular solving it cannot be bound to a hole, that can only happen in diagnostic mode, so let's not even try. Doing so also makes sure that there are no inference side-effects related to holes because bindings are ranked based on their attributes. --- lib/Sema/ConstraintSystem.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/Sema/ConstraintSystem.cpp b/lib/Sema/ConstraintSystem.cpp index 10563c1fe10f8..0f84c8c73bfca 100644 --- a/lib/Sema/ConstraintSystem.cpp +++ b/lib/Sema/ConstraintSystem.cpp @@ -1866,11 +1866,14 @@ TypeVariableType *ConstraintSystem::openGenericParameter( auto *paramLocator = getConstraintLocator( locator.withPathElement(LocatorPathElt::GenericParameter(parameter))); - unsigned options = (TVO_PrefersSubtypeBinding | - TVO_CanBindToHole); + unsigned options = TVO_PrefersSubtypeBinding; + if (parameter->isParameterPack()) options |= TVO_CanBindToPack; + if (shouldAttemptFixes()) + options |= TVO_CanBindToHole; + auto typeVar = createTypeVariable(paramLocator, options); auto result = replacements.insert(std::make_pair( cast(parameter->getCanonicalType()), typeVar)); From e71594725a5fc2d9f5134941de423b5f3d69b02d Mon Sep 17 00:00:00 2001 From: Kavon Farvardin Date: Mon, 12 Jun 2023 17:15:46 -0700 Subject: [PATCH 30/37] be specific that only escaping closures prevent consumption rdar://109908383 --- include/swift/AST/DiagnosticsSIL.def | 2 +- test/SILGen/moveonly_escaping_closure.swift | 112 ++++---- ...nite_init_moveonly_controlflowdep_init.sil | 2 +- .../moveonly_addresschecker_diagnostics.sil | 4 +- .../moveonly_addresschecker_diagnostics.swift | 86 +++--- .../moveonly_nonescaping_closures.swift | 2 +- .../moveonly_objectchecker_diagnostics.swift | 260 +++++++++--------- ...ly_trivial_objectchecker_diagnostics.swift | 68 ++--- .../noimplicitcopy_consuming_parameters.swift | 24 +- 9 files changed, 280 insertions(+), 280 deletions(-) diff --git a/include/swift/AST/DiagnosticsSIL.def b/include/swift/AST/DiagnosticsSIL.def index df082a3ce52fd..362dbc4ed7876 100644 --- a/include/swift/AST/DiagnosticsSIL.def +++ b/include/swift/AST/DiagnosticsSIL.def @@ -766,7 +766,7 @@ ERROR(sil_movechecking_borrowed_parameter_captured_by_closure, none, "parameter", (StringRef)) ERROR(sil_movechecking_capture_consumed, none, - "noncopyable '%0' cannot be consumed when captured by a closure", (StringRef)) + "noncopyable '%0' cannot be consumed when captured by an escaping closure", (StringRef)) ERROR(sil_movechecking_inout_not_reinitialized_before_end_of_function, none, "missing reinitialization of inout parameter '%0' after consume", (StringRef)) ERROR(sil_movechecking_value_consumed_in_a_loop, none, diff --git a/test/SILGen/moveonly_escaping_closure.swift b/test/SILGen/moveonly_escaping_closure.swift index 5492cfad38810..1b20481e0147e 100644 --- a/test/SILGen/moveonly_escaping_closure.swift +++ b/test/SILGen/moveonly_escaping_closure.swift @@ -73,9 +73,9 @@ func testGlobalClosureCaptureVar() { x = SingleElt() globalClosureCaptureVar = { borrowVal(x) - consumeVal(x) // expected-error {{noncopyable 'x' cannot be consumed when captured by a closure}} - consumeVal(x) // expected-error {{noncopyable 'x' cannot be consumed when captured by a closure}} - borrowConsumeVal(x, x) // expected-error {{noncopyable 'x' cannot be consumed when captured by a closure}} + consumeVal(x) // expected-error {{noncopyable 'x' cannot be consumed when captured by an escaping closure}} + consumeVal(x) // expected-error {{noncopyable 'x' cannot be consumed when captured by an escaping closure}} + borrowConsumeVal(x, x) // expected-error {{noncopyable 'x' cannot be consumed when captured by an escaping closure}} // expected-error @-1:29 {{overlapping accesses, but deinitialization requires exclusive access}} // expected-note @-2:26 {{conflicting access is here}} } @@ -196,9 +196,9 @@ func testLocalVarClosureCaptureVar() { x = SingleElt() var f = { borrowVal(x) - consumeVal(x) // expected-error {{noncopyable 'x' cannot be consumed when captured by a closure}} - consumeVal(x) // expected-error {{noncopyable 'x' cannot be consumed when captured by a closure}} - borrowConsumeVal(x, x) // expected-error {{noncopyable 'x' cannot be consumed when captured by a closure}} + consumeVal(x) // expected-error {{noncopyable 'x' cannot be consumed when captured by an escaping closure}} + consumeVal(x) // expected-error {{noncopyable 'x' cannot be consumed when captured by an escaping closure}} + borrowConsumeVal(x, x) // expected-error {{noncopyable 'x' cannot be consumed when captured by an escaping closure}} // expected-error @-1 {{overlapping accesses, but deinitialization requires exclusive access}} // expected-note @-2 {{conflicting access is here}} } @@ -257,9 +257,9 @@ func testInOutVarClosureCaptureVar(_ f: inout () -> ()) { x = SingleElt() f = { borrowVal(x) - consumeVal(x) // expected-error {{noncopyable 'x' cannot be consumed when captured by a closure}} - consumeVal(x) // expected-error {{noncopyable 'x' cannot be consumed when captured by a closure}} - borrowConsumeVal(x, x) // expected-error {{noncopyable 'x' cannot be consumed when captured by a closure}} + consumeVal(x) // expected-error {{noncopyable 'x' cannot be consumed when captured by an escaping closure}} + consumeVal(x) // expected-error {{noncopyable 'x' cannot be consumed when captured by an escaping closure}} + borrowConsumeVal(x, x) // expected-error {{noncopyable 'x' cannot be consumed when captured by an escaping closure}} // expected-error @-1 {{overlapping accesses, but deinitialization requires exclusive access}} // expected-note @-2 {{conflicting access is here}} } @@ -326,9 +326,9 @@ func testConsumingEscapeClosureCaptureVar(_ f: consuming @escaping () -> ()) { x = SingleElt() f = { borrowVal(x) - consumeVal(x) // expected-error {{noncopyable 'x' cannot be consumed when captured by a closure}} - consumeVal(x) // expected-error {{noncopyable 'x' cannot be consumed when captured by a closure}} - borrowConsumeVal(x, x) // expected-error {{noncopyable 'x' cannot be consumed when captured by a closure}} + consumeVal(x) // expected-error {{noncopyable 'x' cannot be consumed when captured by an escaping closure}} + consumeVal(x) // expected-error {{noncopyable 'x' cannot be consumed when captured by an escaping closure}} + borrowConsumeVal(x, x) // expected-error {{noncopyable 'x' cannot be consumed when captured by an escaping closure}} // expected-error @-1 {{overlapping accesses, but deinitialization requires exclusive access}} // expected-note @-2 {{conflicting access is here}} } @@ -379,9 +379,9 @@ func testGlobalClosureCaptureLet() { let x = SingleElt() globalClosureCaptureLet = { borrowVal(x) - consumeVal(x) // expected-error {{noncopyable 'x' cannot be consumed when captured by a closure}} - consumeVal(x) // expected-error {{noncopyable 'x' cannot be consumed when captured by a closure}} - borrowConsumeVal(x, x) // expected-error {{noncopyable 'x' cannot be consumed when captured by a closure}} + consumeVal(x) // expected-error {{noncopyable 'x' cannot be consumed when captured by an escaping closure}} + consumeVal(x) // expected-error {{noncopyable 'x' cannot be consumed when captured by an escaping closure}} + borrowConsumeVal(x, x) // expected-error {{noncopyable 'x' cannot be consumed when captured by an escaping closure}} } globalClosureCaptureLet() } @@ -423,9 +423,9 @@ func testGlobalClosureCaptureLet() { // CHECK: } // end sil function '$s16moveonly_closure026testLocalLetClosureCaptureE0yyFyycfU_' func testLocalLetClosureCaptureLet() { let x = SingleElt() - // expected-error @-1 {{noncopyable 'x' cannot be consumed when captured by a closure}} - // expected-error @-2 {{noncopyable 'x' cannot be consumed when captured by a closure}} - // expected-error @-3 {{noncopyable 'x' cannot be consumed when captured by a closure}} + // expected-error @-1 {{noncopyable 'x' cannot be consumed when captured by an escaping closure}} + // expected-error @-2 {{noncopyable 'x' cannot be consumed when captured by an escaping closure}} + // expected-error @-3 {{noncopyable 'x' cannot be consumed when captured by an escaping closure}} let f = { borrowVal(x) consumeVal(x) // expected-note {{consumed here}} @@ -471,9 +471,9 @@ func testLocalVarClosureCaptureLet() { let x = SingleElt() var f = { borrowVal(x) - consumeVal(x) // expected-error {{noncopyable 'x' cannot be consumed when captured by a closure}} - consumeVal(x) // expected-error {{noncopyable 'x' cannot be consumed when captured by a closure}} - borrowConsumeVal(x, x) // expected-error {{noncopyable 'x' cannot be consumed when captured by a closure}} + consumeVal(x) // expected-error {{noncopyable 'x' cannot be consumed when captured by an escaping closure}} + consumeVal(x) // expected-error {{noncopyable 'x' cannot be consumed when captured by an escaping closure}} + borrowConsumeVal(x, x) // expected-error {{noncopyable 'x' cannot be consumed when captured by an escaping closure}} } f = {} f() @@ -519,9 +519,9 @@ func testInOutVarClosureCaptureLet(_ f: inout () -> ()) { let x = SingleElt() f = { borrowVal(x) - consumeVal(x) // expected-error {{noncopyable 'x' cannot be consumed when captured by a closure}} - consumeVal(x) // expected-error {{noncopyable 'x' cannot be consumed when captured by a closure}} - borrowConsumeVal(x, x) // expected-error {{noncopyable 'x' cannot be consumed when captured by a closure}} + consumeVal(x) // expected-error {{noncopyable 'x' cannot be consumed when captured by an escaping closure}} + consumeVal(x) // expected-error {{noncopyable 'x' cannot be consumed when captured by an escaping closure}} + borrowConsumeVal(x, x) // expected-error {{noncopyable 'x' cannot be consumed when captured by an escaping closure}} } f() } @@ -575,9 +575,9 @@ func testConsumingEscapeClosureCaptureLet(_ f: consuming @escaping () -> ()) { let x = SingleElt() f = { borrowVal(x) - consumeVal(x) // expected-error {{noncopyable 'x' cannot be consumed when captured by a closure}} - consumeVal(x) // expected-error {{noncopyable 'x' cannot be consumed when captured by a closure}} - borrowConsumeVal(x, x) // expected-error {{noncopyable 'x' cannot be consumed when captured by a closure}} + consumeVal(x) // expected-error {{noncopyable 'x' cannot be consumed when captured by an escaping closure}} + consumeVal(x) // expected-error {{noncopyable 'x' cannot be consumed when captured by an escaping closure}} + borrowConsumeVal(x, x) // expected-error {{noncopyable 'x' cannot be consumed when captured by an escaping closure}} } f() } @@ -887,9 +887,9 @@ var globalClosureCaptureConsuming: () -> () = {} func testGlobalClosureCaptureConsuming(_ x: consuming SingleElt) { globalClosureCaptureConsuming = { borrowVal(x) - consumeVal(x) // expected-error {{noncopyable 'x' cannot be consumed when captured by a closure}} - consumeVal(x) // expected-error {{noncopyable 'x' cannot be consumed when captured by a closure}} - borrowConsumeVal(x, x) // expected-error {{noncopyable 'x' cannot be consumed when captured by a closure}} + consumeVal(x) // expected-error {{noncopyable 'x' cannot be consumed when captured by an escaping closure}} + consumeVal(x) // expected-error {{noncopyable 'x' cannot be consumed when captured by an escaping closure}} + borrowConsumeVal(x, x) // expected-error {{noncopyable 'x' cannot be consumed when captured by an escaping closure}} // expected-error @-1:29 {{overlapping accesses, but deinitialization requires exclusive access}} // expected-note @-2:26 {{conflicting access is here}} } @@ -963,9 +963,9 @@ func testLocalLetClosureCaptureConsuming(_ x: consuming SingleElt) { func testLocalLetClosureCaptureConsuming2(_ x: consuming SingleElt) -> (() -> ()) { let f = { borrowVal(x) - consumeVal(x) // expected-error {{noncopyable 'x' cannot be consumed when captured by a closure}} - consumeVal(x) // expected-error {{noncopyable 'x' cannot be consumed when captured by a closure}} - borrowConsumeVal(x, x) // expected-error {{noncopyable 'x' cannot be consumed when captured by a closure}} + consumeVal(x) // expected-error {{noncopyable 'x' cannot be consumed when captured by an escaping closure}} + consumeVal(x) // expected-error {{noncopyable 'x' cannot be consumed when captured by an escaping closure}} + borrowConsumeVal(x, x) // expected-error {{noncopyable 'x' cannot be consumed when captured by an escaping closure}} // expected-error @-1 {{overlapping accesses, but deinitialization requires exclusive access}} // expected-note @-2 {{conflicting access is here}} } @@ -1019,9 +1019,9 @@ func testLocalLetClosureCaptureConsuming2(_ x: consuming SingleElt) -> (() -> () func testLocalVarClosureCaptureConsuming(_ x: consuming SingleElt) { var f = { borrowVal(x) - consumeVal(x) // expected-error {{noncopyable 'x' cannot be consumed when captured by a closure}} - consumeVal(x) // expected-error {{noncopyable 'x' cannot be consumed when captured by a closure}} - borrowConsumeVal(x, x) // expected-error {{noncopyable 'x' cannot be consumed when captured by a closure}} + consumeVal(x) // expected-error {{noncopyable 'x' cannot be consumed when captured by an escaping closure}} + consumeVal(x) // expected-error {{noncopyable 'x' cannot be consumed when captured by an escaping closure}} + borrowConsumeVal(x, x) // expected-error {{noncopyable 'x' cannot be consumed when captured by an escaping closure}} // expected-error @-1 {{overlapping accesses, but deinitialization requires exclusive access}} // expected-note @-2 {{conflicting access is here}} } @@ -1087,9 +1087,9 @@ func testLocalVarClosureCaptureConsuming(_ x: consuming SingleElt) { func testConsumingEscapeClosureCaptureConsuming(_ f: consuming @escaping () -> (), _ x: consuming SingleElt) { f = { borrowVal(x) - consumeVal(x) // expected-error {{noncopyable 'x' cannot be consumed when captured by a closure}} - consumeVal(x) // expected-error {{noncopyable 'x' cannot be consumed when captured by a closure}} - borrowConsumeVal(x, x) // expected-error {{noncopyable 'x' cannot be consumed when captured by a closure}} + consumeVal(x) // expected-error {{noncopyable 'x' cannot be consumed when captured by an escaping closure}} + consumeVal(x) // expected-error {{noncopyable 'x' cannot be consumed when captured by an escaping closure}} + borrowConsumeVal(x, x) // expected-error {{noncopyable 'x' cannot be consumed when captured by an escaping closure}} // expected-error @-1 {{overlapping accesses, but deinitialization requires exclusive access}} // expected-note @-2 {{conflicting access is here}} } @@ -1139,9 +1139,9 @@ var globalClosureCaptureOwned: () -> () = {} func testGlobalClosureCaptureOwned(_ x: __owned SingleElt) { globalClosureCaptureOwned = { borrowVal(x) - consumeVal(x) // expected-error {{noncopyable 'x' cannot be consumed when captured by a closure}} - consumeVal(x) // expected-error {{noncopyable 'x' cannot be consumed when captured by a closure}} - borrowConsumeVal(x, x) // expected-error {{noncopyable 'x' cannot be consumed when captured by a closure}} + consumeVal(x) // expected-error {{noncopyable 'x' cannot be consumed when captured by an escaping closure}} + consumeVal(x) // expected-error {{noncopyable 'x' cannot be consumed when captured by an escaping closure}} + borrowConsumeVal(x, x) // expected-error {{noncopyable 'x' cannot be consumed when captured by an escaping closure}} } globalClosureCaptureOwned() } @@ -1182,9 +1182,9 @@ func testGlobalClosureCaptureOwned(_ x: __owned SingleElt) { // CHECK: apply {{%.*}}([[LOADED_READ]], [[LOADED_TAKE]]) // CHECK: } // end sil function '$s16moveonly_closure31testLocalLetClosureCaptureOwnedyyAA9SingleEltVnFyycfU_' func testLocalLetClosureCaptureOwned(_ x: __owned SingleElt) { - // expected-error @-1 {{noncopyable 'x' cannot be consumed when captured by a closure}} - // expected-error @-2 {{noncopyable 'x' cannot be consumed when captured by a closure}} - // expected-error @-3 {{noncopyable 'x' cannot be consumed when captured by a closure}} + // expected-error @-1 {{noncopyable 'x' cannot be consumed when captured by an escaping closure}} + // expected-error @-2 {{noncopyable 'x' cannot be consumed when captured by an escaping closure}} + // expected-error @-3 {{noncopyable 'x' cannot be consumed when captured by an escaping closure}} let f = { borrowVal(x) consumeVal(x) // expected-note {{consumed here}} @@ -1229,9 +1229,9 @@ func testLocalLetClosureCaptureOwned(_ x: __owned SingleElt) { func testLocalVarClosureCaptureOwned(_ x: __owned SingleElt) { var f = { borrowVal(x) - consumeVal(x) // expected-error {{noncopyable 'x' cannot be consumed when captured by a closure}} - consumeVal(x) // expected-error {{noncopyable 'x' cannot be consumed when captured by a closure}} - borrowConsumeVal(x, x) // expected-error {{noncopyable 'x' cannot be consumed when captured by a closure}} + consumeVal(x) // expected-error {{noncopyable 'x' cannot be consumed when captured by an escaping closure}} + consumeVal(x) // expected-error {{noncopyable 'x' cannot be consumed when captured by an escaping closure}} + borrowConsumeVal(x, x) // expected-error {{noncopyable 'x' cannot be consumed when captured by an escaping closure}} } f = {} f() @@ -1276,9 +1276,9 @@ func testLocalVarClosureCaptureOwned(_ x: __owned SingleElt) { func testInOutVarClosureCaptureOwned(_ f: inout () -> (), _ x: __owned SingleElt) { f = { borrowVal(x) - consumeVal(x) // expected-error {{noncopyable 'x' cannot be consumed when captured by a closure}} - consumeVal(x) // expected-error {{noncopyable 'x' cannot be consumed when captured by a closure}} - borrowConsumeVal(x, x) // expected-error {{noncopyable 'x' cannot be consumed when captured by a closure}} + consumeVal(x) // expected-error {{noncopyable 'x' cannot be consumed when captured by an escaping closure}} + consumeVal(x) // expected-error {{noncopyable 'x' cannot be consumed when captured by an escaping closure}} + borrowConsumeVal(x, x) // expected-error {{noncopyable 'x' cannot be consumed when captured by an escaping closure}} } f() } @@ -1332,9 +1332,9 @@ func testConsumingEscapeClosureCaptureOwned(_ f: consuming @escaping () -> (), _ x: __owned SingleElt) { f = { borrowVal(x) - consumeVal(x) // expected-error {{noncopyable 'x' cannot be consumed when captured by a closure}} - consumeVal(x) // expected-error {{noncopyable 'x' cannot be consumed when captured by a closure}} - borrowConsumeVal(x, x) // expected-error {{noncopyable 'x' cannot be consumed when captured by a closure}} + consumeVal(x) // expected-error {{noncopyable 'x' cannot be consumed when captured by an escaping closure}} + consumeVal(x) // expected-error {{noncopyable 'x' cannot be consumed when captured by an escaping closure}} + borrowConsumeVal(x, x) // expected-error {{noncopyable 'x' cannot be consumed when captured by an escaping closure}} } f() } @@ -1373,7 +1373,7 @@ func closureCoroutineAssignmentLetConsumingArgument(_ e: __owned Empty) { func closureCoroutineAssignmentVarConsumingArgument(_ e: consuming Empty) { let f: () -> () = { - _ = e // expected-error {{noncopyable 'e' cannot be consumed when captured by a closure}} + _ = e // expected-error {{noncopyable 'e' cannot be consumed when captured by an escaping closure}} } var c = ClosureHolder() c.fCoroutine = f @@ -1392,7 +1392,7 @@ func closureCoroutineAssignmentVarBinding() { var e = Empty() e = Empty() let f: () -> () = { - _ = e // expected-error {{noncopyable 'e' cannot be consumed when captured by a closure}} + _ = e // expected-error {{noncopyable 'e' cannot be consumed when captured by an escaping closure}} } var c = ClosureHolder() c.fCoroutine = f diff --git a/test/SILOptimizer/definite_init_moveonly_controlflowdep_init.sil b/test/SILOptimizer/definite_init_moveonly_controlflowdep_init.sil index f8030b7a933c7..fad9172ba0eec 100644 --- a/test/SILOptimizer/definite_init_moveonly_controlflowdep_init.sil +++ b/test/SILOptimizer/definite_init_moveonly_controlflowdep_init.sil @@ -119,7 +119,7 @@ bb3: %23 = apply %22(%21) : $@convention(thin) (@guaranteed S) -> () destroy_value %21 : $S %25 = mark_must_check [assignable_but_not_consumable] %3 : $*S - // expected-error @-1 {{noncopyable 's' cannot be consumed when captured by a closure}} + // expected-error @-1 {{noncopyable 's' cannot be consumed when captured by an escaping closure}} %26 = load [take] %25 : $*S %27 = function_ref @consumeVal : $@convention(thin) (@owned S) -> () %28 = apply %27(%26) : $@convention(thin) (@owned S) -> () diff --git a/test/SILOptimizer/moveonly_addresschecker_diagnostics.sil b/test/SILOptimizer/moveonly_addresschecker_diagnostics.sil index e9fd3072470aa..d8ab032f1d14e 100644 --- a/test/SILOptimizer/moveonly_addresschecker_diagnostics.sil +++ b/test/SILOptimizer/moveonly_addresschecker_diagnostics.sil @@ -359,7 +359,7 @@ bb0(%0 : @closureCapture @guaranteed $<τ_0_0 where τ_0_0 : P> { var AddressOnl end_access %12 : $*AddressOnlyGeneric %17 = begin_access [deinit] [dynamic] %1 : $*AddressOnlyGeneric %18 = mark_must_check [assignable_but_not_consumable] %17 : $*AddressOnlyGeneric - // expected-error @-1 {{noncopyable 'x' cannot be consumed when captured by a closure}} + // expected-error @-1 {{noncopyable 'x' cannot be consumed when captured by an escaping closure}} %19 = function_ref @addressOnlyGenericConsume : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@in AddressOnlyGeneric<τ_0_0>) -> () %20 = apply %19(%18) : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@in AddressOnlyGeneric<τ_0_0>) -> () end_access %17 : $*AddressOnlyGeneric @@ -528,4 +528,4 @@ bb0(%0 : @owned $NonTrivialStruct): dealloc_stack %1 : $*NonTrivialStruct %9999 = tuple() return %9999 : $() -} \ No newline at end of file +} diff --git a/test/SILOptimizer/moveonly_addresschecker_diagnostics.swift b/test/SILOptimizer/moveonly_addresschecker_diagnostics.swift index b8c06c599dcfc..ca449ab9416ab 100644 --- a/test/SILOptimizer/moveonly_addresschecker_diagnostics.swift +++ b/test/SILOptimizer/moveonly_addresschecker_diagnostics.swift @@ -3143,11 +3143,11 @@ func closureLetStoreClosureInVariableIsEscape() { let f = { borrowVal(s) - consumeVal(s) // expected-error {{noncopyable 's' cannot be consumed when captured by a closure}} + consumeVal(s) // expected-error {{noncopyable 's' cannot be consumed when captured by an escaping closure}} } let c = StoreClosure(f: f) _ = c - consumeVal(s) // expected-error {{noncopyable 's' cannot be consumed when captured by a closure}} + consumeVal(s) // expected-error {{noncopyable 's' cannot be consumed when captured by an escaping closure}} } ///////////////////////////// @@ -3202,8 +3202,8 @@ public func closureVarCaptureClassUseAfterConsume() { var f = {} f = { borrowVal(x2) - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} } f() } @@ -3214,7 +3214,7 @@ public func closureVarCaptureClassUseAfterConsume2() { var f = {} f = { borrowVal(x2) - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} } f() } @@ -3225,12 +3225,12 @@ public func closureVarCaptureClassUseAfterConsumeError() { var f = {} f = { borrowVal(x2) - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} } f() - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} - let x3 = x2 // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} + let x3 = x2 // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} x2 = Klass() let _ = x3 } @@ -3458,7 +3458,7 @@ public func closureVarAndDeferCaptureClassUseAfterConsume2(_ x: borrowing Klass) x2 = x // expected-note {{consumed here}} var f = {} f = { - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} defer { borrowVal(x2) consumeVal(x2) // expected-note {{consumed here}} @@ -3479,7 +3479,7 @@ public func closureVarAndDeferCaptureClassUseAfterConsume3(_ x: borrowing Klass) // expected-note @-1 {{consumed here}} var f = {} f = { - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} defer { borrowVal(x2) consumeVal(x2) // expected-note {{consumed here}} @@ -3489,11 +3489,11 @@ public func closureVarAndDeferCaptureClassUseAfterConsume3(_ x: borrowing Klass) print("foo") } f() - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} } public func closureVarAndDeferCaptureClassArgUseAfterConsume(_ x2: borrowing Klass) { - // expected-error @-1 {{noncopyable 'x2' cannot be consumed when captured by a closure}} + // expected-error @-1 {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} // expected-error @-2 {{'x2' cannot be captured by an escaping closure since it is a borrowed parameter}} var f = {} f = {// expected-note {{closure capturing 'x2' here}} @@ -3508,7 +3508,7 @@ public func closureVarAndDeferCaptureClassArgUseAfterConsume(_ x2: borrowing Kla } public func closureVarAndDeferCaptureClassOwnedArgUseAfterConsume(_ x2: __owned Klass) { - // expected-error @-1 {{noncopyable 'x2' cannot be consumed when captured by a closure}} + // expected-error @-1 {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} var f = {} f = { defer { @@ -3539,7 +3539,7 @@ public func closureVarAndDeferCaptureClassOwnedArgUseAfterConsume2(_ x2: consumi // TODO: MG public func closureVarAndDeferCaptureClassOwnedArgUseAfterConsume3(_ x2: __owned Klass) { - // expected-error @-1 {{noncopyable 'x2' cannot be consumed when captured by a closure}} + // expected-error @-1 {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} var f = {} f = { defer { @@ -3550,7 +3550,7 @@ public func closureVarAndDeferCaptureClassOwnedArgUseAfterConsume3(_ x2: __owned print("foo") } f() - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} } public func closureVarAndDeferCaptureClassOwnedArgUseAfterConsume4(_ x2: consuming Klass) { @@ -3567,7 +3567,7 @@ public func closureVarAndDeferCaptureClassOwnedArgUseAfterConsume4(_ x2: consumi print("foo") } f() - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} } /////////////////////////////////////////// @@ -3582,11 +3582,11 @@ public func closureVarAndClosureCaptureClassUseAfterConsume(_ x: borrowing Klass var g = {} g = { borrowVal(x2) - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} } g() - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} } f() } @@ -3601,14 +3601,14 @@ public func closureVarAndClosureCaptureClassUseAfterConsume2(_ x: borrowing Klas var g = {} g = { borrowVal(x2) - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} } g() } f() - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} - let x3 = x2 // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} + let x3 = x2 // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} _ = x3 } @@ -3623,19 +3623,19 @@ public func closureVarAndClosureCaptureClassUseAfterConsume3(_ x: borrowing Klas var g = {} g = { borrowVal(x2) - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} } g() } f() - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} - let x3 = x2 // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} + let x3 = x2 // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} _ = x3 } public func closureVarAndClosureCaptureClassArgUseAfterConsume(_ x2: borrowing Klass) { - // expected-error @-1 {{noncopyable 'x2' cannot be consumed when captured by a closure}} + // expected-error @-1 {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} // expected-error @-2 {{'x2' cannot be captured by an escaping closure since it is a borrowed parameter}} // expected-error @-3 {{'x2' cannot be captured by an escaping closure since it is a borrowed parameter}} var f = {} @@ -3657,8 +3657,8 @@ public func closureVarAndClosureCaptureClassOwnedArgUseAfterConsume(_ x2: __owne var g = {} g = { borrowVal(x2) - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} } g() } @@ -3671,8 +3671,8 @@ public func closureVarAndClosureCaptureClassOwnedArgUseAfterConsume2(_ x2: consu var g = {} g = { borrowVal(x2) - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} } g() } @@ -3685,13 +3685,13 @@ public func closureVarAndClosureCaptureClassOwnedArgUseAfterConsume3(_ x2: __own var g = {} g = { borrowVal(x2) - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} } g() } f() - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} } public func closureVarAndClosureCaptureClassOwnedArgUseAfterConsume4(_ x2: consuming Klass) { @@ -3700,13 +3700,13 @@ public func closureVarAndClosureCaptureClassOwnedArgUseAfterConsume4(_ x2: consu var g = {} g = { borrowVal(x2) - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} } g() } f() - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} } ///////////////////////////// @@ -4106,14 +4106,14 @@ func inoutCaptureTest() -> (() -> ()) { borrowVal(x) consumeVal(x) - // expected-error @-1 {{noncopyable 'x' cannot be consumed when captured by a closure}} + // expected-error @-1 {{noncopyable 'x' cannot be consumed when captured by an escaping closure}} x = NonTrivialStruct() let g = { x = NonTrivialStruct() useInOut(&x) consumeVal(x) - // expected-error @-1 {{noncopyable 'x' cannot be consumed when captured by a closure}} + // expected-error @-1 {{noncopyable 'x' cannot be consumed when captured by an escaping closure}} } g() @@ -4130,13 +4130,13 @@ func inoutCaptureTestAddressOnlyGeneric(_ t: T.Type) -> (() -> ()) { } borrowVal(x) - consumeVal(x) // expected-error {{noncopyable 'x' cannot be consumed when captured by a closure}} + consumeVal(x) // expected-error {{noncopyable 'x' cannot be consumed when captured by an escaping closure}} x = AddressOnlyGeneric() let g = { x = AddressOnlyGeneric() useInOut(&x) - consumeVal(x) // expected-error {{noncopyable 'x' cannot be consumed when captured by a closure}} + consumeVal(x) // expected-error {{noncopyable 'x' cannot be consumed when captured by an escaping closure}} } g() diff --git a/test/SILOptimizer/moveonly_nonescaping_closures.swift b/test/SILOptimizer/moveonly_nonescaping_closures.swift index 311b16701c7b7..3d37a81ae36cc 100644 --- a/test/SILOptimizer/moveonly_nonescaping_closures.swift +++ b/test/SILOptimizer/moveonly_nonescaping_closures.swift @@ -77,7 +77,7 @@ func c2(x: consuming M) { consume(x) } -func d(x: __owned M) { // expected-error {{noncopyable 'x' cannot be consumed when captured by a closure}} +func d(x: __owned M) { // expected-error {{noncopyable 'x' cannot be consumed when captured by an escaping closure}} clodger({ consume(x) }) // expected-note @-1 {{consumed here}} } diff --git a/test/SILOptimizer/moveonly_objectchecker_diagnostics.swift b/test/SILOptimizer/moveonly_objectchecker_diagnostics.swift index 08a73a77e080f..9146484efc167 100644 --- a/test/SILOptimizer/moveonly_objectchecker_diagnostics.swift +++ b/test/SILOptimizer/moveonly_objectchecker_diagnostics.swift @@ -2732,7 +2732,7 @@ public func enumPatternMatchSwitch2WhereClause2OwnedArg2(_ x2: consuming EnumTy) public func closureLetClassUseAfterConsume1(_ x: borrowing Klass) { // expected-error @-1 {{'x' cannot be captured by an escaping closure since it is a borrowed parameter}} - // expected-error @-2 {{noncopyable 'x' cannot be consumed when captured by a closure}} + // expected-error @-2 {{noncopyable 'x' cannot be consumed when captured by an escaping closure}} let f = { // expected-note {{closure capturing 'x' here}} let x2 = x // expected-error {{'x2' consumed more than once}} // expected-note @-1 {{consumed here}} @@ -2764,8 +2764,8 @@ public func closureLetClassUseAfterConsumeArg(_ argX: borrowing Klass) { } public func closureLetCaptureClassUseAfterConsume(_ x: consuming Klass) { - let x2 = x // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} - // expected-error @-1 {{noncopyable 'x2' cannot be consumed when captured by a closure}} + let x2 = x // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} + // expected-error @-1 {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} let f = { borrowVal(x2) consumeVal(x2) // expected-note {{consumed here}} @@ -2816,8 +2816,8 @@ public func closureLetCaptureClassUseAfterConsume3(_ x2: inout Klass) { public func closureLetCaptureClassUseAfterConsumeError(_ x: borrowing Klass) { // expected-error {{'x' is borrowed and cannot be consumed}} let x2 = x // expected-note {{consumed here}} - // expected-error @-1 {{noncopyable 'x2' cannot be consumed when captured by a closure}} - // expected-error @-2 {{noncopyable 'x2' cannot be consumed when captured by a closure}} + // expected-error @-1 {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} + // expected-error @-2 {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} let f = { borrowVal(x2) consumeVal(x2) // expected-note {{consumed here}} @@ -2829,7 +2829,7 @@ public func closureLetCaptureClassUseAfterConsumeError(_ x: borrowing Klass) { / } public func closureLetCaptureClassArgUseAfterConsume(_ x2: borrowing Klass) { - // expected-error @-1 {{noncopyable 'x2' cannot be consumed when captured by a closure}} + // expected-error @-1 {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} // expected-error @-2 {{'x2' cannot be captured by an escaping closure since it is a borrowed parameter}} let f = { // expected-note {{closure capturing 'x2' here}} borrowVal(x2) @@ -2840,8 +2840,8 @@ public func closureLetCaptureClassArgUseAfterConsume(_ x2: borrowing Klass) { } public func closureLetCaptureClassOwnedArgUseAfterConsume(_ x2: __owned Klass) { - // expected-error @-1 {{noncopyable 'x2' cannot be consumed when captured by a closure}} - // expected-error @-2 {{noncopyable 'x2' cannot be consumed when captured by a closure}} + // expected-error @-1 {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} + // expected-error @-2 {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} let f = { borrowVal(x2) consumeVal(x2) // expected-note {{consumed here}} @@ -2863,8 +2863,8 @@ public func closureLetCaptureClassOwnedArgUseAfterConsume2(_ x2: consuming Klass } public func closureLetCaptureClassOwnedArgUseAfterConsume3(_ x2: __owned Klass) { - // expected-error @-1 {{noncopyable 'x2' cannot be consumed when captured by a closure}} - // expected-error @-2 {{noncopyable 'x2' cannot be consumed when captured by a closure}} + // expected-error @-1 {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} + // expected-error @-2 {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} let f = { borrowVal(x2) consumeVal(x2) // expected-note {{consumed here}} @@ -2898,7 +2898,7 @@ public func closureLetCaptureClassOwnedArgUseAfterConsume4(_ x2: consuming Klass public func closureVarClassUseAfterConsume1(_ x: borrowing Klass) { // expected-error @-1 {{'x' cannot be captured by an escaping closure since it is a borrowed parameter}} - // expected-error @-2 {{noncopyable 'x' cannot be consumed when captured by a closure}} + // expected-error @-2 {{noncopyable 'x' cannot be consumed when captured by an escaping closure}} var f = {} f = { // expected-note {{closure capturing 'x' here}} let x2 = x // expected-error {{'x2' consumed more than once}} @@ -2937,8 +2937,8 @@ public func closureVarCaptureClassUseAfterConsume(_ x: borrowing Klass) { // exp var f = {} f = { borrowVal(x2) - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} } f() } @@ -2950,8 +2950,8 @@ public func closureVarCaptureClassUseAfterConsume1(_ x: borrowing Klass) { // ex var f = {} f = { borrowVal(x2) - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} } f() } @@ -2997,16 +2997,16 @@ public func closureVarCaptureClassUseAfterConsumeError(_ x: borrowing Klass) { / var f = {} f = { borrowVal(x2) - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} } f() - let x3 = x2 // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} + let x3 = x2 // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} let _ = x3 } public func closureVarCaptureClassArgUseAfterConsume(_ x2: borrowing Klass) { - // expected-error @-1 {{noncopyable 'x2' cannot be consumed when captured by a closure}} + // expected-error @-1 {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} // expected-error @-2 {{'x2' cannot be captured by an escaping closure since it is a borrowed parameter}} var f = {} f = { // expected-note {{closure capturing 'x2' here}} @@ -3021,8 +3021,8 @@ public func closureVarCaptureClassOwnedArgUseAfterConsume(_ x2: __owned Klass) { var f = {} f = { borrowVal(x2) - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} } f() } @@ -3031,8 +3031,8 @@ public func closureVarCaptureClassOwnedArgUseAfterConsume2(_ x2: consuming Klass var f = {} f = { borrowVal(x2) - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} } f() } @@ -3041,11 +3041,11 @@ public func closureVarCaptureClassOwnedArgUseAfterConsume3(_ x2: __owned Klass) var f = {} f = { borrowVal(x2) - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} } f() - let x3 = x2 // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} + let x3 = x2 // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} let _ = x3 } @@ -3053,12 +3053,12 @@ public func closureVarCaptureClassOwnedArgUseAfterConsume4(_ x2: consuming Klass var f = {} f = { borrowVal(x2) - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} } f() - let x3 = x2 // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} + let x3 = x2 // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} x2 = Klass() let _ = x3 } @@ -3069,7 +3069,7 @@ public func closureVarCaptureClassOwnedArgUseAfterConsume4(_ x2: consuming Klass public func deferCaptureClassUseAfterConsume(_ x: borrowing Klass) { // expected-error {{'x' is borrowed and cannot be consumed}} let x2 = x // expected-note {{consumed here}} - // expected-error @-1 {{noncopyable 'x2' cannot be consumed when captured by a closure}} + // expected-error @-1 {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} defer { borrowVal(x2) // TODO: Defer can only run once, so this error shouldn't occur. @@ -3082,7 +3082,7 @@ public func deferCaptureClassUseAfterConsume(_ x: borrowing Klass) { // expected public func deferCaptureClassUseAfterConsume2(_ x: borrowing Klass) { // expected-error {{'x' is borrowed and cannot be consumed}} let x2 = x // expected-note @-1 {{consumed here}} - // expected-error @-2 {{noncopyable 'x2' cannot be consumed when captured by a closure}} + // expected-error @-2 {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} // expected-error @-3 {{'x2' used after consume}} defer { // expected-note {{used here}} borrowVal(x2) @@ -3094,7 +3094,7 @@ public func deferCaptureClassUseAfterConsume2(_ x: borrowing Klass) { // expecte } public func deferCaptureClassArgUseAfterConsume(_ x2: borrowing Klass) { - // expected-error @-1 {{noncopyable 'x2' cannot be consumed when captured by a closure}} + // expected-error @-1 {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} borrowVal(x2) defer { borrowVal(x2) @@ -3105,7 +3105,7 @@ public func deferCaptureClassArgUseAfterConsume(_ x2: borrowing Klass) { } public func deferCaptureClassOwnedArgUseAfterConsume(_ x2: __owned Klass) { - // expected-error @-1 {{noncopyable 'x2' cannot be consumed when captured by a closure}} + // expected-error @-1 {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} defer { borrowVal(x2) consumeVal(x2) // expected-note {{consumed here}} @@ -3127,7 +3127,7 @@ public func deferCaptureClassOwnedArgUseAfterConsume2(_ x2: consuming Klass) { } public func deferCaptureClassOwnedArgUseAfterConsume3(_ x2: __owned Klass) { - // expected-error @-1 {{noncopyable 'x2' cannot be consumed when captured by a closure}} + // expected-error @-1 {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} // expected-error @-2 {{'x2' used after consume}} defer { // expected-note {{used here}} borrowVal(x2) @@ -3156,7 +3156,7 @@ public func deferCaptureClassOwnedArgUseAfterConsume4(_ x2: consuming Klass) { public func closureLetAndDeferCaptureClassUseAfterConsume(_ x: borrowing Klass) { // expected-error {{'x' is borrowed and cannot be consumed}} let x2 = x // expected-note {{consumed here}} - // expected-error @-1 {{noncopyable 'x2' cannot be consumed when captured by a closure}} + // expected-error @-1 {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} let f = { defer { borrowVal(x2) @@ -3170,9 +3170,9 @@ public func closureLetAndDeferCaptureClassUseAfterConsume(_ x: borrowing Klass) public func closureLetAndDeferCaptureClassUseAfterConsume2(_ x: borrowing Klass) { // expected-error {{'x' is borrowed and cannot be consumed}} // TODO: This is wrong - let x2 = x // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} + let x2 = x // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} // expected-note @-1 {{consumed here}} - // expected-error @-2 {{noncopyable 'x2' cannot be consumed when captured by a closure}} + // expected-error @-2 {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} let f = { consumeVal(x2) // expected-note {{consumed here}} defer { @@ -3189,8 +3189,8 @@ public func closureLetAndDeferCaptureClassUseAfterConsume2(_ x: borrowing Klass) public func closureLetAndDeferCaptureClassUseAfterConsume3(_ x: borrowing Klass) { // expected-error {{'x' is borrowed and cannot be consumed}} let x2 = x // expected-note @-1 {{consumed here}} - // expected-error @-2 {{noncopyable 'x2' cannot be consumed when captured by a closure}} - // expected-error @-3 {{noncopyable 'x2' cannot be consumed when captured by a closure}} + // expected-error @-2 {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} + // expected-error @-3 {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} let f = { consumeVal(x2) // expected-note {{consumed here}} defer { @@ -3205,7 +3205,7 @@ public func closureLetAndDeferCaptureClassUseAfterConsume3(_ x: borrowing Klass) } public func closureLetAndDeferCaptureClassArgUseAfterConsume(_ x2: borrowing Klass) { - // expected-error @-1 {{noncopyable 'x2' cannot be consumed when captured by a closure}} + // expected-error @-1 {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} // expected-error @-2 {{'x2' cannot be captured by an escaping closure since it is a borrowed parameter}} let f = { // expected-note {{closure capturing 'x2' here}} defer { @@ -3219,7 +3219,7 @@ public func closureLetAndDeferCaptureClassArgUseAfterConsume(_ x2: borrowing Kla } public func closureLetAndDeferCaptureClassOwnedArgUseAfterConsume(_ x2: __owned Klass) { - // expected-error @-1 {{noncopyable 'x2' cannot be consumed when captured by a closure}} + // expected-error @-1 {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} let f = { defer { borrowVal(x2) @@ -3248,7 +3248,7 @@ public func closureLetAndDeferCaptureClassOwnedArgUseAfterConsume2(_ x2: consumi // TODO: MG public func closureLetAndDeferCaptureClassOwnedArgUseAfterConsume3(_ x2: __owned Klass) { - // expected-error @-1 {{noncopyable 'x2' cannot be consumed when captured by a closure}} + // expected-error @-1 {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} let f = { defer { borrowVal(x2) @@ -3283,8 +3283,8 @@ public func closureLetAndDeferCaptureClassOwnedArgUseAfterConsume4(_ x2: consumi public func closureLetAndClosureCaptureClassUseAfterConsume(_ x: borrowing Klass) { // expected-error {{'x' is borrowed and cannot be consumed}} let x2 = x // expected-note {{consumed here}} - // expected-error @-1 {{noncopyable 'x2' cannot be consumed when captured by a closure}} - // expected-error @-2 {{noncopyable 'x2' cannot be consumed when captured by a closure}} + // expected-error @-1 {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} + // expected-error @-2 {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} let f = { let g = { borrowVal(x2) @@ -3299,8 +3299,8 @@ public func closureLetAndClosureCaptureClassUseAfterConsume(_ x: borrowing Klass public func closureLetAndClosureCaptureClassUseAfterConsume2(_ x: borrowing Klass) { // expected-error {{'x' is borrowed and cannot be consumed}} let x2 = x // expected-note @-1 {{consumed here}} - // expected-error @-2 {{noncopyable 'x2' cannot be consumed when captured by a closure}} - // expected-error @-3 {{noncopyable 'x2' cannot be consumed when captured by a closure}} + // expected-error @-2 {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} + // expected-error @-3 {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} // expected-error @-4 {{'x2' consumed more than once}} let f = { @@ -3342,7 +3342,7 @@ public func closureLetAndClosureCaptureClassUseAfterConsume3(_ x: borrowing Klas } public func closureLetAndClosureCaptureClassArgUseAfterConsume(_ x2: borrowing Klass) { - // expected-error @-1 {{noncopyable 'x2' cannot be consumed when captured by a closure}} + // expected-error @-1 {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} // expected-error @-2 {{'x2' cannot be captured by an escaping closure since it is a borrowed parameter}} // expected-error @-3 {{'x2' cannot be captured by an escaping closure since it is a borrowed parameter}} let f = { // expected-note {{closure capturing 'x2' here}} @@ -3357,8 +3357,8 @@ public func closureLetAndClosureCaptureClassArgUseAfterConsume(_ x2: borrowing K } public func closureLetAndClosureCaptureClassOwnedArgUseAfterConsume(_ x2: __owned Klass) { - // expected-error @-1 {{noncopyable 'x2' cannot be consumed when captured by a closure}} - // expected-error @-2 {{noncopyable 'x2' cannot be consumed when captured by a closure}} + // expected-error @-1 {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} + // expected-error @-2 {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} let f = { let g = { borrowVal(x2) @@ -3386,8 +3386,8 @@ public func closureLetAndClosureCaptureClassOwnedArgUseAfterConsume2(_ x2: consu } public func closureLetAndClosureCaptureClassOwnedArgUseAfterConsume3(_ x2: __owned Klass) { - // expected-error @-1 {{noncopyable 'x2' cannot be consumed when captured by a closure}} - // expected-error @-2 {{noncopyable 'x2' cannot be consumed when captured by a closure}} + // expected-error @-1 {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} + // expected-error @-2 {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} let f = { let g = { borrowVal(x2) @@ -3440,7 +3440,7 @@ public func closureLetAndClosureCaptureClassOwnedArgUseAfterConsume5(_ x2: consu public func closureVarAndDeferCaptureClassUseAfterConsume(_ x: borrowing Klass) { // expected-error {{'x' is borrowed and cannot be consumed}} let x2 = x // expected-note {{consumed here}} - // expected-error @-1 {{noncopyable 'x2' cannot be consumed when captured by a closure}} + // expected-error @-1 {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} var f = {} f = { defer { @@ -3454,11 +3454,11 @@ public func closureVarAndDeferCaptureClassUseAfterConsume(_ x: borrowing Klass) } public func closureVarAndDeferCaptureClassUseAfterConsume2(_ x: borrowing Klass) { // expected-error {{'x' is borrowed and cannot be consumed}} - let x2 = x // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} + let x2 = x // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} // expected-note @-1 {{consumed here}} var f = {} f = { - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} defer { borrowVal(x2) consumeVal(x2) // expected-note {{consumed here}} @@ -3473,10 +3473,10 @@ public func closureVarAndDeferCaptureClassUseAfterConsume2(_ x: borrowing Klass) public func closureVarAndDeferCaptureClassUseAfterConsume3(_ x: borrowing Klass) { // expected-error {{'x' is borrowed and cannot be consumed}} let x2 = x // expected-note @-1 {{consumed here}} - // expected-error @-2 {{noncopyable 'x2' cannot be consumed when captured by a closure}} + // expected-error @-2 {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} var f = {} f = { - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} defer { borrowVal(x2) consumeVal(x2) // expected-note {{consumed here}} @@ -3485,11 +3485,11 @@ public func closureVarAndDeferCaptureClassUseAfterConsume3(_ x: borrowing Klass) print("foo") } f() - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} } public func closureVarAndDeferCaptureClassArgUseAfterConsume(_ x2: borrowing Klass) { - // expected-error @-1 {{noncopyable 'x2' cannot be consumed when captured by a closure}} + // expected-error @-1 {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} // expected-error @-2 {{'x2' cannot be captured by an escaping closure since it is a borrowed parameter}} var f = {} f = {// expected-note {{closure capturing 'x2' here}} @@ -3504,7 +3504,7 @@ public func closureVarAndDeferCaptureClassArgUseAfterConsume(_ x2: borrowing Kla } public func closureVarAndDeferCaptureClassOwnedArgUseAfterConsume(_ x2: __owned Klass) { - // expected-error @-1 {{noncopyable 'x2' cannot be consumed when captured by a closure}} + // expected-error @-1 {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} var f = {} f = { defer { @@ -3535,7 +3535,7 @@ public func closureVarAndDeferCaptureClassOwnedArgUseAfterConsume2(_ x2: consumi // TODO: MG public func closureVarAndDeferCaptureClassOwnedArgUseAfterConsume3(_ x2: __owned Klass) { - // expected-error @-1 {{noncopyable 'x2' cannot be consumed when captured by a closure}} + // expected-error @-1 {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} var f = {} f = { defer { @@ -3546,7 +3546,7 @@ public func closureVarAndDeferCaptureClassOwnedArgUseAfterConsume3(_ x2: __owned print("foo") } f() - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} } public func closureVarAndDeferCaptureClassOwnedArgUseAfterConsume4(_ x2: consuming Klass) { @@ -3563,7 +3563,7 @@ public func closureVarAndDeferCaptureClassOwnedArgUseAfterConsume4(_ x2: consumi print("foo") } f() - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} } /////////////////////////////////////////// @@ -3577,11 +3577,11 @@ public func closureVarAndClosureCaptureClassUseAfterConsume(_ x: borrowing Klass var g = {} g = { borrowVal(x2) - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} } g() - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} } f() } @@ -3595,14 +3595,14 @@ public func closureVarAndClosureCaptureClassUseAfterConsume2(_ x: borrowing Klas var g = {} g = { borrowVal(x2) - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} } g() } f() - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} - let x3 = x2 // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} + let x3 = x2 // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} _ = x3 } @@ -3617,19 +3617,19 @@ public func closureVarAndClosureCaptureClassUseAfterConsume3(_ x: borrowing Klas var g = {} g = { borrowVal(x2) - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} } g() } f() - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} - let x3 = x2 // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} + let x3 = x2 // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} _ = x3 } public func closureVarAndClosureCaptureClassArgUseAfterConsume(_ x2: borrowing Klass) { - // expected-error @-1 {{noncopyable 'x2' cannot be consumed when captured by a closure}} + // expected-error @-1 {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} // expected-error @-2 {{'x2' cannot be captured by an escaping closure since it is a borrowed parameter}} // expected-error @-3 {{'x2' cannot be captured by an escaping closure since it is a borrowed parameter}} var f = {} @@ -3651,8 +3651,8 @@ public func closureVarAndClosureCaptureClassOwnedArgUseAfterConsume(_ x2: __owne var g = {} g = { borrowVal(x2) - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} } g() } @@ -3665,8 +3665,8 @@ public func closureVarAndClosureCaptureClassOwnedArgUseAfterConsume2(_ x2: consu var g = {} g = { borrowVal(x2) - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} } g() } @@ -3679,13 +3679,13 @@ public func closureVarAndClosureCaptureClassOwnedArgUseAfterConsume3(_ x2: __own var g = {} g = { borrowVal(x2) - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} } g() } f() - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} } public func closureVarAndClosureCaptureClassOwnedArgUseAfterConsume4(_ x2: consuming Klass) { @@ -3694,13 +3694,13 @@ public func closureVarAndClosureCaptureClassOwnedArgUseAfterConsume4(_ x2: consu var g = {} g = { borrowVal(x2) - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} } g() } f() - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} } ///////////////////////////////// @@ -3713,11 +3713,11 @@ public func closureVarAndClosureLetCaptureClassUseAfterConsume(_ x: borrowing Kl f = { let g = { borrowVal(x2) - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} } g() - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} } f() } @@ -3730,14 +3730,14 @@ public func closureVarAndClosureLetCaptureClassUseAfterConsume2(_ x: borrowing K f = { let g = { borrowVal(x2) - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} } g() } f() - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} - let x3 = x2 // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} + let x3 = x2 // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} _ = x3 } @@ -3751,19 +3751,19 @@ public func closureVarAndClosureLetCaptureClassUseAfterConsume3(_ x: borrowing K f = { let g = { borrowVal(x2) - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} } g() } f() - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} - let x3 = x2 // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} + let x3 = x2 // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} _ = x3 } public func closureVarAndClosureLetCaptureClassArgUseAfterConsume(_ x2: borrowing Klass) { - // expected-error @-1 {{noncopyable 'x2' cannot be consumed when captured by a closure}} + // expected-error @-1 {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} // expected-error @-2 {{'x2' cannot be captured by an escaping closure since it is a borrowed parameter}} // expected-error @-3 {{'x2' cannot be captured by an escaping closure since it is a borrowed parameter}} var f = {} @@ -3783,8 +3783,8 @@ public func closureVarAndClosureLetCaptureClassOwnedArgUseAfterConsume(_ x2: __o f = { let g = { borrowVal(x2) - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} } g() } @@ -3796,8 +3796,8 @@ public func closureVarAndClosureLetCaptureClassOwnedArgUseAfterConsume2(_ x2: co f = { let g = { borrowVal(x2) - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} } g() } @@ -3809,13 +3809,13 @@ public func closureVarAndClosureLetCaptureClassOwnedArgUseAfterConsume3(_ x2: __ f = { let g = { borrowVal(x2) - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} } g() } f() - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} } public func closureVarAndClosureLetCaptureClassOwnedArgUseAfterConsume4(_ x2: consuming Klass) { @@ -3823,13 +3823,13 @@ public func closureVarAndClosureLetCaptureClassOwnedArgUseAfterConsume4(_ x2: co f = { let g = { borrowVal(x2) - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} } g() } f() - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} } public func closureLetAndClosureVarCaptureClassUseAfterConsume(_ x: borrowing Klass) { // expected-error {{'x' is borrowed and cannot be consumed}} @@ -3838,11 +3838,11 @@ public func closureLetAndClosureVarCaptureClassUseAfterConsume(_ x: borrowing Kl var g = {} g = { borrowVal(x2) - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} } g() - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} } f() } @@ -3856,17 +3856,17 @@ public func closureLetAndClosureVarCaptureClassUseAfterConsume2(_ x: borrowing K var g = {} g = { borrowVal(x2) - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} } g() } h() - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} } f() - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} - let x3 = x2 // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} + let x3 = x2 // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} _ = x3 } @@ -3880,19 +3880,19 @@ public func closureLetAndClosureVarCaptureClassUseAfterConsume3(_ x: borrowing K var g = {} g = { borrowVal(x2) - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} } g() } f() - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} - let x3 = x2 // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} + let x3 = x2 // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} _ = x3 } public func closureLetAndClosureVarCaptureClassArgUseAfterConsume(_ x2: borrowing Klass) { - // expected-error @-1 {{noncopyable 'x2' cannot be consumed when captured by a closure}} + // expected-error @-1 {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} // expected-error @-2 {{'x2' cannot be captured by an escaping closure since it is a borrowed parameter}} // expected-error @-3 {{'x2' cannot be captured by an escaping closure since it is a borrowed parameter}} let f = {// expected-note {{closure capturing 'x2' here}} @@ -3912,8 +3912,8 @@ public func closureLetAndClosureVarCaptureClassOwnedArgUseAfterConsume(_ x2: __o var g = {} g = { borrowVal(x2) - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} } g() } @@ -3925,8 +3925,8 @@ public func closureLetAndClosureVarCaptureClassOwnedArgUseAfterConsume2(_ x2: co var g = {} g = { borrowVal(x2) - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} } g() } @@ -3938,13 +3938,13 @@ public func closureLetAndClosureVarCaptureClassOwnedArgUseAfterConsume3(_ x2: __ var g = {} g = { borrowVal(x2) - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} } g() } f() - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} } public func closureLetAndClosureVarCaptureClassOwnedArgUseAfterConsume4(_ x2: consuming Klass) { @@ -3952,13 +3952,13 @@ public func closureLetAndClosureVarCaptureClassOwnedArgUseAfterConsume4(_ x2: co var g = {} g = { borrowVal(x2) - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} } g() } f() - consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by a closure}} + consumeVal(x2) // expected-error {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} } /////////////////////////////////// diff --git a/test/SILOptimizer/moveonly_trivial_objectchecker_diagnostics.swift b/test/SILOptimizer/moveonly_trivial_objectchecker_diagnostics.swift index 720b5082725c9..239dd82584050 100644 --- a/test/SILOptimizer/moveonly_trivial_objectchecker_diagnostics.swift +++ b/test/SILOptimizer/moveonly_trivial_objectchecker_diagnostics.swift @@ -1727,7 +1727,7 @@ public func enumPatternMatchSwitch2WhereClause2OwnedArg2(_ x2: consuming EnumTy) ///////////////////////////// public func closureClassUseAfterConsume1(_ x: borrowing NonTrivialStruct) { - // expected-error @-1 {{noncopyable 'x' cannot be consumed when captured by a closure}} + // expected-error @-1 {{noncopyable 'x' cannot be consumed when captured by an escaping closure}} // expected-error @-2 {{'x' cannot be captured by an escaping closure since it is a borrowed parameter}} let f = { // expected-note {{closure capturing 'x' here}} let x2 = x // expected-error {{'x2' consumed more than once}} @@ -1762,8 +1762,8 @@ public func closureClassUseAfterConsumeArg(_ argX: borrowing NonTrivialStruct) { public func closureCaptureClassUseAfterConsume(_ x: borrowing NonTrivialStruct) { // expected-error {{'x' is borrowed and cannot be consumed}} let x2 = x // expected-note {{consumed here}} - // expected-error @-1 {{noncopyable 'x2' cannot be consumed when captured by a closure}} - // expected-error @-2 {{noncopyable 'x2' cannot be consumed when captured by a closure}} + // expected-error @-1 {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} + // expected-error @-2 {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} let f = { borrowVal(x2) @@ -1775,8 +1775,8 @@ public func closureCaptureClassUseAfterConsume(_ x: borrowing NonTrivialStruct) public func closureCaptureClassUseAfterConsumeError(_ x: borrowing NonTrivialStruct) { // expected-error {{'x' is borrowed and cannot be consumed}} let x2 = x // expected-note {{consumed here}} - // expected-error @-1 {{noncopyable 'x2' cannot be consumed when captured by a closure}} - // expected-error @-2 {{noncopyable 'x2' cannot be consumed when captured by a closure}} + // expected-error @-1 {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} + // expected-error @-2 {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} let f = { borrowVal(x2) consumeVal(x2) // expected-note {{consumed here}} @@ -1788,7 +1788,7 @@ public func closureCaptureClassUseAfterConsumeError(_ x: borrowing NonTrivialStr } public func closureCaptureClassArgUseAfterConsume(_ x2: borrowing NonTrivialStruct) { - // expected-error @-1 {{noncopyable 'x2' cannot be consumed when captured by a closure}} + // expected-error @-1 {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} // expected-error @-2 {{'x2' cannot be captured by an escaping closure since it is a borrowed parameter}} let f = { // expected-note {{closure capturing 'x2' here}} borrowVal(x2) @@ -1799,8 +1799,8 @@ public func closureCaptureClassArgUseAfterConsume(_ x2: borrowing NonTrivialStru } public func closureCaptureClassOwnedArgUseAfterConsume(_ x2: __owned NonTrivialStruct) { - // expected-error @-1 {{noncopyable 'x2' cannot be consumed when captured by a closure}} - // expected-error @-2 {{noncopyable 'x2' cannot be consumed when captured by a closure}} + // expected-error @-1 {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} + // expected-error @-2 {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} let f = { borrowVal(x2) consumeVal(x2) // expected-note {{consumed here}} @@ -1822,8 +1822,8 @@ public func closureCaptureClassOwnedArgUseAfterConsume2(_ x2: consuming NonTrivi } public func closureCaptureClassOwnedArgUseAfterConsume3(_ x2: __owned NonTrivialStruct) { - // expected-error @-1 {{noncopyable 'x2' cannot be consumed when captured by a closure}} - // expected-error @-2 {{noncopyable 'x2' cannot be consumed when captured by a closure}} + // expected-error @-1 {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} + // expected-error @-2 {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} let f = { borrowVal(x2) consumeVal(x2) // expected-note {{consumed here}} @@ -1852,7 +1852,7 @@ public func closureCaptureClassOwnedArgUseAfterConsume4(_ x2: consuming NonTrivi public func deferCaptureClassUseAfterConsume(_ x: borrowing NonTrivialStruct) { // expected-error {{'x' is borrowed and cannot be consumed}} let x2 = x // expected-note {{consumed here}} - // expected-error @-1 {{noncopyable 'x2' cannot be consumed when captured by a closure}} + // expected-error @-1 {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} defer { borrowVal(x2) consumeVal(x2) // expected-note {{consumed here}} @@ -1864,7 +1864,7 @@ public func deferCaptureClassUseAfterConsume(_ x: borrowing NonTrivialStruct) { public func deferCaptureClassUseAfterConsume2(_ x: borrowing NonTrivialStruct) { // expected-error {{'x' is borrowed and cannot be consumed}} let x2 = x // expected-note @-1 {{consumed here}} - // expected-error @-2 {{noncopyable 'x2' cannot be consumed when captured by a closure}} + // expected-error @-2 {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} // expected-error @-3 {{'x2' used after consume}} defer { // expected-note {{used here}} borrowVal(x2) @@ -1876,7 +1876,7 @@ public func deferCaptureClassUseAfterConsume2(_ x: borrowing NonTrivialStruct) { } public func deferCaptureClassArgUseAfterConsume(_ x2: borrowing NonTrivialStruct) { - // expected-error @-1 {{noncopyable 'x2' cannot be consumed when captured by a closure}} + // expected-error @-1 {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} borrowVal(x2) defer { borrowVal(x2) @@ -1887,7 +1887,7 @@ public func deferCaptureClassArgUseAfterConsume(_ x2: borrowing NonTrivialStruct } public func deferCaptureClassOwnedArgUseAfterConsume(_ x2: __owned NonTrivialStruct) { - // expected-error @-1 {{noncopyable 'x2' cannot be consumed when captured by a closure}} + // expected-error @-1 {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} defer { borrowVal(x2) consumeVal(x2) // expected-note {{consumed here}} @@ -1909,7 +1909,7 @@ public func deferCaptureClassOwnedArgUseAfterConsume2(_ x2: consuming NonTrivial } public func deferCaptureClassOwnedArgUseAfterConsume3(_ x2: __owned NonTrivialStruct) { - // expected-error @-1 {{noncopyable 'x2' cannot be consumed when captured by a closure}} + // expected-error @-1 {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} // expected-error @-2 {{'x2' used after consume}} defer { // expected-note {{used here}} borrowVal(x2) @@ -1935,7 +1935,7 @@ public func deferCaptureClassOwnedArgUseAfterConsume4(_ x2: consuming NonTrivial public func closureAndDeferCaptureClassUseAfterConsume(_ x: borrowing NonTrivialStruct) { // expected-error @-1 {{'x' is borrowed and cannot be consumed}} let x2 = x // expected-note {{consumed here}} - // expected-error @-1 {{noncopyable 'x2' cannot be consumed when captured by a closure}} + // expected-error @-1 {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} let f = { defer { borrowVal(x2) @@ -1949,8 +1949,8 @@ public func closureAndDeferCaptureClassUseAfterConsume(_ x: borrowing NonTrivial public func closureAndDeferCaptureClassUseAfterConsume2(_ x: borrowing NonTrivialStruct) { // expected-error {{'x' is borrowed and cannot be consumed}} let x2 = x // expected-note {{consumed here}} - // expected-error @-1 {{noncopyable 'x2' cannot be consumed when captured by a closure}} - // expected-error @-2 {{noncopyable 'x2' cannot be consumed when captured by a closure}} + // expected-error @-1 {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} + // expected-error @-2 {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} let f = { consumeVal(x2) // expected-note {{consumed here}} defer { @@ -1966,8 +1966,8 @@ public func closureAndDeferCaptureClassUseAfterConsume2(_ x: borrowing NonTrivia public func closureAndDeferCaptureClassUseAfterConsume3(_ x: borrowing NonTrivialStruct) { // expected-error {{'x' is borrowed and cannot be consumed}} let x2 = x // expected-note @-1 {{consumed here}} - // expected-error @-2 {{noncopyable 'x2' cannot be consumed when captured by a closure}} - // expected-error @-3 {{noncopyable 'x2' cannot be consumed when captured by a closure}} + // expected-error @-2 {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} + // expected-error @-3 {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} let f = { consumeVal(x2) // expected-note {{consumed here}} defer { @@ -1983,7 +1983,7 @@ public func closureAndDeferCaptureClassUseAfterConsume3(_ x: borrowing NonTrivia public func closureAndDeferCaptureClassArgUseAfterConsume(_ x2: borrowing NonTrivialStruct) { // expected-error @-1 {{'x2' cannot be captured by an escaping closure since it is a borrowed parameter}} - // expected-error @-2 {{noncopyable 'x2' cannot be consumed when captured by a closure}} + // expected-error @-2 {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} let f = { // expected-note {{closure capturing 'x2' here}} defer { borrowVal(x2) @@ -1996,7 +1996,7 @@ public func closureAndDeferCaptureClassArgUseAfterConsume(_ x2: borrowing NonTri } public func closureAndDeferCaptureClassOwnedArgUseAfterConsume(_ x2: __owned NonTrivialStruct) { - // expected-error @-1 {{noncopyable 'x2' cannot be consumed when captured by a closure}} + // expected-error @-1 {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} let f = { defer { borrowVal(x2) @@ -2024,7 +2024,7 @@ public func closureAndDeferCaptureClassOwnedArgUseAfterConsume2(_ x2: consuming } public func closureAndDeferCaptureClassOwnedArgUseAfterConsume3(_ x2: __owned NonTrivialStruct) { - // expected-error @-1 {{noncopyable 'x2' cannot be consumed when captured by a closure}} + // expected-error @-1 {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} let f = { defer { borrowVal(x2) @@ -2055,8 +2055,8 @@ public func closureAndDeferCaptureClassOwnedArgUseAfterConsume4(_ x2: consuming public func closureAndClosureCaptureClassUseAfterConsume(_ x: borrowing NonTrivialStruct) { // expected-error {{'x' is borrowed and cannot be consumed}} let x2 = x // expected-note {{consumed here}} - // expected-error @-1 {{noncopyable 'x2' cannot be consumed when captured by a closure}} - // expected-error @-2 {{noncopyable 'x2' cannot be consumed when captured by a closure}} + // expected-error @-1 {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} + // expected-error @-2 {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} let f = { let g = { borrowVal(x2) @@ -2070,8 +2070,8 @@ public func closureAndClosureCaptureClassUseAfterConsume(_ x: borrowing NonTrivi public func closureAndClosureCaptureClassUseAfterConsume2(_ x: borrowing NonTrivialStruct) { // expected-error {{'x' is borrowed and cannot be consumed}} let x2 = x // expected-note {{consumed here}} - // expected-error @-1 {{noncopyable 'x2' cannot be consumed when captured by a closure}} - // expected-error @-2 {{noncopyable 'x2' cannot be consumed when captured by a closure}} + // expected-error @-1 {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} + // expected-error @-2 {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} let f = { let g = { borrowVal(x2) @@ -2086,7 +2086,7 @@ public func closureAndClosureCaptureClassUseAfterConsume2(_ x: borrowing NonTriv public func closureAndClosureCaptureClassArgUseAfterConsume(_ x2: borrowing NonTrivialStruct) { - // expected-error @-1 {{noncopyable 'x2' cannot be consumed when captured by a closure}} + // expected-error @-1 {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} // expected-error @-2 {{'x2' cannot be captured by an escaping closure since it is a borrowed parameter}} // expected-error @-3 {{'x2' cannot be captured by an escaping closure since it is a borrowed parameter}} let f = { // expected-note {{closure capturing 'x2' here}} @@ -2101,8 +2101,8 @@ public func closureAndClosureCaptureClassArgUseAfterConsume(_ x2: borrowing NonT } public func closureAndClosureCaptureClassOwnedArgUseAfterConsume(_ x2: __owned NonTrivialStruct) { - // expected-error @-1 {{noncopyable 'x2' cannot be consumed when captured by a closure}} - // expected-error @-2 {{noncopyable 'x2' cannot be consumed when captured by a closure}} + // expected-error @-1 {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} + // expected-error @-2 {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} let f = { let g = { borrowVal(x2) @@ -2130,8 +2130,8 @@ public func closureAndClosureCaptureClassOwnedArgUseAfterConsume2(_ x2: consumin } public func closureAndClosureCaptureClassOwnedArgUseAfterConsume3(_ x2: __owned NonTrivialStruct) { - // expected-error @-1 {{noncopyable 'x2' cannot be consumed when captured by a closure}} - // expected-error @-2 {{noncopyable 'x2' cannot be consumed when captured by a closure}} + // expected-error @-1 {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} + // expected-error @-2 {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} let f = { let g = { borrowVal(x2) @@ -2145,8 +2145,8 @@ public func closureAndClosureCaptureClassOwnedArgUseAfterConsume3(_ x2: __owned } public func closureAndClosureCaptureClassOwnedArgUseAfterConsume4(_ x2: __owned NonTrivialStruct) { - // expected-error @-1 {{noncopyable 'x2' cannot be consumed when captured by a closure}} - // expected-error @-2 {{noncopyable 'x2' cannot be consumed when captured by a closure}} + // expected-error @-1 {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} + // expected-error @-2 {{noncopyable 'x2' cannot be consumed when captured by an escaping closure}} let f = { let g = { borrowVal(x2) diff --git a/test/SILOptimizer/noimplicitcopy_consuming_parameters.swift b/test/SILOptimizer/noimplicitcopy_consuming_parameters.swift index e9a3f21e340db..380ca517062a7 100644 --- a/test/SILOptimizer/noimplicitcopy_consuming_parameters.swift +++ b/test/SILOptimizer/noimplicitcopy_consuming_parameters.swift @@ -151,7 +151,7 @@ func testLoadableConsumingEscapingClosure(_ x: consuming NonTrivialStruct) { } func testLoadableConsumingEscapingClosure2(_ x: consuming NonTrivialStruct) { - _ = x // expected-error {{noncopyable 'x' cannot be consumed when captured by a closure}} + _ = x // expected-error {{noncopyable 'x' cannot be consumed when captured by an escaping closure}} var f: () -> () = {} f = { _ = x @@ -165,7 +165,7 @@ func testLoadableConsumingEscapingClosure3(_ x: consuming NonTrivialStruct) { _ = x } _ = f - _ = x // expected-error {{noncopyable 'x' cannot be consumed when captured by a closure}} + _ = x // expected-error {{noncopyable 'x' cannot be consumed when captured by an escaping closure}} } func testLoadableConsumingNonEscapingClosure(_ x: consuming NonTrivialStruct) { @@ -302,7 +302,7 @@ func testTrivialConsumingEscapingClosure(_ x: consuming TrivialStruct) { } func testTrivialConsumingEscapingClosure2(_ x: consuming TrivialStruct) { - let _ = x // expected-error {{noncopyable 'x' cannot be consumed when captured by a closure}} + let _ = x // expected-error {{noncopyable 'x' cannot be consumed when captured by an escaping closure}} var f: () -> () = {} f = { _ = x @@ -316,7 +316,7 @@ func testTrivialConsumingEscapingClosure3(_ x: consuming TrivialStruct) { _ = x } _ = f - let _ = x // expected-error {{noncopyable 'x' cannot be consumed when captured by a closure}} + let _ = x // expected-error {{noncopyable 'x' cannot be consumed when captured by an escaping closure}} } func testTrivialConsumingNonEscapingClosure(_ x: consuming TrivialStruct) { @@ -440,7 +440,7 @@ func testAddressOnlyConsumingEscapingClosure(_ x: consuming GenericNonTri } func testAddressOnlyConsumingEscapingClosure2(_ x: consuming GenericNonTrivialStruct) { - let _ = x // expected-error {{noncopyable 'x' cannot be consumed when captured by a closure}} + let _ = x // expected-error {{noncopyable 'x' cannot be consumed when captured by an escaping closure}} var f: () -> () = {} f = { _ = x @@ -454,7 +454,7 @@ func testAddressOnlyConsumingEscapingClosure3(_ x: consuming GenericNonTr _ = x } _ = f - let _ = x // expected-error {{noncopyable 'x' cannot be consumed when captured by a closure}} + let _ = x // expected-error {{noncopyable 'x' cannot be consumed when captured by an escaping closure}} } func testAddressOnlyConsumingNonEscapingClosure(_ x: consuming GenericNonTrivialStruct) { @@ -646,7 +646,7 @@ struct LoadableSelfTest { } consuming func testCallEscapingClosure2() { - let _ = self // expected-error {{noncopyable 'self' cannot be consumed when captured by a closure}} + let _ = self // expected-error {{noncopyable 'self' cannot be consumed when captured by an escaping closure}} var f: () -> () = {} f = { let _ = self @@ -660,7 +660,7 @@ struct LoadableSelfTest { let _ = self } f() - let _ = self // expected-error {{noncopyable 'self' cannot be consumed when captured by a closure}} + let _ = self // expected-error {{noncopyable 'self' cannot be consumed when captured by an escaping closure}} } consuming func testCallNonEscapingClosure() { @@ -804,7 +804,7 @@ struct AddressOnlySelfTest { } consuming func testCallEscapingClosure2() { - let _ = self // expected-error {{noncopyable 'self' cannot be consumed when captured by a closure}} + let _ = self // expected-error {{noncopyable 'self' cannot be consumed when captured by an escaping closure}} var f: () -> () = {} f = { let _ = self @@ -818,7 +818,7 @@ struct AddressOnlySelfTest { let _ = self } f() - let _ = self // expected-error {{noncopyable 'self' cannot be consumed when captured by a closure}} + let _ = self // expected-error {{noncopyable 'self' cannot be consumed when captured by an escaping closure}} } consuming func testCallEscapingClosure4() { @@ -830,7 +830,7 @@ struct AddressOnlySelfTest { f = { let _ = self } - let _ = self // expected-error {{noncopyable 'self' cannot be consumed when captured by a closure}} + let _ = self // expected-error {{noncopyable 'self' cannot be consumed when captured by an escaping closure}} } consuming func testCallNonEscapingClosure() { @@ -956,7 +956,7 @@ struct TrivialSelfTest { } consuming func testCallEscapingClosure2() { - let _ = self // expected-error {{noncopyable 'self' cannot be consumed when captured by a closure}} + let _ = self // expected-error {{noncopyable 'self' cannot be consumed when captured by an escaping closure}} var f: () -> () = {} f = { let _ = self From 3e8985bd1880c7671bcfd9dd81e1c5d6bf558128 Mon Sep 17 00:00:00 2001 From: Nate Chandler Date: Wed, 7 Jun 2023 16:54:40 -0700 Subject: [PATCH 31/37] [CanOSSALifetime] Gardening: Tweaked comments. --- lib/SILOptimizer/Utils/CanonicalizeOSSALifetime.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/lib/SILOptimizer/Utils/CanonicalizeOSSALifetime.cpp b/lib/SILOptimizer/Utils/CanonicalizeOSSALifetime.cpp index 9d119841216cb..f9fda092cbea2 100644 --- a/lib/SILOptimizer/Utils/CanonicalizeOSSALifetime.cpp +++ b/lib/SILOptimizer/Utils/CanonicalizeOSSALifetime.cpp @@ -522,7 +522,7 @@ void CanonicalizeOSSALifetime::findOriginalBoundary( /// These are the "original" live blocks (originalLiveBlocks). /// [Color these blocks green.] /// - From within that collection, collect the blocks which contain a _final_ -/// consuming, non-destroy use, and their successors. +/// consuming, non-destroy use, and their iterative successors. /// These are the "consumed" blocks (consumedAtExitBlocks). /// [Color these blocks red.] /// - Extend liveness down to the boundary between originalLiveBlocks and @@ -569,8 +569,11 @@ void CanonicalizeOSSALifetime::extendUnconsumedLiveness( } } - // Second, collect the blocks which occur after a _final_ consuming use. + // Second, collect the blocks which contain a _final_ consuming use and their + // iterative successors within the originalLiveBlocks. BasicBlockSet consumedAtExitBlocks(currentDef->getFunction()); + // The subset of consumedAtExitBlocks which do not contain a _final_ consuming + // use, i.e. the subset that is dead. StackList consumedAtEntryBlocks(currentDef->getFunction()); { // Start the forward walk from blocks which contain _final_ non-destroy @@ -596,8 +599,8 @@ void CanonicalizeOSSALifetime::extendUnconsumedLiveness( } } - // Third, find the blocks on the boundary between the originally-live blocks - // and the originally-live-but-consumed blocks. Extend liveness "to the end" + // Third, find the blocks on the boundary between the originalLiveBlocks + // blocks and the consumedAtEntryBlocks blocks. Extend liveness "to the end" // of these blocks. for (auto *block : consumedAtEntryBlocks) { for (auto *predecessor : block->getPredecessorBlocks()) { From 219f94fd1aeda6bef20637299e836ab03856448b Mon Sep 17 00:00:00 2001 From: Kavon Farvardin Date: Mon, 12 Jun 2023 17:54:13 -0700 Subject: [PATCH 32/37] tailor reinit-after-consume message for closure captures rdar://109908383 --- include/swift/AST/DiagnosticsSIL.def | 5 +-- .../Mandatory/MoveOnlyDiagnostics.cpp | 21 +++++++++--- test/SILOptimizer/discard_checking.swift | 2 +- .../moveonly_addresschecker_diagnostics.swift | 34 +++++++++---------- .../moveonly_nonescaping_closures.swift | 4 +-- .../moveonly_objectchecker_diagnostics.swift | 30 ++++++++-------- ...y_trivial_addresschecker_diagnostics.swift | 24 ++++++------- ...ly_trivial_objectchecker_diagnostics.swift | 14 ++++---- 8 files changed, 74 insertions(+), 60 deletions(-) diff --git a/include/swift/AST/DiagnosticsSIL.def b/include/swift/AST/DiagnosticsSIL.def index 362dbc4ed7876..896d472d69029 100644 --- a/include/swift/AST/DiagnosticsSIL.def +++ b/include/swift/AST/DiagnosticsSIL.def @@ -767,8 +767,9 @@ ERROR(sil_movechecking_borrowed_parameter_captured_by_closure, none, (StringRef)) ERROR(sil_movechecking_capture_consumed, none, "noncopyable '%0' cannot be consumed when captured by an escaping closure", (StringRef)) -ERROR(sil_movechecking_inout_not_reinitialized_before_end_of_function, none, - "missing reinitialization of inout parameter '%0' after consume", (StringRef)) +ERROR(sil_movechecking_not_reinitialized_before_end_of_function, none, + "missing reinitialization of %select{inout parameter|closure capture}1 '%0' " + "after consume", (StringRef, bool)) ERROR(sil_movechecking_value_consumed_in_a_loop, none, "'%0' consumed in a loop", (StringRef)) ERROR(sil_movechecking_use_after_partial_consume, none, diff --git a/lib/SILOptimizer/Mandatory/MoveOnlyDiagnostics.cpp b/lib/SILOptimizer/Mandatory/MoveOnlyDiagnostics.cpp index 913c373a26fac..4375ee9631556 100644 --- a/lib/SILOptimizer/Mandatory/MoveOnlyDiagnostics.cpp +++ b/lib/SILOptimizer/Mandatory/MoveOnlyDiagnostics.cpp @@ -542,6 +542,19 @@ void DiagnosticEmitter::emitObjectDiagnosticsForPartialApplyUses( // MARK: Address Diagnostics //===----------------------------------------------------------------------===// +static bool isClosureCapture(MarkMustCheckInst *markedValue) { + SILValue val = markedValue->getOperand(); + + // look past any project-box + if (auto *pbi = dyn_cast(val)) + val = pbi->getOperand(); + + if (auto *fArg = dyn_cast(val)) + return fArg->isClosureCapture(); + + return false; +} + void DiagnosticEmitter::emitAddressExclusivityHazardDiagnostic( MarkMustCheckInst *markedValue, SILInstruction *consumingUser) { if (!useWithDiagnostic.insert(consumingUser).second) @@ -596,8 +609,8 @@ void DiagnosticEmitter::emitAddressDiagnostic(MarkMustCheckInst *markedValue, diagnose( astContext, markedValue, diag:: - sil_movechecking_inout_not_reinitialized_before_end_of_function, - varName); + sil_movechecking_not_reinitialized_before_end_of_function, + varName, isClosureCapture(markedValue)); diagnose(astContext, violatingUser, diag::sil_movechecking_consuming_use_here); return; @@ -647,8 +660,8 @@ void DiagnosticEmitter::emitInOutEndOfFunctionDiagnostic( // consuming message: diagnose( astContext, markedValue, - diag::sil_movechecking_inout_not_reinitialized_before_end_of_function, - varName); + diag::sil_movechecking_not_reinitialized_before_end_of_function, + varName, isClosureCapture(markedValue)); diagnose(astContext, violatingUser, diag::sil_movechecking_consuming_use_here); } diff --git a/test/SILOptimizer/discard_checking.swift b/test/SILOptimizer/discard_checking.swift index d8c2ebba5ef57..322c1eb66487c 100644 --- a/test/SILOptimizer/discard_checking.swift +++ b/test/SILOptimizer/discard_checking.swift @@ -388,7 +388,7 @@ struct Basics: ~Copyable { // FIXME move checker is treating the defer like a closure capture (rdar://100468597) // not expecting any errors here - consuming func brokenPositiveTest(_ i: Int) { // expected-error {{missing reinitialization of inout parameter 'self' after consume}} + consuming func brokenPositiveTest(_ i: Int) { // expected-error {{missing reinitialization of closure capture 'self' after consume}} defer { discard self } // expected-note {{consumed here}} switch i { case 0, 1, 2, 3: return diff --git a/test/SILOptimizer/moveonly_addresschecker_diagnostics.swift b/test/SILOptimizer/moveonly_addresschecker_diagnostics.swift index ca449ab9416ab..44319d7b967dd 100644 --- a/test/SILOptimizer/moveonly_addresschecker_diagnostics.swift +++ b/test/SILOptimizer/moveonly_addresschecker_diagnostics.swift @@ -3083,7 +3083,7 @@ public func closureLetClassUseAfterConsumeArg(_ argX: inout Klass) { // We do not support captures of vars by closures today. public func closureLetCaptureClassUseAfterConsume() { - var x2 = Klass() // expected-error {{missing reinitialization of inout parameter 'x2' after consume}} + var x2 = Klass() // expected-error {{missing reinitialization of closure capture 'x2' after consume}} // expected-error @-1 {{'x2' consumed more than once}} x2 = Klass() let f = { @@ -3096,7 +3096,7 @@ public func closureLetCaptureClassUseAfterConsume() { } public func closureLetCaptureClassUseAfterConsume2() { - var x2 = Klass() // expected-error {{missing reinitialization of inout parameter 'x2' after consume}} + var x2 = Klass() // expected-error {{missing reinitialization of closure capture 'x2' after consume}} x2 = Klass() let f = { borrowVal(x2) @@ -3106,7 +3106,7 @@ public func closureLetCaptureClassUseAfterConsume2() { } public func closureLetCaptureClassUseAfterConsumeError() { - var x2 = Klass() // expected-error {{missing reinitialization of inout parameter 'x2' after consume}} + var x2 = Klass() // expected-error {{missing reinitialization of closure capture 'x2' after consume}} // expected-error @-1 {{'x2' consumed more than once}} // expected-error @-2 {{'x2' consumed more than once}} x2 = Klass() @@ -3254,7 +3254,7 @@ public func closureVarCaptureClassArgUseAfterConsume(_ x2: inout Klass) { public func deferCaptureClassUseAfterConsume() { var x2 = Klass() // expected-error @-1 {{'x2' used after consume}} - // expected-error @-2 {{missing reinitialization of inout parameter 'x2' after consume}} + // expected-error @-2 {{missing reinitialization of closure capture 'x2' after consume}} // expected-error @-3 {{'x2' consumed more than once}} x2 = Klass() defer { // expected-note {{used here}} @@ -3269,7 +3269,7 @@ public func deferCaptureClassUseAfterConsume() { public func deferCaptureClassUseAfterConsume2() { var x2 = Klass() - // expected-error @-1 {{missing reinitialization of inout parameter 'x2' after consume}} + // expected-error @-1 {{missing reinitialization of closure capture 'x2' after consume}} // expected-error @-2 {{'x2' consumed more than once}} // expected-error @-3 {{'x2' used after consume}} x2 = Klass() @@ -3284,7 +3284,7 @@ public func deferCaptureClassUseAfterConsume2() { } public func deferCaptureClassArgUseAfterConsume(_ x2: inout Klass) { - // expected-error @-1 {{missing reinitialization of inout parameter 'x2' after consume}} + // expected-error @-1 {{missing reinitialization of closure capture 'x2' after consume}} // expected-error @-2 {{'x2' consumed more than once}} borrowVal(x2) defer { @@ -3298,7 +3298,7 @@ public func deferCaptureClassArgUseAfterConsume(_ x2: inout Klass) { public func closureLetAndDeferCaptureClassUseAfterConsume() { var x2 = Klass() - // expected-error @-1 {{missing reinitialization of inout parameter 'x2' after consume}} + // expected-error @-1 {{missing reinitialization of closure capture 'x2' after consume}} // expected-error @-2 {{'x2' consumed more than once}} x2 = Klass() let f = { @@ -3316,7 +3316,7 @@ public func closureLetAndDeferCaptureClassUseAfterConsume() { public func closureLetAndDeferCaptureClassUseAfterConsume2() { var x2 = Klass() // expected-error {{'x2' used after consume}} - // expected-error @-1 {{missing reinitialization of inout parameter 'x2' after consume}} + // expected-error @-1 {{missing reinitialization of closure capture 'x2' after consume}} // expected-error @-2 {{'x2' consumed more than once}} x2 = Klass() let f = { @@ -3335,7 +3335,7 @@ public func closureLetAndDeferCaptureClassUseAfterConsume2() { public func closureLetAndDeferCaptureClassUseAfterConsume3() { var x2 = Klass() // expected-error {{'x2' used after consume}} - // expected-error @-1 {{missing reinitialization of inout parameter 'x2' after consume}} + // expected-error @-1 {{missing reinitialization of closure capture 'x2' after consume}} // expected-error @-2 {{'x2' consumed more than once}} x2 = Klass() let f = { @@ -3354,7 +3354,7 @@ public func closureLetAndDeferCaptureClassUseAfterConsume3() { } public func closureLetAndDeferCaptureClassArgUseAfterConsume(_ x2: inout Klass) { - // expected-error @-1 {{missing reinitialization of inout parameter 'x2' after consume}} + // expected-error @-1 {{missing reinitialization of closure capture 'x2' after consume}} // expected-error @-2 {{'x2' consumed more than once}} // expected-note @-3 {{'x2' is declared 'inout'}} let f = { // expected-error {{escaping closure captures 'inout' parameter 'x2'}} @@ -3377,7 +3377,7 @@ public func closureLetAndDeferCaptureClassArgUseAfterConsume(_ x2: inout Klass) public func closureLetAndClosureCaptureClassUseAfterConsume() { var x2 = Klass() // expected-error {{'x2' consumed more than once}} - // expected-error @-1 {{missing reinitialization of inout parameter 'x2' after consume}} + // expected-error @-1 {{missing reinitialization of closure capture 'x2' after consume}} x2 = Klass() let f = { let g = { @@ -3393,7 +3393,7 @@ public func closureLetAndClosureCaptureClassUseAfterConsume() { public func closureLetAndClosureCaptureClassUseAfterConsume2() { var x2 = Klass() // expected-error {{'x2' consumed more than once}} - // expected-error @-1 {{missing reinitialization of inout parameter 'x2' after consume}} + // expected-error @-1 {{missing reinitialization of closure capture 'x2' after consume}} x2 = Klass() let f = { let g = { @@ -3436,7 +3436,7 @@ public func closureLetAndClosureCaptureClassArgUseAfterConsume(_ x2: inout Klass public func closureVarAndDeferCaptureClassUseAfterConsume(_ x: borrowing Klass) { // expected-error {{'x' is borrowed and cannot be consumed}} var x2 = Klass() // expected-error {{'x2' consumed more than once}} - // expected-error @-1 {{missing reinitialization of inout parameter 'x2' after consume}} + // expected-error @-1 {{missing reinitialization of closure capture 'x2' after consume}} x2 = x // expected-note {{consumed here}} var f = {} f = { @@ -3453,7 +3453,7 @@ public func closureVarAndDeferCaptureClassUseAfterConsume(_ x: borrowing Klass) public func closureVarAndDeferCaptureClassUseAfterConsume2(_ x: borrowing Klass) { // expected-error {{'x' is borrowed and cannot be consumed}} var x2 = Klass() - // expected-error @-1 {{missing reinitialization of inout parameter 'x2' after consume}} + // expected-error @-1 {{missing reinitialization of closure capture 'x2' after consume}} // expected-error @-2 {{'x2' consumed more than once}} x2 = x // expected-note {{consumed here}} var f = {} @@ -3474,7 +3474,7 @@ public func closureVarAndDeferCaptureClassUseAfterConsume2(_ x: borrowing Klass) public func closureVarAndDeferCaptureClassUseAfterConsume3(_ x: borrowing Klass) { // expected-error {{'x' is borrowed and cannot be consumed}} var x2 = Klass() // expected-error @-1 {{'x2' consumed more than once}} - // expected-error @-2 {{missing reinitialization of inout parameter 'x2' after consume}} + // expected-error @-2 {{missing reinitialization of closure capture 'x2' after consume}} x2 = x // expected-note @-1 {{consumed here}} var f = {} @@ -3522,7 +3522,7 @@ public func closureVarAndDeferCaptureClassOwnedArgUseAfterConsume(_ x2: __owned } public func closureVarAndDeferCaptureClassOwnedArgUseAfterConsume2(_ x2: consuming Klass) { - // expected-error @-1 {{missing reinitialization of inout parameter 'x2' after consume}} + // expected-error @-1 {{missing reinitialization of closure capture 'x2' after consume}} // expected-error @-2 {{'x2' consumed more than once}} var f = {} f = { @@ -3555,7 +3555,7 @@ public func closureVarAndDeferCaptureClassOwnedArgUseAfterConsume3(_ x2: __owned public func closureVarAndDeferCaptureClassOwnedArgUseAfterConsume4(_ x2: consuming Klass) { // expected-error @-1 {{'x2' consumed more than once}} - // expected-error @-2 {{missing reinitialization of inout parameter 'x2' after consume}} + // expected-error @-2 {{missing reinitialization of closure capture 'x2' after consume}} var f = {} f = { defer { diff --git a/test/SILOptimizer/moveonly_nonescaping_closures.swift b/test/SILOptimizer/moveonly_nonescaping_closures.swift index 3d37a81ae36cc..c2c1bec70ee7e 100644 --- a/test/SILOptimizer/moveonly_nonescaping_closures.swift +++ b/test/SILOptimizer/moveonly_nonescaping_closures.swift @@ -82,7 +82,7 @@ func d(x: __owned M) { // expected-error {{noncopyable 'x' cannot be consumed wh // expected-note @-1 {{consumed here}} } -func d2(x: consuming M) { // expected-error {{missing reinitialization of inout parameter 'x' after consume}} +func d2(x: consuming M) { // expected-error {{missing reinitialization of closure capture 'x' after consume}} clodger({ consume(x) }) // expected-note @-1 {{consumed here}} } @@ -129,7 +129,7 @@ func k(x: borrowing M) { } -func l(x: inout M) { // expected-error {{missing reinitialization of inout parameter 'x' after consume}} +func l(x: inout M) { // expected-error {{missing reinitialization of closure capture 'x' after consume}} clodger({ consume(x) }) // expected-note {{consumed here}} } diff --git a/test/SILOptimizer/moveonly_objectchecker_diagnostics.swift b/test/SILOptimizer/moveonly_objectchecker_diagnostics.swift index 9146484efc167..97b95ef1f6934 100644 --- a/test/SILOptimizer/moveonly_objectchecker_diagnostics.swift +++ b/test/SILOptimizer/moveonly_objectchecker_diagnostics.swift @@ -2777,7 +2777,7 @@ public func closureLetCaptureClassUseAfterConsume(_ x: consuming Klass) { public func closureLetCaptureClassUseAfterConsume1(_ x: borrowing Klass) { // expected-error {{'x' is borrowed and cannot be consumed}} var x2 = x // expected-note {{consumed here}} // expected-error @-1 {{'x2' consumed more than once}} - // expected-error @-2 {{missing reinitialization of inout parameter 'x2' after consume}} + // expected-error @-2 {{missing reinitialization of closure capture 'x2' after consume}} x2 = x // expected-note {{consumed here}} let f = { @@ -2802,7 +2802,7 @@ public func closureLetCaptureClassUseAfterConsume2(_ x2: inout Klass) { // TODO: We are considering this to be an escaping use. public func closureLetCaptureClassUseAfterConsume3(_ x2: inout Klass) { // expected-error @-1 {{'x2' consumed more than once}} - // expected-error @-2 {{missing reinitialization of inout parameter 'x2' after consume}} + // expected-error @-2 {{missing reinitialization of closure capture 'x2' after consume}} func useClosure(_ x: () -> ()) {} useClosure { @@ -2852,7 +2852,7 @@ public func closureLetCaptureClassOwnedArgUseAfterConsume(_ x2: __owned Klass) { public func closureLetCaptureClassOwnedArgUseAfterConsume2(_ x2: consuming Klass) { // expected-error @-1 {{'x2' consumed more than once}} - // expected-error @-2 {{missing reinitialization of inout parameter 'x2' after consume}} + // expected-error @-2 {{missing reinitialization of closure capture 'x2' after consume}} let f = { borrowVal(x2) consumeVal(x2) // expected-note {{consumed here}} @@ -2878,7 +2878,7 @@ public func closureLetCaptureClassOwnedArgUseAfterConsume3(_ x2: __owned Klass) public func closureLetCaptureClassOwnedArgUseAfterConsume4(_ x2: consuming Klass) { // expected-error @-1 {{'x2' consumed more than once}} // expected-error @-2 {{'x2' consumed more than once}} - // expected-error @-3 {{missing reinitialization of inout parameter 'x2' after consume}} + // expected-error @-3 {{missing reinitialization of closure capture 'x2' after consume}} let f = { borrowVal(x2) consumeVal(x2) // expected-note {{consumed here}} @@ -2980,7 +2980,7 @@ public func closureVarCaptureClassUseAfterConsume3(_ x2: inout Klass) { public func closureVarCaptureClassUseAfterConsume4(_ x2: inout Klass) { // expected-error @-1 {{'x2' consumed more than once}} - // expected-error @-2 {{missing reinitialization of inout parameter 'x2' after consume}} + // expected-error @-2 {{missing reinitialization of closure capture 'x2' after consume}} func useClosure(_ x: () -> ()) {} useClosure { @@ -3115,7 +3115,7 @@ public func deferCaptureClassOwnedArgUseAfterConsume(_ x2: __owned Klass) { } public func deferCaptureClassOwnedArgUseAfterConsume2(_ x2: consuming Klass) { - // expected-error @-1 {{missing reinitialization of inout parameter 'x2' after consume}} + // expected-error @-1 {{missing reinitialization of closure capture 'x2' after consume}} // expected-error @-2 {{'x2' consumed more than once}} defer { borrowVal(x2) @@ -3138,7 +3138,7 @@ public func deferCaptureClassOwnedArgUseAfterConsume3(_ x2: __owned Klass) { } public func deferCaptureClassOwnedArgUseAfterConsume4(_ x2: consuming Klass) { - // expected-error @-1 {{missing reinitialization of inout parameter 'x2' after consume}} + // expected-error @-1 {{missing reinitialization of closure capture 'x2' after consume}} // expected-error @-2 {{'x2' consumed more than once}} // expected-error @-3 {{'x2' used after consume}} defer { // expected-note {{used here}} @@ -3232,7 +3232,7 @@ public func closureLetAndDeferCaptureClassOwnedArgUseAfterConsume(_ x2: __owned } public func closureLetAndDeferCaptureClassOwnedArgUseAfterConsume2(_ x2: consuming Klass) { - // expected-error @-1 {{missing reinitialization of inout parameter 'x2' after consume}} + // expected-error @-1 {{missing reinitialization of closure capture 'x2' after consume}} // expected-error @-2 {{'x2' consumed more than once}} let f = { defer { @@ -3263,7 +3263,7 @@ public func closureLetAndDeferCaptureClassOwnedArgUseAfterConsume3(_ x2: __owned public func closureLetAndDeferCaptureClassOwnedArgUseAfterConsume4(_ x2: consuming Klass) { // expected-error @-1 {{'x2' consumed more than once}} - // expected-error @-2 {{missing reinitialization of inout parameter 'x2' after consume}} + // expected-error @-2 {{missing reinitialization of closure capture 'x2' after consume}} let f = { defer { borrowVal(x2) @@ -3321,7 +3321,7 @@ public func closureLetAndClosureCaptureClassUseAfterConsume3(_ x: borrowing Klas var x2 = x // expected-note @-1 {{consumed here}} // expected-error @-2 {{'x2' consumed more than once}} - // expected-error @-3 {{missing reinitialization of inout parameter 'x2' after consume}} + // expected-error @-3 {{missing reinitialization of closure capture 'x2' after consume}} // expected-error @-4 {{'x2' consumed more than once}} x2 = x // expected-note @-1 {{consumed here}} @@ -3372,7 +3372,7 @@ public func closureLetAndClosureCaptureClassOwnedArgUseAfterConsume(_ x2: __owne public func closureLetAndClosureCaptureClassOwnedArgUseAfterConsume2(_ x2: consuming Klass) { // expected-error @-1 {{'x2' consumed more than once}} - // expected-error @-2 {{missing reinitialization of inout parameter 'x2' after consume}} + // expected-error @-2 {{missing reinitialization of closure capture 'x2' after consume}} let f = { let g = { borrowVal(x2) @@ -3401,7 +3401,7 @@ public func closureLetAndClosureCaptureClassOwnedArgUseAfterConsume3(_ x2: __own } public func closureLetAndClosureCaptureClassOwnedArgUseAfterConsume4(_ x2: consuming Klass) { - // expected-error @-1 {{missing reinitialization of inout parameter 'x2' after consume}} + // expected-error @-1 {{missing reinitialization of closure capture 'x2' after consume}} // expected-error @-2 {{'x2' consumed more than once}} let f = { let g = { @@ -3417,7 +3417,7 @@ public func closureLetAndClosureCaptureClassOwnedArgUseAfterConsume4(_ x2: consu } public func closureLetAndClosureCaptureClassOwnedArgUseAfterConsume5(_ x2: consuming Klass) { - // expected-error @-1 {{missing reinitialization of inout parameter 'x2' after consume}} + // expected-error @-1 {{missing reinitialization of closure capture 'x2' after consume}} // expected-error @-2 {{'x2' consumed more than once}} // expected-error @-3 {{'x2' used after consume}} let f = { @@ -3518,7 +3518,7 @@ public func closureVarAndDeferCaptureClassOwnedArgUseAfterConsume(_ x2: __owned } public func closureVarAndDeferCaptureClassOwnedArgUseAfterConsume2(_ x2: consuming Klass) { - // expected-error @-1 {{missing reinitialization of inout parameter 'x2' after consume}} + // expected-error @-1 {{missing reinitialization of closure capture 'x2' after consume}} // expected-error @-2 {{'x2' consumed more than once}} var f = {} f = { @@ -3551,7 +3551,7 @@ public func closureVarAndDeferCaptureClassOwnedArgUseAfterConsume3(_ x2: __owned public func closureVarAndDeferCaptureClassOwnedArgUseAfterConsume4(_ x2: consuming Klass) { // expected-error @-1 {{'x2' consumed more than once}} - // expected-error @-2 {{missing reinitialization of inout parameter 'x2' after consume}} + // expected-error @-2 {{missing reinitialization of closure capture 'x2' after consume}} var f = {} f = { defer { diff --git a/test/SILOptimizer/moveonly_trivial_addresschecker_diagnostics.swift b/test/SILOptimizer/moveonly_trivial_addresschecker_diagnostics.swift index 284745459fe04..0546c129efeea 100644 --- a/test/SILOptimizer/moveonly_trivial_addresschecker_diagnostics.swift +++ b/test/SILOptimizer/moveonly_trivial_addresschecker_diagnostics.swift @@ -1200,7 +1200,7 @@ public func closureClassUseAfterConsumeArg(_ argX: inout NonTrivialStruct) { // We do not support captures of vars by closures today. public func closureCaptureClassUseAfterConsume() { var x2 = NonTrivialStruct() - // expected-error @-1 {{missing reinitialization of inout parameter 'x2' after consume}} + // expected-error @-1 {{missing reinitialization of closure capture 'x2' after consume}} // expected-error @-2 {{'x2' consumed more than once}} x2 = NonTrivialStruct() let f = { @@ -1216,7 +1216,7 @@ public func closureCaptureClassUseAfterConsumeError() { var x2 = NonTrivialStruct() // expected-error @-1 {{'x2' consumed more than once}} // expected-error @-2 {{'x2' consumed more than once}} - // expected-error @-3 {{missing reinitialization of inout parameter 'x2' after consume}} + // expected-error @-3 {{missing reinitialization of closure capture 'x2' after consume}} // expected-error @-4 {{'x2' consumed more than once}} // expected-error @-5 {{'x2' consumed more than once}} x2 = NonTrivialStruct() @@ -1251,7 +1251,7 @@ public func closureCaptureClassArgUseAfterConsume(_ x2: inout NonTrivialStruct) // TODO: Improve error msg here to make it clear the use is due to the defer. public func deferCaptureClassUseAfterConsume() { var x2 = NonTrivialStruct() - // expected-error @-1 {{missing reinitialization of inout parameter 'x2' after consume}} + // expected-error @-1 {{missing reinitialization of closure capture 'x2' after consume}} // expected-error @-2 {{'x2' consumed more than once}} // expected-error @-3 {{'x2' used after consume}} x2 = NonTrivialStruct() @@ -1266,7 +1266,7 @@ public func deferCaptureClassUseAfterConsume() { public func deferCaptureClassUseAfterConsume2() { var x2 = NonTrivialStruct() - // expected-error @-1 {{missing reinitialization of inout parameter 'x2' after consume}} + // expected-error @-1 {{missing reinitialization of closure capture 'x2' after consume}} // expected-error @-2 {{'x2' consumed more than once}} // expected-error @-3 {{'x2' used after consume}} x2 = NonTrivialStruct() @@ -1281,7 +1281,7 @@ public func deferCaptureClassUseAfterConsume2() { } public func deferCaptureClassArgUseAfterConsume(_ x2: inout NonTrivialStruct) { - // expected-error @-1 {{missing reinitialization of inout parameter 'x2' after consume}} + // expected-error @-1 {{missing reinitialization of closure capture 'x2' after consume}} // expected-error @-2 {{'x2' consumed more than once}} borrowVal(x2) defer { @@ -1295,7 +1295,7 @@ public func deferCaptureClassArgUseAfterConsume(_ x2: inout NonTrivialStruct) { public func closureAndDeferCaptureClassUseAfterConsume() { var x2 = NonTrivialStruct() - // expected-error @-1 {{missing reinitialization of inout parameter 'x2' after consume}} + // expected-error @-1 {{missing reinitialization of closure capture 'x2' after consume}} // expected-error @-2 {{'x2' consumed more than once}} x2 = NonTrivialStruct() let f = { @@ -1313,7 +1313,7 @@ public func closureAndDeferCaptureClassUseAfterConsume() { public func closureAndDeferCaptureClassUseAfterConsume2() { var x2 = NonTrivialStruct() - // expected-error @-1 {{missing reinitialization of inout parameter 'x2' after consume}} + // expected-error @-1 {{missing reinitialization of closure capture 'x2' after consume}} // expected-error @-2 {{'x2' consumed more than once}} // expected-error @-3 {{'x2' used after consume}} x2 = NonTrivialStruct() @@ -1333,7 +1333,7 @@ public func closureAndDeferCaptureClassUseAfterConsume2() { public func closureAndDeferCaptureClassUseAfterConsume3() { var x2 = NonTrivialStruct() - // expected-error @-1 {{missing reinitialization of inout parameter 'x2' after consume}} + // expected-error @-1 {{missing reinitialization of closure capture 'x2' after consume}} // expected-error @-2 {{'x2' consumed more than once}} // expected-error @-3 {{'x2' used after consume}} x2 = NonTrivialStruct() @@ -1353,7 +1353,7 @@ public func closureAndDeferCaptureClassUseAfterConsume3() { } public func closureAndDeferCaptureClassArgUseAfterConsume(_ x2: inout NonTrivialStruct) { - // expected-error @-1 {{missing reinitialization of inout parameter 'x2' after consume}} + // expected-error @-1 {{missing reinitialization of closure capture 'x2' after consume}} // expected-error @-2 {{'x2' consumed more than once}} // expected-note @-3 {{'x2' is declared 'inout'}} let f = { // expected-error {{escaping closure captures 'inout' parameter 'x2'}} @@ -1373,7 +1373,7 @@ public func closureAndDeferCaptureClassArgUseAfterConsume(_ x2: inout NonTrivial public func closureAndClosureCaptureClassUseAfterConsume() { var x2 = NonTrivialStruct() // expected-error @-1 {{'x2' consumed more than once}} - // expected-error @-2 {{missing reinitialization of inout parameter 'x2' after consume}} + // expected-error @-2 {{missing reinitialization of closure capture 'x2' after consume}} x2 = NonTrivialStruct() let f = { let g = { @@ -1390,7 +1390,7 @@ public func closureAndClosureCaptureClassUseAfterConsume() { public func closureAndClosureCaptureClassUseAfterConsume2() { var x2 = NonTrivialStruct() // expected-error @-1 {{'x2' consumed more than once}} - // expected-error @-2 {{missing reinitialization of inout parameter 'x2' after consume}} + // expected-error @-2 {{missing reinitialization of closure capture 'x2' after consume}} x2 = NonTrivialStruct() let f = { let g = { @@ -1408,7 +1408,7 @@ public func closureAndClosureCaptureClassUseAfterConsume2() { public func closureAndClosureCaptureClassUseAfterConsume3() { var x2 = NonTrivialStruct() // expected-error @-1 {{'x2' consumed more than once}} - // expected-error @-2 {{missing reinitialization of inout parameter 'x2' after consume}} + // expected-error @-2 {{missing reinitialization of closure capture 'x2' after consume}} // expected-error @-3 {{'x2' used after consume}} x2 = NonTrivialStruct() let f = { diff --git a/test/SILOptimizer/moveonly_trivial_objectchecker_diagnostics.swift b/test/SILOptimizer/moveonly_trivial_objectchecker_diagnostics.swift index 239dd82584050..f08448dbeae24 100644 --- a/test/SILOptimizer/moveonly_trivial_objectchecker_diagnostics.swift +++ b/test/SILOptimizer/moveonly_trivial_objectchecker_diagnostics.swift @@ -1810,7 +1810,7 @@ public func closureCaptureClassOwnedArgUseAfterConsume(_ x2: __owned NonTrivialS } public func closureCaptureClassOwnedArgUseAfterConsume2(_ x2: consuming NonTrivialStruct) { - // expected-error @-1 {{missing reinitialization of inout parameter 'x2' after consume}} + // expected-error @-1 {{missing reinitialization of closure capture 'x2' after consume}} // expected-error @-2 {{'x2' consumed more than once}} let f = { borrowVal(x2) @@ -1835,7 +1835,7 @@ public func closureCaptureClassOwnedArgUseAfterConsume3(_ x2: __owned NonTrivial } public func closureCaptureClassOwnedArgUseAfterConsume4(_ x2: consuming NonTrivialStruct) { - // expected-error @-1 {{missing reinitialization of inout parameter 'x2' after consume}} + // expected-error @-1 {{missing reinitialization of closure capture 'x2' after consume}} // expected-error @-2 {{'x2' consumed more than once}} // expected-error @-3 {{'x2' consumed more than once}} let f = { @@ -1898,7 +1898,7 @@ public func deferCaptureClassOwnedArgUseAfterConsume(_ x2: __owned NonTrivialStr public func deferCaptureClassOwnedArgUseAfterConsume2(_ x2: consuming NonTrivialStruct) { // expected-error @-1 {{'x2' consumed more than once}} - // expected-error @-2 {{missing reinitialization of inout parameter 'x2' after consume}} + // expected-error @-2 {{missing reinitialization of closure capture 'x2' after consume}} defer { borrowVal(x2) consumeVal(x2) // expected-note {{consumed here}} @@ -1920,7 +1920,7 @@ public func deferCaptureClassOwnedArgUseAfterConsume3(_ x2: __owned NonTrivialSt } public func deferCaptureClassOwnedArgUseAfterConsume4(_ x2: consuming NonTrivialStruct) { - // expected-error @-1 {{missing reinitialization of inout parameter 'x2' after consume}} + // expected-error @-1 {{missing reinitialization of closure capture 'x2' after consume}} // expected-error @-2 {{'x2' used after consume}} // expected-error @-3 {{'x2' consumed more than once}} defer { // expected-note {{used here}} @@ -2009,7 +2009,7 @@ public func closureAndDeferCaptureClassOwnedArgUseAfterConsume(_ x2: __owned Non } public func closureAndDeferCaptureClassOwnedArgUseAfterConsume2(_ x2: consuming NonTrivialStruct) { - // expected-error @-1 {{missing reinitialization of inout parameter 'x2' after consume}} + // expected-error @-1 {{missing reinitialization of closure capture 'x2' after consume}} // expected-error @-2 {{'x2' consumed more than once}} let f = { defer { @@ -2038,7 +2038,7 @@ public func closureAndDeferCaptureClassOwnedArgUseAfterConsume3(_ x2: __owned No } public func closureAndDeferCaptureClassOwnedArgUseAfterConsume4(_ x2: consuming NonTrivialStruct) { - // expected-error @-1 {{missing reinitialization of inout parameter 'x2' after consume}} + // expected-error @-1 {{missing reinitialization of closure capture 'x2' after consume}} // expected-error @-2 {{'x2' consumed more than once}} let f = { defer { @@ -2116,7 +2116,7 @@ public func closureAndClosureCaptureClassOwnedArgUseAfterConsume(_ x2: __owned N public func closureAndClosureCaptureClassOwnedArgUseAfterConsume2(_ x2: consuming NonTrivialStruct) { // expected-error @-1 {{'x2' consumed more than once}} - // expected-error @-2 {{missing reinitialization of inout parameter 'x2' after consume}} + // expected-error @-2 {{missing reinitialization of closure capture 'x2' after consume}} let f = { let g = { borrowVal(x2) From d6fe62542af18b3fa7bbbd91edc1b88d409b96eb Mon Sep 17 00:00:00 2001 From: Holly Borla Date: Mon, 12 Jun 2023 23:07:21 -0700 Subject: [PATCH 33/37] [GenericEnvironment] Don't apply outer context substitutions before type.subst in mapTypeIntoContext. The outer context substitutions are already applied when invoking QueryInterfaceTypeSubstitutions. Applying the context substitutions before subst also causes problems because QueryInterfaceTypeSubstitutions will return a null type if given an archetype, which manifested with opened pack element environments. --- lib/AST/GenericEnvironment.cpp | 1 - test/Constraints/pack-expansion-expressions.swift | 8 ++++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/AST/GenericEnvironment.cpp b/lib/AST/GenericEnvironment.cpp index 88957a6abe737..aecf75826e670 100644 --- a/lib/AST/GenericEnvironment.cpp +++ b/lib/AST/GenericEnvironment.cpp @@ -635,7 +635,6 @@ Type GenericEnvironment::mapTypeIntoContext( assert((!type->hasArchetype() || type->hasLocalArchetype()) && "already have a contextual type"); - type = maybeApplyOuterContextSubstitutions(type); Type result = type.subst(QueryInterfaceTypeSubstitutions(this), lookupConformance, SubstFlags::AllowLoweredTypes | diff --git a/test/Constraints/pack-expansion-expressions.swift b/test/Constraints/pack-expansion-expressions.swift index b773c333cc3c5..a718ed2944acd 100644 --- a/test/Constraints/pack-expansion-expressions.swift +++ b/test/Constraints/pack-expansion-expressions.swift @@ -553,3 +553,11 @@ do { _ = (repeat overloaded(1, each a)) } } + +func configure( + _ item: T, + with configuration: repeat (ReferenceWritableKeyPath, each Element) +) -> T { + repeat item[keyPath: (each configuration).0] = (each configuration).1 + return item +} From 4ec82768ce2cdf7c220e3c5eec4f0bad7ec86de0 Mon Sep 17 00:00:00 2001 From: Dario Rexin Date: Mon, 12 Jun 2023 23:40:58 -0700 Subject: [PATCH 34/37] [Runtime] Extract some layout string functionality into separate functions (#66577) We want to re-use them for enum layout string instantiation, so best to pull them into separate functions. --- include/swift/Runtime/Metadata.h | 30 ++++++++++++++++ stdlib/public/runtime/Enum.cpp | 60 ++++++++++++++++++++++++++++++++ 2 files changed, 90 insertions(+) diff --git a/include/swift/Runtime/Metadata.h b/include/swift/Runtime/Metadata.h index 557d7530c90ea..07094ef23e7bc 100644 --- a/include/swift/Runtime/Metadata.h +++ b/include/swift/Runtime/Metadata.h @@ -666,6 +666,36 @@ void swift_initStructMetadataWithLayoutString(StructMetadata *self, const uint8_t *fieldTags, uint32_t *fieldOffsets); +SWIFT_RUNTIME_STDLIB_INTERNAL +size_t _swift_refCountBytesForMetatype(const Metadata *type); + +enum LayoutStringFlags : uint64_t { + Empty = 0, + // TODO: Track other useful information tha can be used to optimize layout + // strings, like different reference kinds contained in the string + // number of ref counting operations (maybe up to 4), so we can + // use witness functions optimized for these cases. + HasRelativePointers = (1ULL << 63), +}; + +inline bool operator&(LayoutStringFlags a, LayoutStringFlags b) { + return (uint64_t(a) & uint64_t(b)) != 0; +} +inline LayoutStringFlags operator|(LayoutStringFlags a, LayoutStringFlags b) { + return LayoutStringFlags(uint64_t(a) | uint64_t(b)); +} +inline LayoutStringFlags &operator|=(LayoutStringFlags &a, LayoutStringFlags b) { + return a = (a | b); +} + +SWIFT_RUNTIME_STDLIB_INTERNAL +void _swift_addRefCountStringForMetatype(uint8_t *layoutStr, + size_t &layoutStrOffset, + LayoutStringFlags &flags, + const Metadata *fieldType, + size_t &fullOffset, + size_t &previousFieldOffset); + /// Allocate the metadata for a class and copy fields from the given pattern. /// The final size of the metadata is calculated at runtime from the metadata /// bounds in the class descriptor. diff --git a/stdlib/public/runtime/Enum.cpp b/stdlib/public/runtime/Enum.cpp index 92967e05bd366..f1fdddd3a386e 100644 --- a/stdlib/public/runtime/Enum.cpp +++ b/stdlib/public/runtime/Enum.cpp @@ -214,6 +214,66 @@ swift::swift_initEnumMetadataMultiPayload(EnumMetadata *enumType, vwtable->publishLayout(layout); } +// void +// swift::swift_initEnumMetadataMultiPayloadWithLayoutString(EnumMetadata *enumType, +// EnumLayoutFlags layoutFlags, +// unsigned numPayloads, +// const TypeLayout * const *payloadLayouts) { + // // Accumulate the layout requirements of the payloads. + // size_t payloadSize = 0, alignMask = 0; + // bool isPOD = true, isBT = true; + // for (unsigned i = 0; i < numPayloads; ++i) { + // const TypeLayout *payloadLayout = payloadLayouts[i]; + // payloadSize + // = std::max(payloadSize, (size_t)payloadLayout->size); + // alignMask |= payloadLayout->flags.getAlignmentMask(); + // isPOD &= payloadLayout->flags.isPOD(); + // isBT &= payloadLayout->flags.isBitwiseTakable(); + // } + + // // Store the max payload size in the metadata. + // assignUnlessEqual(enumType->getPayloadSize(), payloadSize); + + // // The total size includes space for the tag. + // auto tagCounts = getEnumTagCounts(payloadSize, + // enumType->getDescription()->getNumEmptyCases(), + // numPayloads); + // unsigned totalSize = payloadSize + tagCounts.numTagBytes; + + // // See whether there are extra inhabitants in the tag. + // unsigned numExtraInhabitants = tagCounts.numTagBytes == 4 + // ? INT_MAX + // : (1 << (tagCounts.numTagBytes * 8)) - tagCounts.numTags; + // numExtraInhabitants = std::min(numExtraInhabitants, + // unsigned(ValueWitnessFlags::MaxNumExtraInhabitants)); + + // auto vwtable = getMutableVWTableForInit(enumType, layoutFlags); + + // // Set up the layout info in the vwtable. + // auto rawStride = (totalSize + alignMask) & ~alignMask; + // TypeLayout layout{totalSize, + // rawStride == 0 ? 1 : rawStride, + // ValueWitnessFlags() + // .withAlignmentMask(alignMask) + // .withPOD(isPOD) + // .withBitwiseTakable(isBT) + // .withEnumWitnesses(true) + // .withInlineStorage(ValueWitnessTable::isValueInline( + // isBT, totalSize, alignMask + 1)), + // numExtraInhabitants}; + + // installCommonValueWitnesses(layout, vwtable); + + // // Unconditionally overwrite the enum-tag witnesses. + // // The compiler does not generate meaningful enum-tag witnesses for + // // enums in this state. + // vwtable->getEnumTagSinglePayload = swift_getMultiPayloadEnumTagSinglePayload; + // vwtable->storeEnumTagSinglePayload = + // swift_storeMultiPayloadEnumTagSinglePayload; + + // vwtable->publishLayout(layout); +//} + namespace { struct MultiPayloadLayout { size_t payloadSize; From fa2ac84d29c7611a1930b9282c8f3ae9ad4d6e15 Mon Sep 17 00:00:00 2001 From: Erik Eckstein Date: Tue, 13 Jun 2023 10:25:41 +0200 Subject: [PATCH 35/37] cmake: correctly set NDEBUG for imported headers in SwiftCompilerSources So that it's consistent with C++ sources rdar://110363377 --- SwiftCompilerSources/CMakeLists.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/SwiftCompilerSources/CMakeLists.txt b/SwiftCompilerSources/CMakeLists.txt index 410a8938f3bd5..b4c66e32aeaf9 100644 --- a/SwiftCompilerSources/CMakeLists.txt +++ b/SwiftCompilerSources/CMakeLists.txt @@ -87,6 +87,10 @@ function(add_swift_compiler_modules_library name) list(APPEND swift_compile_options "-O" "-cross-module-optimization") endif() + if(NOT LLVM_ENABLE_ASSERTIONS) + list(APPEND swift_compile_options "-Xcc" "-DNDEBUG") + endif() + if(NOT SWIFT_STDLIB_SUPPORT_BACK_DEPLOYMENT) list(APPEND swift_compile_options "-Xfrontend" "-disable-legacy-type-info") endif() From 185820a1480baa6e222d75004a9aa6676bfea0e2 Mon Sep 17 00:00:00 2001 From: Stephen Canon Date: Tue, 13 Jun 2023 08:46:46 -0400 Subject: [PATCH 36/37] Fix sign of fractional units in Duration initializers from Double. (#66582) * Fix sign of fractional units in Duration initializers from Double. When separating a double duration into integral and fractional parts, we got the sign wrong. This fixes that bug. * Fixup variable name. --- stdlib/public/core/Duration.swift | 2 +- test/stdlib/Duration.swift | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/stdlib/public/core/Duration.swift b/stdlib/public/core/Duration.swift index 737b77971b3e2..5d4319aca0341 100644 --- a/stdlib/public/core/Duration.swift +++ b/stdlib/public/core/Duration.swift @@ -122,7 +122,7 @@ extension Duration { // handle them slightly differently to ensure that integer values are // never rounded if `scale` is representable as Double. let integralPart = duration.rounded(.towardZero) - let fractionalPart = integralPart - duration + let fractionalPart = duration - integralPart self.init(_attoseconds: // This term may trap due to overflow, but it cannot round, so if the // input `seconds` is an exact integer, we get an exact integer result. diff --git a/test/stdlib/Duration.swift b/test/stdlib/Duration.swift index e6533d52d5254..def1633b2e51d 100644 --- a/test/stdlib/Duration.swift +++ b/test/stdlib/Duration.swift @@ -14,6 +14,8 @@ if #available(SwiftStdlib 5.7, *) { expectEqual(sec, Int64(integerValue)) expectEqual(attosec, 0) } + let quarterSecond = Duration.seconds(0.25) + expectEqual(quarterSecond.components, (0, 250_000_000_000_000_000)) // Value that overflows conversion from Double -> Int64, but should be // representable as a number of seconds: let huge: Double = 1.7e20 From dd7e1775fc20cea2d9a6ba71172538c4100dff0f Mon Sep 17 00:00:00 2001 From: Egor Zhdan Date: Thu, 8 Jun 2023 23:53:34 +0100 Subject: [PATCH 37/37] [cxx-interop] Add `std::set` initializer that takes a Swift Sequence rdar://107909624 --- .../ClangDerivedConformances.cpp | 23 +++++++++++++++++++ stdlib/public/Cxx/CxxSet.swift | 20 ++++++++++++++++ test/Interop/Cxx/stdlib/use-std-set.swift | 14 +++++++++++ 3 files changed, 57 insertions(+) diff --git a/lib/ClangImporter/ClangDerivedConformances.cpp b/lib/ClangImporter/ClangDerivedConformances.cpp index 89bd5d8ddd66d..59a7a60410aaa 100644 --- a/lib/ClangImporter/ClangDerivedConformances.cpp +++ b/lib/ClangImporter/ClangDerivedConformances.cpp @@ -586,10 +586,33 @@ void swift::conformToCxxSetIfNeeded(ClangImporter::Implementation &impl, if (!valueType || !sizeType) return; + auto insertId = ctx.getIdentifier("__insertUnsafe"); + auto inserts = lookupDirectWithoutExtensions(decl, insertId); + FuncDecl *insert = nullptr; + for (auto candidate : inserts) { + if (auto candidateMethod = dyn_cast(candidate)) { + if (!candidateMethod->hasParameterList()) + continue; + auto params = candidateMethod->getParameters(); + if (params->size() != 1) + continue; + auto param = params->front(); + if (param->getType()->getCanonicalType() != + valueType->getUnderlyingType()->getCanonicalType()) + continue; + insert = candidateMethod; + break; + } + } + if (!insert) + return; + impl.addSynthesizedTypealias(decl, ctx.Id_Element, valueType->getUnderlyingType()); impl.addSynthesizedTypealias(decl, ctx.getIdentifier("Size"), sizeType->getUnderlyingType()); + impl.addSynthesizedTypealias(decl, ctx.getIdentifier("InsertionResult"), + insert->getResultInterfaceType()); impl.addSynthesizedProtocolAttrs(decl, {KnownProtocolKind::CxxSet}); } diff --git a/stdlib/public/Cxx/CxxSet.swift b/stdlib/public/Cxx/CxxSet.swift index 02dec94fb1193..e3f143da45b60 100644 --- a/stdlib/public/Cxx/CxxSet.swift +++ b/stdlib/public/Cxx/CxxSet.swift @@ -13,11 +13,31 @@ public protocol CxxSet { associatedtype Element associatedtype Size: BinaryInteger + associatedtype InsertionResult // std::pair + + init() + + @discardableResult + mutating func __insertUnsafe(_ element: Element) -> InsertionResult func count(_ element: Element) -> Size } extension CxxSet { + /// Creates a C++ set containing the elements of a Swift Sequence. + /// + /// This initializes the set by copying every element of the sequence. + /// + /// - Complexity: O(*n*), where *n* is the number of elements in the Swift + /// sequence + @inlinable + public init(_ sequence: S) where S.Element == Element { + self.init() + for item in sequence { + self.__insertUnsafe(item) + } + } + @inlinable public func contains(_ element: Element) -> Bool { return count(element) > 0 diff --git a/test/Interop/Cxx/stdlib/use-std-set.swift b/test/Interop/Cxx/stdlib/use-std-set.swift index 56f7b7672f166..95f0110908f10 100644 --- a/test/Interop/Cxx/stdlib/use-std-set.swift +++ b/test/Interop/Cxx/stdlib/use-std-set.swift @@ -47,4 +47,18 @@ StdSetTestSuite.test("MultisetOfCInt.contains") { expectFalse(s.contains(3)) } +StdSetTestSuite.test("SetOfCInt.init()") { + let s = SetOfCInt([1, 3, 5]) + expectTrue(s.contains(1)) + expectFalse(s.contains(2)) + expectTrue(s.contains(3)) +} + +StdSetTestSuite.test("UnorderedSetOfCInt.init()") { + let s = UnorderedSetOfCInt([1, 3, 5]) + expectTrue(s.contains(1)) + expectFalse(s.contains(2)) + expectTrue(s.contains(3)) +} + runAllTests()