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/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/ClangImporter/ClangImporter.cpp b/lib/ClangImporter/ClangImporter.cpp index 60cc7c87fbd32..039367397ec88 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()); @@ -2848,10 +2844,20 @@ ClangModuleUnit *ClangImporter::Implementation::getWrapperForModule( for (auto UI : implicitImportInfo.AdditionalUnloadedImports) Imported.insert(UI.module.getImportPath()); assert(implicitImportInfo.AdditionalImports.empty()); + bool cxx = SwiftContext.LangOpts.EnableCXXInterop; 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" || + (cxx && Req.FeatureName == "cplusplus")); + }); + if (cannotBeImported) { + return; + } ImportPath::Builder builder = getSwiftModulePath(M); if (!guaranteedUnique && Imported.count(builder.get())) return; @@ -8891,7 +8897,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/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/lib/Sema/ImportResolution.cpp b/lib/Sema/ImportResolution.cpp index 3c4f4325f4674..f8de48dc4ef18 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 ? 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..8a033b0292c44 --- /dev/null +++ b/test/ImportResolution/import-alias-fail.swift @@ -0,0 +1,5 @@ +// 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 new file mode 100644 index 0000000000000..96b5d44a556bc --- /dev/null +++ b/test/ImportResolution/import-std-fail.swift @@ -0,0 +1,42 @@ +// 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}} + +//--- 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-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'}} 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..dee8e4a3e7236 --- /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%{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 + +// 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) +} 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..c304506fd07db --- /dev/null +++ b/test/Interop/Cxx/swiftify-import/transitive-std-core-import.swift @@ -0,0 +1,38 @@ +// 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: %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 || 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. + +//--- 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) +} +