Author: Petr Hosek
Date: 2026-04-03T19:25:34-07:00
New Revision: 3080198cc372da34191c7f4bf21d9c2a9ab18f1a

URL: 
https://github.com/llvm/llvm-project/commit/3080198cc372da34191c7f4bf21d9c2a9ab18f1a
DIFF: 
https://github.com/llvm/llvm-project/commit/3080198cc372da34191c7f4bf21d9c2a9ab18f1a.diff

LOG: Revert "[clang] Fix conflicting declaration error with using_if_exists" 
(#190441)

Reverts llvm/llvm-project#167646

Added: 
    

Modified: 
    clang/lib/Sema/SemaDeclCXX.cpp
    clang/lib/Sema/SemaLookup.cpp
    clang/test/SemaCXX/using-if-exists.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index e6bec8684bc20..c1d3960e65ef6 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -12926,11 +12926,19 @@ bool Sema::CheckUsingShadowDecl(BaseUsingDecl *BUD, 
NamedDecl *Orig,
   if (FoundEquivalentDecl)
     return false;
 
-  // This using_if_exists decl cannot be a subsitute for the original decl,
-  // so do not create a shadow decl for this case.
+  // Always emit a diagnostic for a mismatch between an unresolved
+  // using_if_exists and a resolved using declaration in either direction.
   if (isa<UnresolvedUsingIfExistsDecl>(Target) !=
-      (isa_and_nonnull<UnresolvedUsingIfExistsDecl>(NonTag)))
-    return false;
+      (isa_and_nonnull<UnresolvedUsingIfExistsDecl>(NonTag))) {
+    if (!NonTag && !Tag)
+      return false;
+    Diag(BUD->getLocation(), diag::err_using_decl_conflict);
+    Diag(Target->getLocation(), diag::note_using_decl_target);
+    Diag((NonTag ? NonTag : Tag)->getLocation(),
+         diag::note_using_decl_conflict);
+    BUD->setInvalidDecl();
+    return true;
+  }
 
   if (FunctionDecl *FD = Target->getAsFunction()) {
     NamedDecl *OldDecl = nullptr;

diff  --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp
index ee37415af18a9..b96065f8619d2 100644
--- a/clang/lib/Sema/SemaLookup.cpp
+++ b/clang/lib/Sema/SemaLookup.cpp
@@ -521,15 +521,11 @@ void LookupResult::resolveKind() {
 
   llvm::SmallVector<const NamedDecl *, 4> EquivalentNonFunctions;
   llvm::BitVector RemovedDecls(N);
-  llvm::BitVector UnresolvedUsingDecls(N);
 
   for (unsigned I = 0; I < N; I++) {
     const NamedDecl *D = Decls[I]->getUnderlyingDecl();
     D = cast<NamedDecl>(D->getCanonicalDecl());
 
-    if (isa<UnresolvedUsingIfExistsDecl>(D))
-      UnresolvedUsingDecls.set(I);
-
     // Ignore an invalid declaration unless it's the only one left.
     // Also ignore HLSLBufferDecl which not have name conflict with other 
Decls.
     if ((D->isInvalidDecl() || isa<HLSLBufferDecl>(D)) &&
@@ -637,31 +633,6 @@ void LookupResult::resolveKind() {
     getSema().diagnoseEquivalentInternalLinkageDeclarations(
         getNameLoc(), HasNonFunction, EquivalentNonFunctions);
 
-  // A lookup can be ambiguous if we find multiple declarations that cannot
-  // coexist. This occurs if:
-  //
-  // 1. We have a non-function (like a variable or namespace), which cannot
-  //    be overloaded, and either a function or an unresolved using 
declaration.
-  bool ConflictWithNonFunction =
-      HasNonFunction && (HasFunction || HasUnresolved);
-
-  // 2. We have a hidden tag (struct or enum) and another declaration, and
-  //    Because they both remain in the results, they must be from 
diff erent
-  //    scopes. If they were in the same scope, the tag would have been hidden
-  //    and removed prior.
-  bool HiddenTagConflict =
-      HideTags && HasTag && (HasFunction || HasNonFunction || HasUnresolved);
-
-  if (ConflictWithNonFunction || HiddenTagConflict)
-    Ambiguous = true;
-
-  if (Ambiguous && UnresolvedUsingDecls.count()) {
-    // If we would have an ambiguous reference but any of them are
-    // using_if_exist decls, ignore them since they are unresolved.
-    RemovedDecls |= UnresolvedUsingDecls;
-    Ambiguous = false;
-  }
-
   // Remove decls by replacing them with decls from the end (which
   // means that we need to iterate from the end) and then truncating
   // to the new size.
@@ -669,6 +640,10 @@ void LookupResult::resolveKind() {
     Decls[I] = Decls[--N];
   Decls.truncate(N);
 
+  if ((HasNonFunction && (HasFunction || HasUnresolved)) ||
+      (HideTags && HasTag && (HasFunction || HasNonFunction || HasUnresolved)))
+    Ambiguous = true;
+
   if (Ambiguous && ReferenceToPlaceHolderVariable)
     setAmbiguous(LookupAmbiguityKind::AmbiguousReferenceToPlaceholderVariable);
   else if (Ambiguous)

diff  --git a/clang/test/SemaCXX/using-if-exists.cpp 
b/clang/test/SemaCXX/using-if-exists.cpp
index 5c2ccd997048c..36fbbb171fb9a 100644
--- a/clang/test/SemaCXX/using-if-exists.cpp
+++ b/clang/test/SemaCXX/using-if-exists.cpp
@@ -22,28 +22,28 @@ using NS::x UIE;
 namespace NS1 {}
 namespace NS2 {}
 namespace NS3 {
-int A();
-struct B {};
-int C();
-struct D {};
+int A();     // expected-note{{target of using declaration}}
+struct B {}; // expected-note{{target of using declaration}}
+int C();     // expected-note{{conflicting declaration}}
+struct D {}; // expected-note{{conflicting declaration}}
 } // namespace NS3
 
-using NS1::A UIE; // OK since this declaration shouldn't exist since `A` is 
not in `NS1` 
-using NS2::A UIE; // OK since this declaration shouldn't exist since `A` is 
not in `NS2` 
-using NS3::A UIE; // OK since prior UIEs of `A` shouldn't have declare 
anything since they don't exist
-int i = A();      // OK since `A` resolved to the single UIE in the previous 
line
+using NS1::A UIE;
+using NS2::A UIE; // expected-note{{using declaration annotated with 
'using_if_exists' here}} expected-note{{conflicting declaration}}
+using NS3::A UIE; // expected-error{{target of using declaration conflicts 
with declaration already in scope}}
+int i = A();      // expected-error{{reference to unresolved using 
declaration}}
 
-using NS1::B UIE; // OK since this declaration shouldn't exist since `B` is 
not in `NS1`
-using NS2::B UIE; // OK since this declaration shouldn't exist since `B` is 
not in `NS2 
-using NS3::B UIE; // OK since prior UIEs of `B` shouldn't have declare 
anything since they don't exist
-B myB;            // OK since `B` resolved to the single UIE in the previous 
line
+using NS1::B UIE;
+using NS2::B UIE; // expected-note{{conflicting declaration}} 
expected-note{{using declaration annotated with 'using_if_exists' here}}
+using NS3::B UIE; // expected-error{{target of using declaration conflicts 
with declaration already in scope}}
+B myB;            // expected-error{{reference to unresolved using 
declaration}}
 
 using NS3::C UIE;
-using NS2::C UIE; // OK since NS2::C doesn't exist
+using NS2::C UIE; // expected-error{{target of using declaration conflicts 
with declaration already in scope}} expected-note{{target of using declaration}}
 int j = C();
 
 using NS3::D UIE;
-using NS2::D UIE; // OK since NS2::D doesn't exist
+using NS2::D UIE; // expected-error{{target of using declaration conflicts 
with declaration already in scope}} expected-note{{target of using declaration}}
 D myD;
 } // namespace test_redecl
 
@@ -113,12 +113,7 @@ struct NonDep : BaseEmpty {
 namespace test_using_pack {
 template <class... Ts>
 struct S : Ts... {
-  // We don't expect any errors with conflicting targets for variables `a`, 
`b`, `c`,
-  // and `d` below this. For `a`, `x` will not be declared because neither E1 
nor E2
-  // defines it. For `b`, `x` is the same type so there won't be any 
conflicts. For
-  // `c` and `d`, only one of the template parameters has a class that defines 
it,
-  // so there's no conflict.
-  using typename Ts::x... UIE;
+  using typename Ts::x... UIE; // expected-error 2 {{target of using 
declaration conflicts with declaration already in scope}} 
expected-note{{conflicting declaration}} expected-note{{target of using 
declaration}}
 };
 
 struct E1 {};
@@ -126,23 +121,21 @@ struct E2 {};
 S<E1, E2> a;
 
 struct F1 {
-  typedef int x;
+  typedef int x; // expected-note 2 {{conflicting declaration}}
 };
 struct F2 {
-  typedef int x;
+  typedef int x; // expected-note 2 {{target of using declaration}}
 };
 S<F1, F2> b;
 
-S<E1, F2> c;
-S<F1, E2> d;
+S<E1, F2> c; // expected-note{{in instantiation of template class}}
+S<F1, E2> d; // expected-note{{in instantiation of template class}}
 
 template <class... Ts>
 struct S2 : Ts... {
-  // OK for the same reasons listed in `struct S` above. We don't expect any 
conflicts w.r.t
-  // redefinitions of `x` but we still expect errors when using `x` for cases 
it's not available.
-  using typename Ts::x... UIE; // expected-note 4 {{using declaration 
annotated with 'using_if_exists' here}}
+  using typename Ts::x... UIE; // expected-error 2 {{target of using 
declaration conflicts with declaration already in scope}} expected-note 3 
{{using declaration annotated with 'using_if_exists' here}} 
expected-note{{conflicting declaration}} expected-note{{target of using 
declaration}}
 
-  x mem(); // expected-error 4 {{reference to unresolved using declaration}}
+  x mem(); // expected-error 3 {{reference to unresolved using declaration}}
 };
 
 S2<E1, E2> e; // expected-note{{in instantiation of template class}}
@@ -152,15 +145,14 @@ S2<F1, E2> h; // expected-note{{in instantiation of 
template class}}
 
 template <class... Ts>
 struct S3 : protected Ts... {
-  // No errors for conflicting declarations because only one of the parent 
classes declares `m`.
-  using Ts::m... UIE;
+  using Ts::m... UIE; // expected-error{{target of using declaration conflicts 
with declaration already in scope}} expected-note{{target of using declaration}}
 };
 struct B1 {
-  enum { m };
+  enum { m }; // expected-note{{conflicting declaration}}
 };
 struct B2 {};
 
-S3<B1, B2> i;
+S3<B1, B2> i; // expected-note{{in instantiation of template}}
 S<B2, B1> j;
 
 } // namespace test_using_pack
@@ -178,9 +170,9 @@ NS2::x y; // expected-error {{reference to unresolved using 
declaration}}
 } // namespace test_nested
 
 namespace test_scope {
-int x;
+int x; // expected-note{{conflicting declaration}}
 void f() {
-  int x;
+  int x; // expected-note{{conflicting declaration}}
   {
     using ::x UIE; // expected-note {{using declaration annotated with 
'using_if_exists' here}}
     (void)x;       // expected-error {{reference to unresolved using 
declaration}}
@@ -188,13 +180,13 @@ void f() {
 
   {
     using test_scope::x;
-    using ::x UIE; // OK since there's no `x` in the global namespace, so this 
wouldn't be any declaration
+    using ::x UIE; // expected-error{{target of using declaration conflicts 
with declaration already in scope}} expected-note{{target of using declaration}}
     (void)x;
   }
 
   (void)x;
 
-  using ::x UIE; // OK since there's no `x` in the global namespace, so this 
wouldn't be any declaration
+  using ::x UIE; // expected-error{{target of using declaration conflicts with 
declaration already in scope}} expected-note{{target of using declaration}}
   (void)x;
 }
 } // namespace test_scope
@@ -232,20 +224,3 @@ int main() {
   size = fake_printf();
   size = std::fake_printf();
 }
-
-// Regression test for https://github.com/llvm/llvm-project/issues/85335.
-// No errors should be reported here.
-namespace PR85335 {
-void foo();
-
-namespace N {
-  void bar();
-
-  using ::foo __attribute__((__using_if_exists__));
-  using ::bar __attribute__((__using_if_exists__));
-}
-
-void baz() {
-  N::bar();
-}
-}  // namespace PR85335


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to