[interop] avoid importing math functions from the C++ standard library

They cause ambiguities with math functions from platform's libc
This commit is contained in:
Alex Lorenz
2023-04-25 18:22:52 -07:00
committed by Alex Lorenz
parent 6e63015dea
commit 8e7766bf18
3 changed files with 73 additions and 0 deletions

View File

@@ -3121,6 +3121,36 @@ namespace {
if (decl->isDeleted()) if (decl->isDeleted())
return nullptr; return nullptr;
if (Impl.SwiftContext.LangOpts.EnableCXXInterop &&
!isa<clang::CXXMethodDecl>(decl)) {
// Do not import math functions from the C++ standard library, as
// they're also imported from the Darwin/Glibc module, and their
// presence in the C++ standard library will cause overloading
// ambiguities or other type checking errors in Swift.
auto isAlternativeCStdlibFunctionFromTextualHeader =
[](const clang::FunctionDecl *d) -> bool {
// stdlib.h might be a textual header in libc++'s module map.
// in this case, check for known ambiguous functions by their name
// instead of checking if they come from the `std` module.
if (!d->getDeclName().isIdentifier())
return false;
return d->getName() == "abs" || d->getName() == "div";
};
if (decl->getOwningModule() &&
(decl->getOwningModule()
->getTopLevelModule()
->getFullModuleName() == "std" ||
isAlternativeCStdlibFunctionFromTextualHeader(decl))) {
auto filename =
Impl.getClangPreprocessor().getSourceManager().getFilename(
decl->getLocation());
if (filename.endswith("cmath") || filename.endswith("math.h") ||
filename.endswith("stdlib.h") || filename.endswith("cstdlib")) {
return nullptr;
}
}
}
auto dc = auto dc =
Impl.importDeclContextOf(decl, importedName.getEffectiveContext()); Impl.importDeclContextOf(decl, importedName.getEffectiveContext());
if (!dc) if (!dc)

View File

@@ -0,0 +1,23 @@
// RUN: %target-swift-frontend %s -typecheck -verify -enable-experimental-cxx-interop -Xcc -std=c++17
// REQUIRES: OS=macosx || OS=linux-gnu
import CxxStdlib
func test() {
let x: Float = 1.0
let y: Double = 2.0
// Note: we dispatch `pow(Float,Double)`
// to ensure we don't pick up the
// C++ stdlib `pow` function template.
// The `pow` function is still reexported
// from Darwin via CxxStdlib, so there are
// matching overloads that can be found still.
// Note: the error is different on Glibc instead
// of Darwin, so do not check the exact error.
let _ = CxxStdlib.pow(x, y) // expected-error {{}}
let _ = CxxStdlib.abs(x) // expected-error {{module 'CxxStdlib' has no member named 'abs'}}
let _ = CxxStdlib.div(x) // expected-error {{module 'CxxStdlib' has no member named 'div'}}
}

View File

@@ -0,0 +1,20 @@
// RUN: %target-swift-frontend %s -typecheck -enable-experimental-cxx-interop -Xcc -std=c++17
#if canImport(Foundation)
// Foundation depends on C++ standard library
// on some platforms already, and as such
// may bring math functions from it.
import Foundation
func test() -> Float {
let x: Float = 1.0
// Note: we mix 'Float' and 'Double' (literal)
// intentionally, as this might trigger Swift
// to instantiate a function template from
// the C++ standard library.
let z = pow(x, 2.0)
let _ = abs(x)
let m = z + 1.0
return m
}
#endif