llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang Author: Petr Hosek (petrhosek) <details> <summary>Changes</summary> Reverts llvm/llvm-project#<!-- -->167646 --- Full diff: https://github.com/llvm/llvm-project/pull/190441.diff 3 Files Affected: - (modified) clang/lib/Sema/SemaDeclCXX.cpp (+12-4) - (modified) clang/lib/Sema/SemaLookup.cpp (+4-29) - (modified) clang/test/SemaCXX/using-if-exists.cpp (+28-53) ``````````diff 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 different - // 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 `````````` </details> https://github.com/llvm/llvm-project/pull/190441 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
