[Concepts] Fix placeholder constraints when references are involved

Placeholder types were not checked for constraint satisfaction when modified by references or pointers.
The behavior now matches that of GCC and MSVC.

Are there other modifiers we might need to "peel"? I'm not sure my approach to this is the 'right' way to fix this, the loop feels a bit clunky.

GitHub issues [[ https://github.com/llvm/llvm-project/issues/54443 | #54443 ]], [[ https://github.com/llvm/llvm-project/issues/53911 | #53911 ]]

Reviewed By: erichkeane

Differential Revision: https://reviews.llvm.org/D122083
This commit is contained in:
Roy Jacobson 2022-03-19 13:26:02 -04:00
parent da167a53c8
commit 94fd00f41e
3 changed files with 51 additions and 12 deletions

View File

@ -65,6 +65,10 @@ Bug Fixes
fixes `Issue 53044 <https://github.com/llvm/llvm-project/issues/53044>`_.
- Allow `-Wno-gnu` to silence GNU extension diagnostics for pointer arithmetic
diagnostics. Fixes `Issue 54444 <https://github.com/llvm/llvm-project/issues/54444>`_.
- Placeholder constraints, as in `Concept auto x = f();`, were not checked when modifiers
like ``auto&`` or ``auto**`` were added. These constraints are now checked.
This fixes `Issue 53911 <https://github.com/llvm/llvm-project/issues/53911>`_
and `Issue 54443 <https://github.com/llvm/llvm-project/issues/54443>`_.
Improvements to Clang's diagnostics
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

View File

@ -4769,12 +4769,13 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result,
return DAR_FailedAlreadyDiagnosed;
}
if (const auto *AT = Type.getType()->getAs<AutoType>()) {
QualType MaybeAuto = Type.getType().getNonReferenceType();
while (MaybeAuto->isPointerType())
MaybeAuto = MaybeAuto->getPointeeType();
if (const auto *AT = MaybeAuto->getAs<AutoType>()) {
if (AT->isConstrained() && !IgnoreConstraints) {
auto ConstraintsResult =
CheckDeducedPlaceholderConstraints(*this, *AT,
Type.getContainedAutoTypeLoc(),
DeducedType);
auto ConstraintsResult = CheckDeducedPlaceholderConstraints(
*this, *AT, Type.getContainedAutoTypeLoc(), DeducedType);
if (ConstraintsResult != DAR_Succeeded)
return ConstraintsResult;
}

View File

@ -171,7 +171,7 @@ namespace PR50561 {
}
namespace PR49188 {
template<class T> concept C = false; // expected-note 6 {{because 'false' evaluated to false}}
template<class T> concept C = false; // expected-note 7 {{because 'false' evaluated to false}}
C auto f1() { // expected-error {{deduced type 'void' does not satisfy 'C'}}
return void();
@ -189,7 +189,7 @@ namespace PR49188 {
}
C decltype(auto) f6() { // expected-error {{deduced type 'void' does not satisfy 'C'}}
}
C auto& f7() { // expected-error {{cannot form a reference to 'void'}}
C auto& f7() { // expected-error {{deduced type 'void' does not satisfy 'C'}}
return void();
}
C auto& f8() {
@ -199,13 +199,16 @@ namespace PR49188 {
}
}
namespace PR53911 {
template<class T> concept C = false;
template<class T> concept C = false; // expected-note 3 {{because 'false' evaluated to false}}
C auto *f1() {
return (void*)nullptr; // FIXME: should error
C auto *f1() { // expected-error {{deduced type 'void' does not satisfy 'C'}}
return (void*)nullptr;
}
C auto *f2() {
return (int*)nullptr; // FIXME: should error
C auto *f2() { // expected-error {{deduced type 'int' does not satisfy 'C'}}
return (int*)nullptr;
}
C auto *****f3() { // expected-error {{deduced type 'int' does not satisfy 'C'}}
return (int*****)nullptr;
}
}
@ -222,3 +225,34 @@ struct B {
};
void (*f2)() = B::f; // expected-error {{address of overloaded function 'f' does not match required type}}
}
namespace PR54443 {
template <class T, class U>
struct is_same { static constexpr bool value = false; };
template <class T>
struct is_same<T, T> { static constexpr bool value = true; };
template <class T, class U>
concept same_as = is_same<T, U>::value; // expected-note-re 4 {{because {{.*}} evaluated to false}}
int const &f();
same_as<int const> auto i1 = f(); // expected-error {{deduced type 'int' does not satisfy 'same_as<const int>'}}
same_as<int const> auto &i2 = f();
same_as<int const> auto &&i3 = f(); // expected-error {{deduced type 'const int &' does not satisfy 'same_as<const int>'}}
same_as<int const &> auto i4 = f(); // expected-error {{deduced type 'int' does not satisfy 'same_as<const int &>'}}
same_as<int const &> auto &i5 = f(); // expected-error {{deduced type 'const int' does not satisfy 'same_as<const int &>'}}
same_as<int const &> auto &&i6 = f();
template <class T>
concept C = false; // expected-note 3 {{because 'false' evaluated to false}}
int **const &g();
C auto **j1 = g(); // expected-error {{deduced type 'int' does not satisfy 'C'}}
C auto **&j2 = g(); // expected-error {{deduced type 'int' does not satisfy 'C'}}
C auto **&&j3 = g(); // expected-error {{deduced type 'int' does not satisfy 'C'}}
}