Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
6 changes: 6 additions & 0 deletions include/swift/Basic/DiagnosticOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,12 @@ class DiagnosticOptions {
/// allow diagnostics at <unknown>, 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;

Expand Down
7 changes: 5 additions & 2 deletions include/swift/Frontend/DiagnosticVerifier.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,18 +100,21 @@ class DiagnosticVerifier : public DiagnosticConsumer {
bool AutoApplyFixes;
bool IgnoreUnknown;
bool IgnoreUnrelated;
bool IgnoreMacroLocationNote;
bool UseColor;
ArrayRef<std::string> AdditionalExpectedPrefixes;

public:
explicit DiagnosticVerifier(SourceManager &SM, ArrayRef<unsigned> BufferIDs,
ArrayRef<std::string> AdditionalFilePaths,
bool AutoApplyFixes, bool IgnoreUnknown,
bool IgnoreUnrelated, bool UseColor,
bool IgnoreUnrelated,
bool IgnoreMacroLocationNote, bool UseColor,
ArrayRef<std::string> 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,
Expand Down
2 changes: 2 additions & 0 deletions include/swift/Option/FrontendOptions.td
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,8 @@ def verify_ignore_unknown: Flag<["-"], "verify-ignore-unknown">,
HelpText<"Allow diagnostics for '<unknown>' 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<"<module-name>">,
HelpText<"Verify the generic signatures in the given module">;
Expand Down
12 changes: 7 additions & 5 deletions lib/ClangImporter/ClangImporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand Down Expand Up @@ -2852,6 +2848,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;
Expand Down Expand Up @@ -8891,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")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this still accept std_core, which acts as a top-level module in recent libc++?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is specifically done to exclude top-level libc++ modules other than std. The issue is that while you could specify submodules to CxxStdlib, there was no way to inherit imports to other libc++ submodules. E.g. a clang module importing std_core.math.abs would become an import of CxxStdlib.math.abs on the Swift side, which would then be translated back to std.math.abs (which doesn't exist) when looking up the module.

builder.push_back(SwiftContext.Id_CxxStdlib);
else
builder.push_back(SwiftContext.getIdentifier(M->Name));
Expand Down
1 change: 1 addition & 0 deletions lib/Frontend/CompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 2 additions & 0 deletions lib/Frontend/DiagnosticVerifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<CapturedFixItInfo, 2> fixIts;
for (const auto &fixIt : Info.FixIts) {
fixIts.emplace_back(SM, fixIt);
Expand Down
3 changes: 2 additions & 1 deletion lib/Frontend/Frontend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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());
}
Expand Down
45 changes: 37 additions & 8 deletions lib/Sema/ImportResolution.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
Expand Down Expand Up @@ -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,
Expand All @@ -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() &&
Expand Down
5 changes: 5 additions & 0 deletions test/ImportResolution/import-alias-fail.swift
Original file line number Diff line number Diff line change
@@ -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'}}

42 changes: 42 additions & 0 deletions test/ImportResolution/import-std-fail.swift
Original file line number Diff line number Diff line change
@@ -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'}}
81 changes: 81 additions & 0 deletions test/Interop/C/swiftify-import/clang-includes-no-swift.swift
Original file line number Diff line number Diff line change
@@ -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)
}
Original file line number Diff line number Diff line change
@@ -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 <span>
#include <lifetimebound.h>

using FloatSpan = std::span<const float>;

size_t foo(FloatSpan x __noescape);

//--- test.swift
import TestClang

func test(x: Span<Float>) {
let _ = foo(x)
}