Skip to content

Commit 8e7766b

Browse files
committed
[interop] avoid importing math functions from the C++ standard library
They cause ambiguities with math functions from platform's libc
1 parent 6e63015 commit 8e7766b

File tree

3 files changed

+73
-0
lines changed

3 files changed

+73
-0
lines changed

lib/ClangImporter/ImportDecl.cpp

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3121,6 +3121,36 @@ namespace {
31213121
if (decl->isDeleted())
31223122
return nullptr;
31233123

3124+
if (Impl.SwiftContext.LangOpts.EnableCXXInterop &&
3125+
!isa<clang::CXXMethodDecl>(decl)) {
3126+
// Do not import math functions from the C++ standard library, as
3127+
// they're also imported from the Darwin/Glibc module, and their
3128+
// presence in the C++ standard library will cause overloading
3129+
// ambiguities or other type checking errors in Swift.
3130+
auto isAlternativeCStdlibFunctionFromTextualHeader =
3131+
[](const clang::FunctionDecl *d) -> bool {
3132+
// stdlib.h might be a textual header in libc++'s module map.
3133+
// in this case, check for known ambiguous functions by their name
3134+
// instead of checking if they come from the `std` module.
3135+
if (!d->getDeclName().isIdentifier())
3136+
return false;
3137+
return d->getName() == "abs" || d->getName() == "div";
3138+
};
3139+
if (decl->getOwningModule() &&
3140+
(decl->getOwningModule()
3141+
->getTopLevelModule()
3142+
->getFullModuleName() == "std" ||
3143+
isAlternativeCStdlibFunctionFromTextualHeader(decl))) {
3144+
auto filename =
3145+
Impl.getClangPreprocessor().getSourceManager().getFilename(
3146+
decl->getLocation());
3147+
if (filename.endswith("cmath") || filename.endswith("math.h") ||
3148+
filename.endswith("stdlib.h") || filename.endswith("cstdlib")) {
3149+
return nullptr;
3150+
}
3151+
}
3152+
}
3153+
31243154
auto dc =
31253155
Impl.importDeclContextOf(decl, importedName.getEffectiveContext());
31263156
if (!dc)
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// RUN: %target-swift-frontend %s -typecheck -verify -enable-experimental-cxx-interop -Xcc -std=c++17
2+
3+
// REQUIRES: OS=macosx || OS=linux-gnu
4+
5+
import CxxStdlib
6+
7+
func test() {
8+
let x: Float = 1.0
9+
let y: Double = 2.0
10+
11+
// Note: we dispatch `pow(Float,Double)`
12+
// to ensure we don't pick up the
13+
// C++ stdlib `pow` function template.
14+
// The `pow` function is still reexported
15+
// from Darwin via CxxStdlib, so there are
16+
// matching overloads that can be found still.
17+
// Note: the error is different on Glibc instead
18+
// of Darwin, so do not check the exact error.
19+
let _ = CxxStdlib.pow(x, y) // expected-error {{}}
20+
21+
let _ = CxxStdlib.abs(x) // expected-error {{module 'CxxStdlib' has no member named 'abs'}}
22+
let _ = CxxStdlib.div(x) // expected-error {{module 'CxxStdlib' has no member named 'div'}}
23+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// RUN: %target-swift-frontend %s -typecheck -enable-experimental-cxx-interop -Xcc -std=c++17
2+
3+
#if canImport(Foundation)
4+
// Foundation depends on C++ standard library
5+
// on some platforms already, and as such
6+
// may bring math functions from it.
7+
import Foundation
8+
9+
func test() -> Float {
10+
let x: Float = 1.0
11+
// Note: we mix 'Float' and 'Double' (literal)
12+
// intentionally, as this might trigger Swift
13+
// to instantiate a function template from
14+
// the C++ standard library.
15+
let z = pow(x, 2.0)
16+
let _ = abs(x)
17+
let m = z + 1.0
18+
return m
19+
}
20+
#endif

0 commit comments

Comments
 (0)