mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[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
This commit is contained in:
@@ -17,6 +17,8 @@
|
||||
#include "swift/AST/NameLookup.h"
|
||||
#include "swift/AST/NameLookupRequests.h"
|
||||
#include "swift/Basic/Assertions.h"
|
||||
#include "clang/AST/Attr.h"
|
||||
#include "clang/AST/ExprCXX.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
|
||||
using namespace swift;
|
||||
@@ -278,6 +280,43 @@ void ModuleNameLookup<LookupStrategy>::lookupInModule(
|
||||
if (decls.size() - initialCount <= 1)
|
||||
return;
|
||||
|
||||
// Some functions like `memchr` are defined both in libc and in libc++.
|
||||
// Importing both would result in ambiguities, but there are some attributes
|
||||
// that mark the preferred overloads. See _LIBCPP_PREFERRED_OVERLOAD.
|
||||
llvm::SmallPtrSet<ValueDecl *, 4> declsToRemove;
|
||||
bool hasPreferredOverload = false;
|
||||
for (auto decl : decls)
|
||||
if (const auto *clangDecl = decl->getClangDecl()) {
|
||||
if (clangDecl->hasAttr<clang::EnableIfAttr>()) {
|
||||
// FIXME: at some point we might want to call into Clang to implement
|
||||
// the full enable_if semantics including the constant evaluation of the
|
||||
// conditions. For now, just look for the first enable_if(true, "...")
|
||||
// and assume all the rest of the enable_ifs evaluate to true.
|
||||
bool thisDeclHasPreferredOverload = false;
|
||||
for (auto clangAttr :
|
||||
clangDecl->specific_attrs<clang::EnableIfAttr>()) {
|
||||
if (auto litExpr =
|
||||
dyn_cast<clang::CXXBoolLiteralExpr>(clangAttr->getCond())) {
|
||||
if (litExpr->getValue()) {
|
||||
thisDeclHasPreferredOverload = hasPreferredOverload = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!thisDeclHasPreferredOverload)
|
||||
declsToRemove.insert(decl);
|
||||
} else
|
||||
declsToRemove.insert(decl);
|
||||
}
|
||||
|
||||
if (hasPreferredOverload) {
|
||||
decls.erase(std::remove_if(decls.begin() + initialCount, decls.end(),
|
||||
[&](ValueDecl *d) -> bool {
|
||||
return declsToRemove.contains(d);
|
||||
}),
|
||||
decls.end());
|
||||
}
|
||||
|
||||
// Remove duplicated declarations, which can happen when the same module is
|
||||
// imported with multiple access paths.
|
||||
llvm::SmallPtrSet<ValueDecl *, 4> knownDecls;
|
||||
|
||||
Reference in New Issue
Block a user