|
17 | 17 | #include "swift/AST/NameLookup.h"
|
18 | 18 | #include "swift/AST/NameLookupRequests.h"
|
19 | 19 | #include "swift/Basic/Assertions.h"
|
| 20 | +#include "clang/AST/Attr.h" |
| 21 | +#include "clang/AST/ExprCXX.h" |
20 | 22 | #include "llvm/Support/raw_ostream.h"
|
21 | 23 |
|
22 | 24 | using namespace swift;
|
@@ -278,6 +280,43 @@ void ModuleNameLookup<LookupStrategy>::lookupInModule(
|
278 | 280 | if (decls.size() - initialCount <= 1)
|
279 | 281 | return;
|
280 | 282 |
|
| 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 | + |
281 | 320 | // Remove duplicated declarations, which can happen when the same module is
|
282 | 321 | // imported with multiple access paths.
|
283 | 322 | llvm::SmallPtrSet<ValueDecl *, 4> knownDecls;
|
|
0 commit comments