Skip to content

[Clang] Implement CWG2517 Useless restriction on use of parameter in constraint-expression #132919

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
3 changes: 3 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,9 @@ Resolutions to C++ Defect Reports
- Bumped the ``__cpp_constexpr`` feature-test macro to ``202002L`` in C++20 mode as indicated in
`P2493R0 <https://wg21.link/P2493R0>`_.

- Implemented `CWG2517 Useless restriction on use of parameter in `
`constraint-expression <https://cplusplus.github.io/CWG/issues/2517.html>`_.

C Language Changes
------------------

Expand Down
11 changes: 0 additions & 11 deletions clang/lib/Sema/SemaExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -396,17 +396,6 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, ArrayRef<SourceLocation> Locs,
targetDiag(*Locs.begin(), diag::err_thread_unsupported);
}

if (isa<ParmVarDecl>(D) && isa<RequiresExprBodyDecl>(D->getDeclContext()) &&
!isUnevaluatedContext()) {
// C++ [expr.prim.req.nested] p3
// A local parameter shall only appear as an unevaluated operand
// (Clause 8) within the constraint-expression.
Diag(Loc, diag::err_requires_expr_parameter_referenced_in_evaluated_context)
<< D;
Diag(D->getLocation(), diag::note_entity_declared_at) << D;
return true;
}

return false;
}

Expand Down
20 changes: 20 additions & 0 deletions clang/test/CXX/drs/cwg25xx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,26 @@ enum E2 : S<E2>::I { e };
#endif
} // namespace cwg2516

namespace cwg2517 { // cwg2517: 21
#if __cplusplus >= 202302L
template<typename ArrayType>
concept LargeArray = requires (ArrayType my_array) {
requires my_array.size() > 5;
};
Comment on lines +38 to +40
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we have a test for the cases where the expression is not a constant expression?

Copy link
Contributor Author

@imdj imdj Mar 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would this be covered by the tests we updated in nested-requirement.cpp? Please let me know what you think or your suggestions since I'm not very experienced here.

template<typename T>
concept C2 = requires (T a) {
requires sizeof(a) == 4; // OK
requires a == 0; // expected-error{{substitution into constraint expression resulted in a non-constant expression}}
// expected-note@-1{{while checking the satisfaction of nested requirement requested here}}
// expected-note@-2{{in instantiation of requirement here}}
// expected-note@-3{{while checking the satisfaction of nested requirement requested here}}
// expected-note@-6{{while substituting template arguments into constraint expression here}}
// expected-note@-5{{function parameter 'a' with unknown value cannot be used in a constant expression}}
// expected-note@-8{{declared here}}
};
static_assert(C2<int>); // expected-error{{static assertion failed}}
// expected-note@-1{{while checking the satisfaction of concept 'C2<int>' requested here}}
// expected-note@-2{{because 'int' does not satisfy 'C2'}}


struct Big {
constexpr int size() const { return 100; }
};

struct Small {
constexpr int size() const { return 3; }
};

static_assert(LargeArray<Big>);
static_assert(!LargeArray<Small>);
#endif
} // namespace cwg2517

namespace cwg2518 { // cwg2518: 17

#if __cplusplus >= 201103L
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,6 @@ namespace std_example {
static_assert(D<T1>);
template<D T> struct D_check {}; // expected-note{{because 'short' does not satisfy 'D'}}
using dc1 = D_check<short>; // expected-error{{constraints not satisfied for class template 'D_check' [with T = short]}}

template<typename T>
concept C2 = requires (T a) {
requires sizeof(a) == 4; // OK
requires a == 0; // expected-note{{because 'a == 0' would be invalid: constraint variable 'a' cannot be used in an evaluated context}}
};
static_assert(C2<int>); // expected-note{{because 'int' does not satisfy 'C2'}} expected-error{{static assertion failed}}
}

template<typename T>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,13 +98,6 @@ namespace std_example {
using c1c2 = C_check<int *>; // expected-error{{constraints not satisfied for class template 'C_check' [with T = int *]}}
}

// typeid() of an expression becomes potentially evaluated if the expression is
// of a polymorphic type.
class X { virtual ~X(); };
constexpr bool b = requires (X &x) { static_cast<int(*)[(typeid(x), 0)]>(nullptr); };
// expected-error@-1{{constraint variable 'x' cannot be used in an evaluated context}}
// expected-note@-2{{'x' declared here}}

namespace access_checks {
namespace in_requires_expression {
template<auto>
Expand Down
2 changes: 1 addition & 1 deletion clang/www/cxx_dr_status.html
Original file line number Diff line number Diff line change
Expand Up @@ -14937,7 +14937,7 @@ <h2 id="cxxdr">C++ defect report implementation status</h2>
<td><a href="https://cplusplus.github.io/CWG/issues/2517.html">2517</a></td>
<td>C++23</td>
<td>Useless restriction on use of parameter in <I>constraint-expression</I></td>
<td class="unknown" align="center">Unknown</td>
<td class="unreleased" align="center">Clang 21</td>
</tr>
<tr id="2518">
<td><a href="https://cplusplus.github.io/CWG/issues/2518.html">2518</a></td>
Expand Down
Loading