Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,8 @@ Improvements to Clang's diagnostics

- Clang now diagnoses cases where a dangling ``GSLOwner<GSLPointer>`` object is constructed, e.g. ``std::vector<string_view> v = {std::string()};`` (#GH100526).

- Clang now diagnoses when a ``requires`` expression has a local parameter of void type, aligning with the function parameter (#GH109831).

Improvements to Clang's time-trace
----------------------------------

Expand Down
4 changes: 4 additions & 0 deletions clang/lib/AST/ExprConcepts.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,10 @@ RequiresExpr::RequiresExpr(ASTContext &C, SourceLocation RequiresKWLoc,
std::copy(Requirements.begin(), Requirements.end(),
getTrailingObjects<concepts::Requirement *>());
RequiresExprBits.IsSatisfied |= Dependent;
RequiresExprBits.IsSatisfied &=
llvm::none_of(LocalParameters, [](const ParmVarDecl *Param) {
return Param->isInvalidDecl();
});
// FIXME: move the computing dependency logic to ComputeDependence.h
if (ContainsUnexpandedParameterPack)
setDependence(getDependence() | ExprDependence::UnexpandedPack);
Expand Down
13 changes: 13 additions & 0 deletions clang/lib/Sema/SemaExprCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9509,6 +9509,19 @@ Sema::ActOnStartRequiresExpr(SourceLocation RequiresKWLoc,
PushDeclContext(BodyScope, Body);

for (ParmVarDecl *Param : LocalParameters) {
if (Param->getType()->isVoidType()) {
if (LocalParameters.size() > 1) {
Diag(Param->getBeginLoc(), diag::err_void_only_param);
Param->setInvalidDecl();
} else if (Param->getIdentifier()) {
Diag(Param->getBeginLoc(), diag::err_param_with_void_type);
Param->setInvalidDecl();
} else if (Param->getType().hasQualifiers()) {
Diag(Param->getBeginLoc(), diag::err_void_param_qualified);
Param->setInvalidDecl();
}
}

if (Param->hasDefaultArg())
// C++2a [expr.prim.req] p4
// [...] A local parameter of a requires-expression shall not have a
Expand Down
16 changes: 15 additions & 1 deletion clang/test/CXX/expr/expr.prim/expr.prim.req/requires-expr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,4 +65,18 @@ template<typename T> requires requires { T::value; S<T>::s; }
struct r4 { };

using r4i = r4<int>;
// expected-error@-1 {{constraints not satisfied for class template 'r4' [with T = int]}}
// expected-error@-1 {{constraints not satisfied for class template 'r4' [with T = int]}}

namespace GH109538 {
static_assert(requires(void *t) { t; });
static_assert(requires(void) { 42; });
static_assert(!requires(void t) { // expected-error {{argument may not have 'void' type}}
t;
});
static_assert(!requires(void t, int a) { // expected-error {{'void' must be the first and only parameter if specified}}
t;
});
static_assert(!requires(const void) { // expected-error {{'void' as parameter must not have type qualifiers}}
42;
});
} // namespace GH109538
Loading