Revert "[clang] Fix conflicting declaration error with using_if_exists" (#190441)
Reverts llvm/llvm-project#167646
This commit is contained in:
parent
5cd98f966e
commit
3080198cc3
@ -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;
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user