-
Notifications
You must be signed in to change notification settings - Fork 13.6k
[clang] Fix the local parameter of void type inside the Requires
expression.
#109831
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
Conversation
@llvm/pr-subscribers-clang Author: None (c8ef) ChangesFixes #109538. In this patch, we introduce diagnostic for required expression parameters in the same way as function parameters, fix the issue of handling void type parameters, and align the behavior with GCC and other compilers. Full diff: https://github.com/llvm/llvm-project/pull/109831.diff 2 Files Affected:
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index ac3fe6ab8f9bd0..d0914d990be6a7 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -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);
+ Body->setInvalidDecl();
+ } else if (Param->getIdentifier()) {
+ Diag(Param->getBeginLoc(), diag::err_param_with_void_type);
+ Body->setInvalidDecl();
+ } else if (Param->getType().hasQualifiers()) {
+ Diag(Param->getBeginLoc(), diag::err_void_param_qualified);
+ Body->setInvalidDecl();
+ }
+ }
+
if (Param->hasDefaultArg())
// C++2a [expr.prim.req] p4
// [...] A local parameter of a requires-expression shall not have a
diff --git a/clang/test/SemaCXX/invalid-requirement-requires-parameter.cpp b/clang/test/SemaCXX/invalid-requirement-requires-parameter.cpp
new file mode 100644
index 00000000000000..01aa0ca4d229b5
--- /dev/null
+++ b/clang/test/SemaCXX/invalid-requirement-requires-parameter.cpp
@@ -0,0 +1,15 @@
+// RUN: %clang -fsyntax-only -std=c++2a -Xclang -verify %s
+
+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
|
CC @erichkeane @zyn0217, since I do not have permission to request reviewers. |
clang/lib/Sema/SemaExprCXX.cpp
Outdated
if (Param->getType()->isVoidType()) { | ||
if (LocalParameters.size() > 1) { | ||
Diag(Param->getBeginLoc(), diag::err_void_only_param); | ||
Body->setInvalidDecl(); | ||
} else if (Param->getIdentifier()) { | ||
Diag(Param->getBeginLoc(), diag::err_param_with_void_type); | ||
Body->setInvalidDecl(); | ||
} else if (Param->getType().hasQualifiers()) { | ||
Diag(Param->getBeginLoc(), diag::err_void_param_qualified); | ||
Body->setInvalidDecl(); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we unify these with the parameter type checks in SemaType?
Also, it would make sense to perform the same error recovery here, which is to just adjust these parameter types
to int
, or perhaps some other error recovery, but consistently between requires local parameters and function parameters.
I don't think it's helpful to mark the requires body as invalid, but in some scenarios we can mark the parameter itself as invalid, if needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are you suggesting unifying the parameter type check for void type only or for all parameters? As I understand it, the complete parameter check involves a lot more branches, such as support for objc, opencl, etc. It appears challenging to merge these two aspects seamlessly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the invalidity of the Decl should be used to indicate the "unsatisfied" flag such that the constant expression would result in a false value. That said, marking the parameters as invalid should also work.
Note that we don't seem ever to use the invalid flag. I think you need to examine that flag in RequiresExpr
's constructor.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done. The required expression will now evaluate to false if it has an incorrect void parameter now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There should be a release note :)
I think I agree with @mizvekov's idea of merging the parameter checks into SemaType; we can probably in part reuse GetTypeForDeclarator. I would appreciate it if we can see some exploration here.
Another thing is that we need to make sure the values of such require expressions are false, aligning with other compilers.
@@ -0,0 +1,15 @@ | |||
// RUN: %clang -fsyntax-only -std=c++2a -Xclang -verify %s |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you move the test to clang/test/CXX/expr/expr.prim/expr.prim.req/requires-expr.cpp
? I don't think this issue merits a new one
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will do it later :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
Apologies for the delayed response. The implementation I provided is actually derived from |
You can perhaps extract just the parts that are common between both use cases into a separate function, or another possible approach would be to reuse the whole thing, but then add an extra mode parameter which turns off some checks for the requires local parameters. |
After spending the entire afternoon attempting to streamline the parameter check process, I still haven't found an elegant solution to consolidate it into a single location. I explored how GCC approaches this issue and discovered that while GCC does utilize a single parameter check function (specifically in the Upon examining the actual parameter checking process, it seems that the most crucial check related to require-expressions is for void types. Other checks are mainly for OpenCL, Objective-C, etc. Merging these checks for just a single void check might be overkill. llvm-project/clang/lib/Sema/SemaType.cpp Lines 5143 to 5236 in 75e08a5
Therefore, I recommend adding the void parameter check directly into Additionally, there appears to be some overlap between the parameter checks in llvm-project/clang/lib/Sema/SemaType.cpp Lines 2637 to 2660 in 75e08a5
|
That works for me if it turns out to take much more effort than our anticipation, although it's really a shame for us to end up strewing the check three times. |
Same then, go ahead, but please make sure the error handling strategies don't diverge unnecessarily. |
I have another simple question: If an explicit-object-parameter-declaration appears in the parameter list, should the requires expression evaluate to false? All three compilers I've tested seem to evaluate it to true, but I'm unsure if this is the correct behavior.
https://gcc.godbolt.org/z/9Pajb5G9s (This issue arises when I attempt to merge this diagnostic into |
The grammar doesn't appear to disallow the explicit object parameter in a requires expression, see https://eel.is/c++draft/expr.prim.req#nt:requirement-parameter-list. But the usage is indeed suspicious to me. We probably need a CWG issue? @cor3ntin @mizvekov |
See also: #88974 |
Done. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes sense to me. Thanks
Please wait for other folks a day or two in case they have different opinions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, Thanks!
Thank you all for reviewing! If this patch looks good, could someone help me land it? |
…ssion parameter. (#110773) This patch is a follow-up to #109831. In the discussion, we agreed that having parameter checks scattered across different areas isn't ideal. Therefore, I suggest merging the check from #88974 into the void parameter check. This change won't impact functionality and will enhance maintainability.
…pression. (llvm#109831) Fixes llvm#109538. In this patch, we introduce diagnostic for required expression parameters in the same way as function parameters, fix the issue of handling void type parameters, and align the behavior with GCC and other compilers.
…ssion parameter. (llvm#110773) This patch is a follow-up to llvm#109831. In the discussion, we agreed that having parameter checks scattered across different areas isn't ideal. Therefore, I suggest merging the check from llvm#88974 into the void parameter check. This change won't impact functionality and will enhance maintainability.
Fixes #109538.
In this patch, we introduce diagnostic for required expression parameters in the same way as function parameters, fix the issue of handling void type parameters, and align the behavior with GCC and other compilers.