Skip to content

Commit 27879c7

Browse files
author
Gabor Horvath
committed
[cxx-interop] Support _LIBCPP_PREFERRED_OVERLOAD
Some functions like memchr are defined both in libc++ and libc. Including both would result in ambiguous references at the call sites. This is worked around by an attribute that tells the compiler to prefer one overload over the others. This attribute was not interpreted by Swift. As a result, importing both libc and libc++ and calling such functions resulted in compilation errors due to ambiguous overloads. This PR modifies the lookup logic to exclude the non-preferred Clang functions from the overload set whenever a preferred overload is available. rdar://152192945
1 parent 68524a8 commit 27879c7

File tree

6 files changed

+76
-0
lines changed

6 files changed

+76
-0
lines changed

lib/AST/ModuleNameLookup.cpp

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
#include "swift/AST/NameLookup.h"
1818
#include "swift/AST/NameLookupRequests.h"
1919
#include "swift/Basic/Assertions.h"
20+
#include "clang/AST/Attr.h"
21+
#include "clang/AST/ExprCXX.h"
2022
#include "llvm/Support/raw_ostream.h"
2123

2224
using namespace swift;
@@ -278,6 +280,43 @@ void ModuleNameLookup<LookupStrategy>::lookupInModule(
278280
if (decls.size() - initialCount <= 1)
279281
return;
280282

283+
// Some functions like `memchr` are defined both in libc and in libc++.
284+
// Importing both would result in ambiguities, but there are some attributes
285+
// that mark the preferred overloads. See _LIBCPP_PREFERRED_OVERLOAD.
286+
llvm::SmallPtrSet<ValueDecl *, 4> declsToRemove;
287+
bool hasPreferredOverload = false;
288+
for (auto decl : decls)
289+
if (const auto *clangDecl = decl->getClangDecl()) {
290+
if (clangDecl->hasAttr<clang::EnableIfAttr>()) {
291+
// FIXME: at some point we might want to call into Clang to implement
292+
// the full enable_if semantics including the constant evaluation of the
293+
// conditions. For now, just look for the first enable_if(true, "...")
294+
// and assume all the rest of the enable_ifs evaluate to true.
295+
bool thisDeclHasPreferredOverload = false;
296+
for (auto clangAttr :
297+
clangDecl->specific_attrs<clang::EnableIfAttr>()) {
298+
if (auto litExpr =
299+
dyn_cast<clang::CXXBoolLiteralExpr>(clangAttr->getCond())) {
300+
if (litExpr->getValue()) {
301+
thisDeclHasPreferredOverload = hasPreferredOverload = true;
302+
break;
303+
}
304+
}
305+
}
306+
if (!thisDeclHasPreferredOverload)
307+
declsToRemove.insert(decl);
308+
} else
309+
declsToRemove.insert(decl);
310+
}
311+
312+
if (hasPreferredOverload) {
313+
decls.erase(std::remove_if(decls.begin() + initialCount, decls.end(),
314+
[&](ValueDecl *d) -> bool {
315+
return declsToRemove.contains(d);
316+
}),
317+
decls.end());
318+
}
319+
281320
// Remove duplicated declarations, which can happen when the same module is
282321
// imported with multiple access paths.
283322
llvm::SmallPtrSet<ValueDecl *, 4> knownDecls;
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
#pragma once
2+
3+
void f(int a);
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
#pragma once
2+
3+
void f(int a) __attribute__((enable_if(a > 0, ""))) __attribute__((enable_if(true, "")));

test/Interop/Cxx/modules/Inputs/module.modulemap

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,13 @@ module TopLevelModule {
1717
}
1818
export *
1919
}
20+
21+
module AmbiguousA {
22+
header "ambiguous_a.h"
23+
requires cplusplus
24+
}
25+
26+
module AmbiguousB {
27+
header "ambiguous_a.h"
28+
requires cplusplus
29+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// RUN: %target-typecheck-verify-swift -I %S/Inputs -cxx-interoperability-mode=default
2+
3+
import AmbiguousA
4+
import AmbiguousB
5+
6+
func g(_ x: CInt) {
7+
f(x)
8+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// RUN: %target-swift-frontend -cxx-interoperability-mode=default -typecheck -verify -I %S/Inputs %s
2+
3+
// REQUIRES: objc_interop
4+
// REQUIRES: VENDOR=apple
5+
6+
import Darwin
7+
8+
func test_memchr() {
9+
var src = "hello"
10+
var _ = src.withUTF8 { srcBuf in
11+
Darwin.memchr(srcBuf.baseAddress!, 137, src.count)
12+
}
13+
}

0 commit comments

Comments
 (0)