-
Notifications
You must be signed in to change notification settings - Fork 10.8k
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
[Sema] -Wpointer-bool-conversion: suppress lambda function pointer conversion diagnostic during instantiation #83497
Conversation
Created using spr 1.3.4
@llvm/pr-subscribers-clang Author: Fangrui Song (MaskRay) ChangesI have seen internal pieces of code that uses a template type parameter template <typename... Ts>
static bool IsFalse(const Ts&...) { return false; }
template <typename T, typename... Ts,
typename = typename std::enable_if<std::is_constructible<bool, const T&>::value>::type>
static bool IsFalse(const Partial&, const T& p, const Ts&...) {
return p ? false : true;
}
template <typename... Args>
void Init(Args&&... args) {
if (IsFalse(absl::implicit_cast<const typename std::decay<Args>::type&>(
args)...)) {
// A callable object convertible to false is either a null pointer or a
// null functor (e.g., a default-constructed std::function).
empty_ = true;
} else {
empty_ = false;
new (&factory_) Factory(std::forward<Args>(args)...);
}
} Full diff: https://github.com/llvm/llvm-project/pull/83497.diff 2 Files Affected:
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 690bdaa63d058b..3533b5c8e0d235 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -16586,13 +16586,16 @@ void Sema::DiagnoseAlwaysNonNullPointer(Expr *E,
}
// Complain if we are converting a lambda expression to a boolean value
- if (const auto *MCallExpr = dyn_cast<CXXMemberCallExpr>(E)) {
- if (const auto *MRecordDecl = MCallExpr->getRecordDecl();
- MRecordDecl && MRecordDecl->isLambda()) {
- Diag(E->getExprLoc(), diag::warn_impcast_pointer_to_bool)
- << /*LambdaPointerConversionOperatorType=*/3
- << MRecordDecl->getSourceRange() << Range << IsEqual;
- return;
+ // outside of instantiation.
+ if (!inTemplateInstantiation()) {
+ if (const auto *MCallExpr = dyn_cast<CXXMemberCallExpr>(E)) {
+ if (const auto *MRecordDecl = MCallExpr->getRecordDecl();
+ MRecordDecl && MRecordDecl->isLambda()) {
+ Diag(E->getExprLoc(), diag::warn_impcast_pointer_to_bool)
+ << /*LambdaPointerConversionOperatorType=*/3
+ << MRecordDecl->getSourceRange() << Range << IsEqual;
+ return;
+ }
}
}
diff --git a/clang/test/SemaCXX/warn-bool-conversion.cpp b/clang/test/SemaCXX/warn-bool-conversion.cpp
index 9e8cf0e4f8944a..8b1bf80af79d26 100644
--- a/clang/test/SemaCXX/warn-bool-conversion.cpp
+++ b/clang/test/SemaCXX/warn-bool-conversion.cpp
@@ -92,6 +92,19 @@ void foo() {
bool is_true = [](){ return true; };
// expected-warning@-1{{address of lambda function pointer conversion operator will always evaluate to 'true'}}
}
+
+template <typename... Ts>
+static bool IsFalse(const Ts&...) { return false; }
+template <typename T>
+static bool IsFalse(const T& p) {
+ bool b;
+ b = f7; // expected-warning {{address of lambda function pointer conversion operator will always evaluate to 'true'}}
+ return p ? false : true;
+}
+
+bool use_instantiation() {
+ return IsFalse([]() { return 0; });
+}
#endif
void bar() {
|
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 with a minor commenting nit. Thank you for catching this and the quick patch!
static bool IsFalse(const T& p) { | ||
bool b; | ||
b = f7; // expected-warning {{address of lambda function pointer conversion operator will always evaluate to 'true'}} | ||
return p ? false : true; |
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.
return p ? false : true; | |
// Intentionally not warned on because p could be a lambda type in one instantiation, but a pointer | |
// type in another. | |
return p ? false : true; |
(May need to adjust for 80-col limits.)
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.
Thanks for the suggestion! Adjusted to 80-col.
Great catch! The usage of template instantiation didn't seem very obvious while adding the tests, and hence the missed test case. |
Created using spr 1.3.4
Presumably similar things might show up in macros? But can cross that bridge when we come to it. Perhaps we have some/could use some generic utility for this sort of contextual warning "if these things are literally written next to each other, warn, but if they came to be via template instantiation, macro, (something else?) then don't" because that sort of situation shows up pretty regularly in diagnostics, I think... |
I modeled the template instantiation suppression after While some macro uses suppress
some have diagnostics (e.g. https://reviews.llvm.org/D70624). Yes, we can cross that bridge when we come to it. |
I have seen two internal pieces of code that uses a template type
parameter to accept any callable type (function pointer, std::function,
closure type, etc). The diagnostic added in #83152 would require
adaptation to the template, which is difficult and also seems
unnecessary. Example: