From da1fa745142a1920f581f8d57cb14b9c2d690413 Mon Sep 17 00:00:00 2001 From: "Henrik G. Olsson" Date: Wed, 1 Oct 2025 23:30:26 -0700 Subject: [PATCH 1/8] [MacrosOnImports] Don't import !swift modules Inheriting a clang import marked `requires: !swift` will always result in an error. This skips such imports, which *may* result in name lookup errors instead, but also may not, depending on the module. rdar://161795145 --- lib/ClangImporter/ClangImporter.cpp | 6 ++ .../clang-includes-no-swift.swift | 81 +++++++++++++++++++ 2 files changed, 87 insertions(+) create mode 100644 test/Interop/C/swiftify-import/clang-includes-no-swift.swift diff --git a/lib/ClangImporter/ClangImporter.cpp b/lib/ClangImporter/ClangImporter.cpp index 60cc7c87fbd32..fbe56c58e6b22 100644 --- a/lib/ClangImporter/ClangImporter.cpp +++ b/lib/ClangImporter/ClangImporter.cpp @@ -2852,6 +2852,12 @@ ClangModuleUnit *ClangImporter::Implementation::getWrapperForModule( auto addImplicitImport = [&implicitImportInfo, &Imported, this](const clang::Module *M, bool guaranteedUnique) { + const bool cannotBeImported = llvm::any_of(M->Requirements, [](auto &Req) { + return !Req.RequiredState && Req.FeatureName == "swift"; + }); + if (cannotBeImported) { + return; + } ImportPath::Builder builder = getSwiftModulePath(M); if (!guaranteedUnique && Imported.count(builder.get())) return; diff --git a/test/Interop/C/swiftify-import/clang-includes-no-swift.swift b/test/Interop/C/swiftify-import/clang-includes-no-swift.swift new file mode 100644 index 0000000000000..b6c565cb986aa --- /dev/null +++ b/test/Interop/C/swiftify-import/clang-includes-no-swift.swift @@ -0,0 +1,81 @@ +// REQUIRES: swift_feature_SafeInteropWrappers + +// RUN: %empty-directory(%t) +// RUN: split-file --leading-lines %s %t + +// RUN: %target-swift-frontend -typecheck -plugin-path %swift-plugin-dir -I %t/Inputs -enable-experimental-feature SafeInteropWrappers %t/succeed.swift +// RUN: not %target-swift-frontend -typecheck -plugin-path %swift-plugin-dir -I %t/Inputs -enable-experimental-feature SafeInteropWrappers %t/fail.swift -dump-source-file-imports 2>&1 | %FileCheck %s +// RUN: %target-swift-frontend -typecheck -plugin-path %swift-plugin-dir -I %t/Inputs -enable-experimental-feature SafeInteropWrappers %t/fail.swift -verify -verify-additional-file %t%{fs-sep}Inputs%{fs-sep}B1.h + +// Tests that we don't try to import modules that don't work well with Swift + +// CHECK: imports for {{.*}}fail.swift: +// CHECK-NEXT: Swift +// CHECK-NEXT: _StringProcessing +// CHECK-NEXT: _SwiftConcurrencyShims +// CHECK-NEXT: _Concurrency +// CHECK-NEXT: B1 +// CHECK-NEXT: A1 + +// CHECK-NEXT: imports for A1.foo: + +// CHECK-NEXT: imports for @__swiftmacro{{.*}}foo{{.*}}_SwiftifyImport{{.*}}.swift: +// CHECK-NEXT: Swift +// CHECK-NEXT: B1 +// CHECK-NEXT: _StringProcessing +// CHECK-NEXT: _SwiftConcurrencyShims +// CHECK-NEXT: _Concurrency + +//--- Inputs/module.modulemap +module A1 { + explicit module B1 { + header "B1.h" + explicit module C1 { + header "C1.h" + requires !swift + } + } +} + +//--- Inputs/B1.h +#pragma once + +#include "C1.h" +#define __sized_by(s) __attribute__((__sized_by__(s))) + +// We can use bar without C1 causing errors +void bar(void * _Nonnull __sized_by(size), int size); +// foo causes an error when we try to refer to c1_t from the '!swift' module C1 +c1_t foo(void * _Nonnull __sized_by(size), int size); +/* +expected-note@-2{{'foo' declared here}} +expected-expansion@-3:52{{ + expected-error@2:110{{cannot find type 'c1_t' in scope}} +}} +*/ + +//--- Inputs/C1.h +#pragma once + +typedef int c1_t; + +//--- fail.swift +import A1.B1 + +public func callUnsafe(_ p: UnsafeMutableRawPointer) { + let _ = foo(p, 13) +} +public func callSafe(_ p: UnsafeMutableRawBufferPointer) { + let _ = foo(p) // expected-error{{cannot convert value of type 'UnsafeMutableRawBufferPointer' to expected argument type 'UnsafeMutableRawPointer'}} + // expected-error@-1{{missing argument}} +} + +//--- succeed.swift +import A1.B1 + +public func callUnsafe(_ p: UnsafeMutableRawPointer) { + bar(p, 13) +} +public func callSafe(_ p: UnsafeMutableRawBufferPointer) { + bar(p) +} From fca94fbceb12a818c2b224e3bc4b0362f3a3aa26 Mon Sep 17 00:00:00 2001 From: "Henrik G. Olsson" Date: Wed, 1 Oct 2025 23:37:47 -0700 Subject: [PATCH 2/8] [ImportResolution] Only disallow explicit `std` imports (allow implicit) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When expanding a Swift macro in a clang module where the original clang module imported a submodule in a C++ standard library module other than `std`, e.g. a submodule to `std_core`, this would result in an error. This is because `std_core.math.abs` would be imported as `CxxStdlib.math.abs`, which would later be translated back as `std.math.abs` which doesn’t exist. This changes the mapping to only map `std` to `CxxStdlib`. To prevent errors when importing modules starting with `std_`, this error is moved from the late-stage module import to the earlier processing of `ImportDecl`s. This results in these module names still being forbidden in explicit imports (i.e. naming them in source code), while still being allowed in implicit imports inherited from clang modules. This also fixes a fix-it bug where only the first 3 characters would be selected for replacing with `CxxStdlib` when importing `std_core`. This also fixes a diagnostic bug where aliased modules would refer to the module name in the source code rather than the real module name, and adds a note clarifying the situation. rdar://161795429 rdar://161795673 rdar://161795793 --- include/swift/AST/DiagnosticsSema.def | 2 + lib/ClangImporter/ClangImporter.cpp | 6 +-- lib/Sema/ImportResolution.cpp | 45 +++++++++++++++---- test/ImportResolution/import-alias-fail.swift | 5 +++ test/ImportResolution/import-std-fail.swift | 22 +++++++++ .../transitive-std-core-import.swift | 33 ++++++++++++++ 6 files changed, 100 insertions(+), 13 deletions(-) create mode 100644 test/ImportResolution/import-alias-fail.swift create mode 100644 test/ImportResolution/import-std-fail.swift create mode 100644 test/Interop/Cxx/swiftify-import/transitive-std-core-import.swift diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index dbee278386036..8cda6b72da572 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -875,6 +875,8 @@ WARNING(sema_import_current_module_with_file,none, (StringRef, Identifier)) ERROR(sema_opening_import,Fatal, "opening import file for module %0: %1", (Identifier, StringRef)) +NOTE(sema_module_aliased,none, + "module name '%0' is aliased to '%1'", (StringRef, StringRef)) REMARK(serialization_skipped_invalid_decl,none, "serialization skipped invalid %kind0", diff --git a/lib/ClangImporter/ClangImporter.cpp b/lib/ClangImporter/ClangImporter.cpp index fbe56c58e6b22..985d989f79680 100644 --- a/lib/ClangImporter/ClangImporter.cpp +++ b/lib/ClangImporter/ClangImporter.cpp @@ -2415,10 +2415,6 @@ ModuleDecl *ClangImporter::Implementation::loadModule( ModuleDecl *MD = nullptr; ASTContext &ctx = getNameImporter().getContext(); - // `CxxStdlib` is the only accepted spelling of the C++ stdlib module name. - if (path.front().Item.is("std") || - path.front().Item.str().starts_with("std_")) - return nullptr; if (path.front().Item == ctx.Id_CxxStdlib) { ImportPath::Builder adjustedPath(ctx.getIdentifier("std"), importLoc); adjustedPath.append(path.getSubmodulePath()); @@ -8897,7 +8893,7 @@ bool importer::isCxxStdModule(StringRef moduleName, bool IsSystem) { ImportPath::Builder ClangImporter::Implementation::getSwiftModulePath(const clang::Module *M) { ImportPath::Builder builder; while (M) { - if (!M->isSubModule() && isCxxStdModule(M)) + if (!M->isSubModule() && M->Name == "std") builder.push_back(SwiftContext.Id_CxxStdlib); else builder.push_back(SwiftContext.getIdentifier(M->Name)); diff --git a/lib/Sema/ImportResolution.cpp b/lib/Sema/ImportResolution.cpp index 3c4f4325f4674..6a57fe2c9a090 100644 --- a/lib/Sema/ImportResolution.cpp +++ b/lib/Sema/ImportResolution.cpp @@ -359,6 +359,26 @@ static bool isSubmodule(const ModuleDecl* M) { void ImportResolver::visitImportDecl(ImportDecl *ID) { assert(unboundImports.empty()); + // `CxxStdlib` is the only accepted spelling of the C++ stdlib module name. + ImportPath::Builder builder; + const ImportPath path = ID->getRealImportPath(builder); + const llvm::StringRef front = path.front().Item.str(); + if (front == "std" || front.starts_with("std_")) { + SmallString<64> modulePathStr; + path.getString(modulePathStr); + auto diagKind = (ctx.LangOpts.DebuggerSupport || true) ? diag::sema_no_import_repl + : diag::sema_no_import; + const SourceLoc importLoc = ID->getLoc(); + const ImportPath sourcePath = ID->getImportPath(); + const llvm::StringRef sourceFront = sourcePath.front().Item.str(); + ctx.Diags.diagnose(importLoc, diagKind, modulePathStr); + ctx.Diags.diagnose(importLoc, diag::did_you_mean_cxxstdlib) + .fixItReplaceChars(importLoc, importLoc.getAdvancedLoc(sourceFront.size()), "CxxStdlib"); + if (front != sourceFront) + ctx.Diags.diagnose(importLoc, diag::sema_module_aliased, sourceFront, front); + return; + } + unboundImports.emplace_back(ID); bindPendingImports(); } @@ -513,13 +533,15 @@ UnboundImport::getTopLevelModule(ModuleDecl *M, SourceFile &SF) { // MARK: Implicit imports //===----------------------------------------------------------------------===// -static void tryStdlibFixit(ASTContext &ctx, - StringRef moduleName, - SourceLoc loc) { - if (moduleName.starts_with("std")) { - ctx.Diags.diagnose(loc, diag::did_you_mean_cxxstdlib) - .fixItReplaceChars(loc, loc.getAdvancedLoc(3), "CxxStdlib"); +ImportPath::Module getRealModulePath(ImportPath::Builder &builder, ImportPath::Module path, ASTContext &ctx) { + for (size_t i = 0; i < path.size(); i++) { + if (i == 0) { + builder.push_back(ctx.getRealModuleName(path[i].Item)); + } else { + builder.push_back(path[i]); + } } + return builder.get().getModulePath(false); } static void diagnoseNoSuchModule(ModuleDecl *importingModule, @@ -534,13 +556,20 @@ static void diagnoseNoSuchModule(ModuleDecl *importingModule, importingModule->getName()); } else { SmallString<64> modulePathStr; - modulePath.getString(modulePathStr); + ImportPath::Builder builder; + ImportPath::Module realModulePath = getRealModulePath(builder, modulePath, ctx); + realModulePath.getString(modulePathStr); auto diagKind = diag::sema_no_import; if (nonfatalInREPL && ctx.LangOpts.DebuggerSupport) diagKind = diag::sema_no_import_repl; ctx.Diags.diagnose(importLoc, diagKind, modulePathStr); - tryStdlibFixit(ctx, modulePathStr, importLoc); + + const llvm::StringRef sourceFront = modulePath.front().Item.str(); + const llvm::StringRef realFront = realModulePath.front().Item.str(); + if (realFront != sourceFront) + ctx.Diags.diagnose(importLoc, diag::sema_module_aliased, sourceFront, + realFront); } if (ctx.SearchPathOpts.getSDKPath().empty() && diff --git a/test/ImportResolution/import-alias-fail.swift b/test/ImportResolution/import-alias-fail.swift new file mode 100644 index 0000000000000..db1165ffffc0a --- /dev/null +++ b/test/ImportResolution/import-alias-fail.swift @@ -0,0 +1,5 @@ +// RUN: %target-typecheck-verify-swift -cxx-interoperability-mode=default -module-alias Foo=Bar -verify-ignore-unknown + +import Foo // expected-error{{no such module 'Bar'}} +// expected-note@-1{{module name 'Foo' is aliased to 'Bar'}} + diff --git a/test/ImportResolution/import-std-fail.swift b/test/ImportResolution/import-std-fail.swift new file mode 100644 index 0000000000000..ead015d57bce2 --- /dev/null +++ b/test/ImportResolution/import-std-fail.swift @@ -0,0 +1,22 @@ +// RUN: %target-typecheck-verify-swift -cxx-interoperability-mode=default -module-alias FooBar=std_foo_bar -module-alias X=std_x_h + +import std // expected-error{{no such module 'std'}} + // expected-note@-1{{did you mean 'CxxStdlib'?}}{{8-11=CxxStdlib}} {{none}} + +import std_ // expected-error{{no such module 'std_'}} + // expected-note@-1{{did you mean 'CxxStdlib'?}}{{8-12=CxxStdlib}} {{none}} + +import std_error_h // expected-error{{no such module 'std_error_h'}} + // expected-note@-1{{did you mean 'CxxStdlib'?}}{{8-19=CxxStdlib}} {{none}} + +import std_core.math.abs // expected-error{{no such module 'std_core.math.abs'}} + // expected-note@-1{{did you mean 'CxxStdlib'?}}{{8-16=CxxStdlib}} {{none}} + +import FooBar // expected-error{{no such module 'std_foo_bar'}} + // expected-note@-1{{did you mean 'CxxStdlib'?}}{{8-14=CxxStdlib}} {{none}} + // expected-note@-2{{module name 'FooBar' is aliased to 'std_foo_bar'}} {{none}} + +import X +// expected-error@-1{{no such module 'std_x_h'}} +// expected-note@-2{{did you mean 'CxxStdlib'?}}{{8-9=CxxStdlib}} {{none}} +// expected-note@-3{{module name 'X' is aliased to 'std_x_h'}} {{none}} diff --git a/test/Interop/Cxx/swiftify-import/transitive-std-core-import.swift b/test/Interop/Cxx/swiftify-import/transitive-std-core-import.swift new file mode 100644 index 0000000000000..78b86f2393df3 --- /dev/null +++ b/test/Interop/Cxx/swiftify-import/transitive-std-core-import.swift @@ -0,0 +1,33 @@ +// REQUIRES: swift_feature_SafeInteropWrappers + +// RUN: %empty-directory(%t) +// RUN: split-file %s %t +// RUN: %target-swift-frontend -emit-module -plugin-path %swift-plugin-dir -o %t/Test.swiftmodule -I %t/Inputs -enable-experimental-feature SafeInteropWrappers -strict-memory-safety -warnings-as-errors -Xcc -Werror %t/test.swift -cxx-interoperability-mode=default -Xcc -std=c++20 + +// Test that implicit imports can refer to std_core etc., even though Swift source code may not. + +//--- Inputs/module.modulemap +module TestClang { + header "test.h" + requires cplusplus + export std_core.cstddef.size_t + export span +} + +//--- Inputs/test.h + +#include <__cstddef/size_t.h> +#include +#include + +using FloatSpan = std::span; + +size_t foo(FloatSpan x __noescape); + +//--- test.swift +import TestClang + +func test(x: Span) { + let _ = foo(x) +} + From 0b10caf646caa3225451c4bef2dd9d88550e0d2e Mon Sep 17 00:00:00 2001 From: "Henrik G. Olsson" Date: Wed, 1 Oct 2025 23:55:05 -0700 Subject: [PATCH 3/8] remove unnecessary c++ interop --- test/ImportResolution/import-alias-fail.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/ImportResolution/import-alias-fail.swift b/test/ImportResolution/import-alias-fail.swift index db1165ffffc0a..ebd510a53fd44 100644 --- a/test/ImportResolution/import-alias-fail.swift +++ b/test/ImportResolution/import-alias-fail.swift @@ -1,4 +1,4 @@ -// RUN: %target-typecheck-verify-swift -cxx-interoperability-mode=default -module-alias Foo=Bar -verify-ignore-unknown +// RUN: %target-typecheck-verify-swift -module-alias Foo=Bar -verify-ignore-unknown import Foo // expected-error{{no such module 'Bar'}} // expected-note@-1{{module name 'Foo' is aliased to 'Bar'}} From a17ad02f77cfaadcfaa0b44ce42d49746bd5d037 Mon Sep 17 00:00:00 2001 From: "Henrik G. Olsson" Date: Thu, 2 Oct 2025 11:32:42 -0700 Subject: [PATCH 4/8] fix non-fatal import error --- lib/Sema/ImportResolution.cpp | 2 +- test/ImportResolution/import-alias-fail.swift | 2 +- test/ImportResolution/import-std-fail.swift | 34 +++++++++++++++---- 3 files changed, 29 insertions(+), 9 deletions(-) diff --git a/lib/Sema/ImportResolution.cpp b/lib/Sema/ImportResolution.cpp index 6a57fe2c9a090..f8de48dc4ef18 100644 --- a/lib/Sema/ImportResolution.cpp +++ b/lib/Sema/ImportResolution.cpp @@ -366,7 +366,7 @@ void ImportResolver::visitImportDecl(ImportDecl *ID) { if (front == "std" || front.starts_with("std_")) { SmallString<64> modulePathStr; path.getString(modulePathStr); - auto diagKind = (ctx.LangOpts.DebuggerSupport || true) ? diag::sema_no_import_repl + auto diagKind = ctx.LangOpts.DebuggerSupport ? diag::sema_no_import_repl : diag::sema_no_import; const SourceLoc importLoc = ID->getLoc(); const ImportPath sourcePath = ID->getImportPath(); diff --git a/test/ImportResolution/import-alias-fail.swift b/test/ImportResolution/import-alias-fail.swift index ebd510a53fd44..8a033b0292c44 100644 --- a/test/ImportResolution/import-alias-fail.swift +++ b/test/ImportResolution/import-alias-fail.swift @@ -1,4 +1,4 @@ -// RUN: %target-typecheck-verify-swift -module-alias Foo=Bar -verify-ignore-unknown +// RUN: %target-typecheck-verify-swift -module-alias Foo=Bar import Foo // expected-error{{no such module 'Bar'}} // expected-note@-1{{module name 'Foo' is aliased to 'Bar'}} diff --git a/test/ImportResolution/import-std-fail.swift b/test/ImportResolution/import-std-fail.swift index ead015d57bce2..96b5d44a556bc 100644 --- a/test/ImportResolution/import-std-fail.swift +++ b/test/ImportResolution/import-std-fail.swift @@ -1,22 +1,42 @@ -// RUN: %target-typecheck-verify-swift -cxx-interoperability-mode=default -module-alias FooBar=std_foo_bar -module-alias X=std_x_h +// RUN: %empty-directory(%t) +// RUN: split-file %s %t +// These errors are fatal, so test each one separately + +// RUN: %target-swift-frontend -typecheck -verify -cxx-interoperability-mode=default %t/a.swift +// RUN: %target-swift-frontend -typecheck -verify -cxx-interoperability-mode=default %t/b.swift +// RUN: %target-swift-frontend -typecheck -verify -cxx-interoperability-mode=default %t/c.swift +// RUN: %target-swift-frontend -typecheck -verify -cxx-interoperability-mode=default %t/d.swift +// RUN: %target-swift-frontend -typecheck -verify -cxx-interoperability-mode=default %t/e.swift -verify-additional-prefix aliased- -module-alias FooBar=std_foo_bar +// RUN: %target-swift-frontend -typecheck -verify -cxx-interoperability-mode=default %t/e.swift -verify-additional-prefix unaliased- +// RUN: %target-swift-frontend -typecheck -verify -cxx-interoperability-mode=default %t/f.swift -verify-additional-prefix aliased- -module-alias X=std_x_h +// RUN: %target-swift-frontend -typecheck -verify -cxx-interoperability-mode=default %t/f.swift -verify-additional-prefix unaliased- + +//--- a.swift import std // expected-error{{no such module 'std'}} // expected-note@-1{{did you mean 'CxxStdlib'?}}{{8-11=CxxStdlib}} {{none}} +//--- b.swift import std_ // expected-error{{no such module 'std_'}} // expected-note@-1{{did you mean 'CxxStdlib'?}}{{8-12=CxxStdlib}} {{none}} +//--- c.swift import std_error_h // expected-error{{no such module 'std_error_h'}} // expected-note@-1{{did you mean 'CxxStdlib'?}}{{8-19=CxxStdlib}} {{none}} +//--- d.swift import std_core.math.abs // expected-error{{no such module 'std_core.math.abs'}} // expected-note@-1{{did you mean 'CxxStdlib'?}}{{8-16=CxxStdlib}} {{none}} -import FooBar // expected-error{{no such module 'std_foo_bar'}} - // expected-note@-1{{did you mean 'CxxStdlib'?}}{{8-14=CxxStdlib}} {{none}} - // expected-note@-2{{module name 'FooBar' is aliased to 'std_foo_bar'}} {{none}} +//--- e.swift +import FooBar // expected-aliased-error{{no such module 'std_foo_bar'}} + // expected-aliased-note@-1{{did you mean 'CxxStdlib'?}}{{8-14=CxxStdlib}} {{none}} + // expected-aliased-note@-2{{module name 'FooBar' is aliased to 'std_foo_bar'}} {{none}} + // expected-unaliased-error@-3{{no such module 'FooBar'}} +//--- f.swift import X -// expected-error@-1{{no such module 'std_x_h'}} -// expected-note@-2{{did you mean 'CxxStdlib'?}}{{8-9=CxxStdlib}} {{none}} -// expected-note@-3{{module name 'X' is aliased to 'std_x_h'}} {{none}} +// expected-aliased-error@-1{{no such module 'std_x_h'}} +// expected-aliased-note@-2{{did you mean 'CxxStdlib'?}}{{8-9=CxxStdlib}} {{none}} +// expected-aliased-note@-3{{module name 'X' is aliased to 'std_x_h'}} {{none}} +// expected-unaliased-error@-4{{no such module 'X'}} From a6c0778c7fbf037159b2f03c4aa6f8614e224b35 Mon Sep 17 00:00:00 2001 From: "Henrik G. Olsson" Date: Mon, 6 Oct 2025 18:02:26 -0700 Subject: [PATCH 5/8] only run transitive-std-core-import.swift on new libc++ --- .../swiftify-import/transitive-std-core-import.swift | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/test/Interop/Cxx/swiftify-import/transitive-std-core-import.swift b/test/Interop/Cxx/swiftify-import/transitive-std-core-import.swift index 78b86f2393df3..2f6a9531385b2 100644 --- a/test/Interop/Cxx/swiftify-import/transitive-std-core-import.swift +++ b/test/Interop/Cxx/swiftify-import/transitive-std-core-import.swift @@ -1,8 +1,14 @@ // REQUIRES: swift_feature_SafeInteropWrappers +// REQUIRES: OS=macosx +// Don't run this test with libc++ versions 17-19, when the top-level std module was split into multiple top-level modules. // RUN: %empty-directory(%t) -// RUN: split-file %s %t -// RUN: %target-swift-frontend -emit-module -plugin-path %swift-plugin-dir -o %t/Test.swiftmodule -I %t/Inputs -enable-experimental-feature SafeInteropWrappers -strict-memory-safety -warnings-as-errors -Xcc -Werror %t/test.swift -cxx-interoperability-mode=default -Xcc -std=c++20 +// RUN: %target-clangxx %S/../stdlib/Inputs/check-libcxx-version.cpp -o %t/check-libcxx-version +// RUN: %target-codesign %t/check-libcxx-version + +// RUN: %target-run %t/check-libcxx-version || %empty-directory(%t) +// RUN: %target-run %t/check-libcxx-version || split-file %s %t +// RUN: %target-run %t/check-libcxx-version || %target-swift-frontend -emit-module -plugin-path %swift-plugin-dir -o %t/Test.swiftmodule -I %t/Inputs -enable-experimental-feature SafeInteropWrappers -strict-memory-safety -warnings-as-errors -Xcc -Werror %t/test.swift -cxx-interoperability-mode=default -Xcc -std=c++20 // Test that implicit imports can refer to std_core etc., even though Swift source code may not. From 3e25af2d64dc1e6b2700a5343de6c450cd86500b Mon Sep 17 00:00:00 2001 From: "Henrik G. Olsson" Date: Mon, 6 Oct 2025 23:07:13 -0700 Subject: [PATCH 6/8] [DiagnosticVerifier] Add -verify-ignore-macro-note The _SwiftifyImport macro is emitted into an unnamed buffer and then parsed, pretending it was in the header all along. This makes it hard to add `expected-note` comments for `diag::in_macro_expansion` when they point here. That's okay, because the macro expansion has already been pointed out by `expected-expansion` directives. But -verify-ignore-unrelated is too blunt of a tool, so this adds -verify-ignore-macro-note to ignore these specific diagnostics. --- include/swift/Basic/DiagnosticOptions.h | 6 ++++++ include/swift/Frontend/DiagnosticVerifier.h | 7 +++++-- include/swift/Option/FrontendOptions.td | 2 ++ lib/Frontend/CompilerInvocation.cpp | 1 + lib/Frontend/DiagnosticVerifier.cpp | 2 ++ lib/Frontend/Frontend.cpp | 3 ++- .../C/swiftify-import/clang-includes-no-swift.swift | 2 +- 7 files changed, 19 insertions(+), 4 deletions(-) diff --git a/include/swift/Basic/DiagnosticOptions.h b/include/swift/Basic/DiagnosticOptions.h index 356cbebfe6ad4..376ad905f8c99 100644 --- a/include/swift/Basic/DiagnosticOptions.h +++ b/include/swift/Basic/DiagnosticOptions.h @@ -46,6 +46,12 @@ class DiagnosticOptions { /// allow diagnostics at , that is controlled by VerifyIgnoreUnknown. bool VerifyIgnoreUnrelated = false; + /// Indicates whether to ignore \c diag::in_macro_expansion. This is useful + /// for when they occur in unnamed buffers (such as clang attribute buffers), + /// but VerifyIgnoreUnrelated is too blunt of a tool. Note that notes of this + /// kind are not printed by \c PrintingDiagnosticConsumer. + bool VerifyIgnoreMacroLocationNote = false; + /// Indicates whether diagnostic passes should be skipped. bool SkipDiagnosticPasses = false; diff --git a/include/swift/Frontend/DiagnosticVerifier.h b/include/swift/Frontend/DiagnosticVerifier.h index 8cd5ad1a03d0d..381767cd20ac3 100644 --- a/include/swift/Frontend/DiagnosticVerifier.h +++ b/include/swift/Frontend/DiagnosticVerifier.h @@ -100,6 +100,7 @@ class DiagnosticVerifier : public DiagnosticConsumer { bool AutoApplyFixes; bool IgnoreUnknown; bool IgnoreUnrelated; + bool IgnoreMacroLocationNote; bool UseColor; ArrayRef AdditionalExpectedPrefixes; @@ -107,11 +108,13 @@ class DiagnosticVerifier : public DiagnosticConsumer { explicit DiagnosticVerifier(SourceManager &SM, ArrayRef BufferIDs, ArrayRef AdditionalFilePaths, bool AutoApplyFixes, bool IgnoreUnknown, - bool IgnoreUnrelated, bool UseColor, + bool IgnoreUnrelated, + bool IgnoreMacroLocationNote, bool UseColor, ArrayRef AdditionalExpectedPrefixes) : SM(SM), BufferIDs(BufferIDs), AdditionalFilePaths(AdditionalFilePaths), AutoApplyFixes(AutoApplyFixes), IgnoreUnknown(IgnoreUnknown), - IgnoreUnrelated(IgnoreUnrelated), UseColor(UseColor), + IgnoreUnrelated(IgnoreUnrelated), + IgnoreMacroLocationNote(IgnoreMacroLocationNote), UseColor(UseColor), AdditionalExpectedPrefixes(AdditionalExpectedPrefixes) {} virtual void handleDiagnostic(SourceManager &SM, diff --git a/include/swift/Option/FrontendOptions.td b/include/swift/Option/FrontendOptions.td index b72721ee4e3ca..951fc9a4f22fd 100644 --- a/include/swift/Option/FrontendOptions.td +++ b/include/swift/Option/FrontendOptions.td @@ -167,6 +167,8 @@ def verify_ignore_unknown: Flag<["-"], "verify-ignore-unknown">, HelpText<"Allow diagnostics for '' location in verify mode">; def verify_ignore_unrelated: Flag<["-"], "verify-ignore-unrelated">, HelpText<"Allow diagnostics in files outside those with expected diagnostics in verify mode">; +def verify_ignore_macro_note: Flag<["-"], "verify-ignore-macro-note">, + HelpText<"Skip verifying notes about macro location">; def verify_generic_signatures : Separate<["-"], "verify-generic-signatures">, MetaVarName<"">, HelpText<"Verify the generic signatures in the given module">; diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index 773c30ffd3f84..e374f32cb70a9 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -2598,6 +2598,7 @@ static bool ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args, Opts.VerifyMode = DiagnosticOptions::VerifyAndApplyFixes; Opts.VerifyIgnoreUnknown |= Args.hasArg(OPT_verify_ignore_unknown); Opts.VerifyIgnoreUnrelated |= Args.hasArg(OPT_verify_ignore_unrelated); + Opts.VerifyIgnoreMacroLocationNote |= Args.hasArg(OPT_verify_ignore_macro_note); Opts.SkipDiagnosticPasses |= Args.hasArg(OPT_disable_diagnostic_passes); Opts.ShowDiagnosticsAfterFatalError |= Args.hasArg(OPT_show_diagnostics_after_fatal); diff --git a/lib/Frontend/DiagnosticVerifier.cpp b/lib/Frontend/DiagnosticVerifier.cpp index 42346c5d869fb..e7dcedb344dc5 100644 --- a/lib/Frontend/DiagnosticVerifier.cpp +++ b/lib/Frontend/DiagnosticVerifier.cpp @@ -1502,6 +1502,8 @@ void DiagnosticVerifier::handleDiagnostic(SourceManager &SM, // because there's no reason to verify them. if (Info.ID == diag::verify_encountered_fatal.ID) return; + if (IgnoreMacroLocationNote && Info.ID == diag::in_macro_expansion.ID) + return; SmallVector fixIts; for (const auto &fixIt : Info.FixIts) { fixIts.emplace_back(SM, fixIt); diff --git a/lib/Frontend/Frontend.cpp b/lib/Frontend/Frontend.cpp index 159e312732fd3..e79d4925940fb 100644 --- a/lib/Frontend/Frontend.cpp +++ b/lib/Frontend/Frontend.cpp @@ -435,7 +435,8 @@ bool CompilerInstance::setupDiagnosticVerifierIfNeeded() { SourceMgr, InputSourceCodeBufferIDs, diagOpts.AdditionalVerifierFiles, diagOpts.VerifyMode == DiagnosticOptions::VerifyAndApplyFixes, diagOpts.VerifyIgnoreUnknown, diagOpts.VerifyIgnoreUnrelated, - diagOpts.UseColor, diagOpts.AdditionalDiagnosticVerifierPrefixes); + diagOpts.VerifyIgnoreMacroLocationNote, diagOpts.UseColor, + diagOpts.AdditionalDiagnosticVerifierPrefixes); addDiagnosticConsumer(DiagVerifier.get()); } diff --git a/test/Interop/C/swiftify-import/clang-includes-no-swift.swift b/test/Interop/C/swiftify-import/clang-includes-no-swift.swift index b6c565cb986aa..983c9aec10df2 100644 --- a/test/Interop/C/swiftify-import/clang-includes-no-swift.swift +++ b/test/Interop/C/swiftify-import/clang-includes-no-swift.swift @@ -5,7 +5,7 @@ // RUN: %target-swift-frontend -typecheck -plugin-path %swift-plugin-dir -I %t/Inputs -enable-experimental-feature SafeInteropWrappers %t/succeed.swift // RUN: not %target-swift-frontend -typecheck -plugin-path %swift-plugin-dir -I %t/Inputs -enable-experimental-feature SafeInteropWrappers %t/fail.swift -dump-source-file-imports 2>&1 | %FileCheck %s -// RUN: %target-swift-frontend -typecheck -plugin-path %swift-plugin-dir -I %t/Inputs -enable-experimental-feature SafeInteropWrappers %t/fail.swift -verify -verify-additional-file %t%{fs-sep}Inputs%{fs-sep}B1.h +// RUN: %target-swift-frontend -typecheck -plugin-path %swift-plugin-dir -I %t/Inputs -enable-experimental-feature SafeInteropWrappers %t/fail.swift -verify -verify-additional-file %t%{fs-sep}Inputs%{fs-sep}B1.h -verify-ignore-macro-note // Tests that we don't try to import modules that don't work well with Swift From f828474bfca39d6729038d0fadafcb4e1de5fb5d Mon Sep 17 00:00:00 2001 From: "Henrik G. Olsson" Date: Tue, 7 Oct 2025 17:33:43 -0700 Subject: [PATCH 7/8] fix test on Windows --- test/Interop/C/swiftify-import/clang-includes-no-swift.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Interop/C/swiftify-import/clang-includes-no-swift.swift b/test/Interop/C/swiftify-import/clang-includes-no-swift.swift index 983c9aec10df2..dee8e4a3e7236 100644 --- a/test/Interop/C/swiftify-import/clang-includes-no-swift.swift +++ b/test/Interop/C/swiftify-import/clang-includes-no-swift.swift @@ -5,7 +5,7 @@ // RUN: %target-swift-frontend -typecheck -plugin-path %swift-plugin-dir -I %t/Inputs -enable-experimental-feature SafeInteropWrappers %t/succeed.swift // RUN: not %target-swift-frontend -typecheck -plugin-path %swift-plugin-dir -I %t/Inputs -enable-experimental-feature SafeInteropWrappers %t/fail.swift -dump-source-file-imports 2>&1 | %FileCheck %s -// RUN: %target-swift-frontend -typecheck -plugin-path %swift-plugin-dir -I %t/Inputs -enable-experimental-feature SafeInteropWrappers %t/fail.swift -verify -verify-additional-file %t%{fs-sep}Inputs%{fs-sep}B1.h -verify-ignore-macro-note +// RUN: %target-swift-frontend -typecheck -plugin-path %swift-plugin-dir -I %t%{fs-sep}Inputs -enable-experimental-feature SafeInteropWrappers %t/fail.swift -verify -verify-additional-file %t%{fs-sep}Inputs%{fs-sep}B1.h -verify-ignore-macro-note // Tests that we don't try to import modules that don't work well with Swift From 6ebb5e4794fa18dd0456ffb25df19b90bc7a8db4 Mon Sep 17 00:00:00 2001 From: "Henrik G. Olsson" Date: Fri, 10 Oct 2025 18:50:39 -0700 Subject: [PATCH 8/8] don't run %empty-directory twice --- .../Interop/Cxx/swiftify-import/transitive-std-core-import.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/test/Interop/Cxx/swiftify-import/transitive-std-core-import.swift b/test/Interop/Cxx/swiftify-import/transitive-std-core-import.swift index 2f6a9531385b2..c304506fd07db 100644 --- a/test/Interop/Cxx/swiftify-import/transitive-std-core-import.swift +++ b/test/Interop/Cxx/swiftify-import/transitive-std-core-import.swift @@ -6,7 +6,6 @@ // RUN: %target-clangxx %S/../stdlib/Inputs/check-libcxx-version.cpp -o %t/check-libcxx-version // RUN: %target-codesign %t/check-libcxx-version -// RUN: %target-run %t/check-libcxx-version || %empty-directory(%t) // RUN: %target-run %t/check-libcxx-version || split-file %s %t // RUN: %target-run %t/check-libcxx-version || %target-swift-frontend -emit-module -plugin-path %swift-plugin-dir -o %t/Test.swiftmodule -I %t/Inputs -enable-experimental-feature SafeInteropWrappers -strict-memory-safety -warnings-as-errors -Xcc -Werror %t/test.swift -cxx-interoperability-mode=default -Xcc -std=c++20