Skip to content
Merged
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: 1 addition & 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 @@ -8891,7 +8887,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));
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'}}
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)
}