Index: clang/include/clang/Sema/Sema.h =================================================================== --- clang/include/clang/Sema/Sema.h +++ clang/include/clang/Sema/Sema.h @@ -4252,8 +4252,8 @@ = NotForRedeclaration); bool LookupBuiltin(LookupResult &R); void LookupNecessaryTypesForBuiltin(Scope *S, unsigned ID); - bool LookupName(LookupResult &R, Scope *S, - bool AllowBuiltinCreation = false); + bool LookupName(LookupResult &R, Scope *S, bool AllowBuiltinCreation = false, + bool ForceNoCPlusPlus = false); bool LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, bool InUnqualifiedLookup = false); bool LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, Index: clang/lib/Sema/SemaLookup.cpp =================================================================== --- clang/lib/Sema/SemaLookup.cpp +++ clang/lib/Sema/SemaLookup.cpp @@ -1931,13 +1931,14 @@ /// used to diagnose ambiguities. /// /// @returns \c true if lookup succeeded and false otherwise. -bool Sema::LookupName(LookupResult &R, Scope *S, bool AllowBuiltinCreation) { +bool Sema::LookupName(LookupResult &R, Scope *S, bool AllowBuiltinCreation, + bool ForceNoCPlusPlus) { DeclarationName Name = R.getLookupName(); if (!Name) return false; LookupNameKind NameKind = R.getLookupKind(); - if (!getLangOpts().CPlusPlus) { + if (!getLangOpts().CPlusPlus || ForceNoCPlusPlus) { // Unqualified name lookup in C/Objective-C is purely lexical, so // search in the declarations attached to the name. if (NameKind == Sema::LookupRedeclarationWithLinkage) { Index: clang/unittests/Sema/CMakeLists.txt =================================================================== --- clang/unittests/Sema/CMakeLists.txt +++ clang/unittests/Sema/CMakeLists.txt @@ -7,6 +7,7 @@ ExternalSemaSourceTest.cpp CodeCompleteTest.cpp GslOwnerPointerInference.cpp + SemaLookupTest.cpp ) clang_target_link_libraries(SemaTests Index: clang/unittests/Sema/SemaLookupTest.cpp =================================================================== --- /dev/null +++ clang/unittests/Sema/SemaLookupTest.cpp @@ -0,0 +1,60 @@ +#include "clang/AST/DeclarationName.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Frontend/FrontendAction.h" +#include "clang/Parse/ParseAST.h" +#include "clang/Sema/Lookup.h" +#include "clang/Sema/Sema.h" +#include "clang/Tooling/Tooling.h" +#include "gtest/gtest.h" + +using namespace llvm; +using namespace clang; +using namespace clang::tooling; + +namespace { + +class LookupAction : public ASTFrontendAction { + std::unique_ptr + CreateASTConsumer(CompilerInstance &CI, StringRef /*Unused*/) override { + return std::make_unique(); + } + + void ExecuteAction() override { + CompilerInstance &CI = getCompilerInstance(); + ASSERT_FALSE(CI.hasSema()); + CI.createSema(getTranslationUnitKind(), nullptr); + ASSERT_TRUE(CI.hasSema()); + Sema &S = CI.getSema(); + ParseAST(S); + + ASTContext &Ctx = S.getASTContext(); + auto Name = &Ctx.Idents.get("Foo"); + LookupResult R_cpp(S, Name, SourceLocation(), Sema::LookupOrdinaryName); + S.LookupName(R_cpp, S.TUScope, /*AllowBuiltinCreation=*/false, + /*ForceNoCPlusPlus=*/false); + // By this point, parsing is done and S.TUScope is nullptr + // CppLookupName will perform an early return with no results if the Scope + // we pass in is nullptr. We expect to find nothing. + ASSERT_TRUE(R_cpp.empty()); + + // On the other hand, the non-C++ path doesn't care if the Scope passed in + // is nullptr. We'll force the non-C++ path with a flag. + LookupResult R_nocpp(S, Name, SourceLocation(), Sema::LookupOrdinaryName); + S.LookupName(R_nocpp, S.TUScope, /*AllowBuiltinCreation=*/false, + /*ForceNoCPlusPlus=*/true); + ASSERT_TRUE(!R_nocpp.empty()); + } +}; + +TEST(SemaLookupTest, ForceNoCPlusPlusPath) { + const char *file_contents = R"objcxx( +@protocol Foo +@end +@interface Foo +@end + )objcxx"; + ASSERT_TRUE(runToolOnCodeWithArgs(std::make_unique(), + file_contents, {"-x", "objective-c++"}, + "test.mm")); +} +} // namespace