Pass the found declaration to DiagnoseUseOfDecl.

Don't pass in the resolved declaration, because that might be an
inheriting constructor declaration, which should never be used directly
and for which constraint satisfaction checking doesn't work.

Fixes #62361.
This commit is contained in:
Richard Smith 2023-04-26 16:53:34 -07:00
parent 919382004f
commit 1e43349e32
2 changed files with 72 additions and 4 deletions

View File

@ -6885,7 +6885,7 @@ PerformConstructorInitialization(Sema &S,
if (isExplicitTemporary(Entity, Kind, NumArgs)) {
// An explicitly-constructed temporary, e.g., X(1, 2).
if (S.DiagnoseUseOfDecl(Constructor, Loc))
if (S.DiagnoseUseOfDecl(Step.Function.FoundDecl, Loc))
return ExprError();
TypeSourceInfo *TSInfo = Entity.getTypeSourceInfo();
@ -6900,8 +6900,6 @@ PerformConstructorInitialization(Sema &S,
if (auto *Shadow = dyn_cast<ConstructorUsingShadowDecl>(
Step.Function.FoundDecl.getDecl())) {
CalleeDecl = S.findInheritingConstructor(Loc, Constructor, Shadow);
if (S.DiagnoseUseOfDecl(CalleeDecl, Loc))
return ExprError();
}
S.MarkFunctionReferenced(Loc, CalleeDecl);
@ -10608,7 +10606,7 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer(
// Make sure we didn't select an unusable deduction guide, and mark it
// as referenced.
DiagnoseUseOfDecl(Best->Function, Kind.getLocation());
DiagnoseUseOfDecl(Best->FoundDecl, Kind.getLocation());
MarkFunctionReferenced(Kind.getLocation(), Best->Function);
break;
}

View File

@ -0,0 +1,70 @@
// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify %s
namespace GH62361 {
template <typename T, typename U = void*> struct B { // expected-note 14{{candidate}}
B() // expected-note 7{{not viable}}
requires __is_same(T, int); // expected-note 7{{because '__is_same(char, int)' evaluated to false}}
};
template <typename U> struct B<void, U> : B<int, U> {
using B<int, U>::B;
};
template<typename T>
void g(B<T>); // expected-note {{cannot convert}}
void f1() {
B<void> b1;
B<void> b2{};
B<void> b3 = {};
new B<void>{};
new B<void>();
g<void>({});
B<void>{};
B<void>();
}
void f2() {
B<int> b1;
B<int> b2{};
B<int> b3 = {};
new B<int>{};
new B<int>();
g<int>({});
B<int>{};
B<int>();
}
void f3() {
B<char> b1; // expected-error {{no matching constructor}}
B<char> b2{}; // expected-error {{no matching constructor}}
B<char> b3 = {}; // expected-error {{no matching constructor}}
new B<char>{}; // expected-error {{no matching constructor}}
new B<char>(); // expected-error {{no matching constructor}}
g<char>({}); // expected-error {{no matching function}}
B<char>{}; // expected-error {{no matching constructor}}
B<char>(); // expected-error {{no matching constructor}}
}
}
namespace no_early_substitution {
template <typename T> concept X = true;
struct A {};
template <typename T> struct B {
B() requires X<T*>;
B();
};
template <typename U = int, typename V = A>
struct C : public B<V&> {
using B<V&>::B;
};
void foo() {
// OK, we only substitute T ~> V& into X<T*> in a SFINAE context,
// during satisfaction checks.
C();
}
}