-
Notifications
You must be signed in to change notification settings - Fork 14.9k
[clang] Check captured variables for noreturn attribute #155213
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
base: main
Are you sure you want to change the base?
Conversation
Anaysis for noreturn attribute now misses the case when an assignment to a variable is made inside a lambda function call. This change fixes that case.
@llvm/pr-subscribers-clang Author: Serge Pavlov (spavloff) ChangesAnaysis for noreturn attribute now misses the case when an assignment to a variable is made inside a lambda function call. This change fixes that case. Full diff: https://github.com/llvm/llvm-project/pull/155213.diff 2 Files Affected:
diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp
index 0b94b1044f072..fe1498003e7da 100644
--- a/clang/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp
@@ -467,6 +467,41 @@ struct TransferFunctions : public StmtVisitor<TransferFunctions> {
AllValuesAreNoReturn = false;
}
}
+
+ void VisitCXXOperatorCallExpr(CXXOperatorCallExpr *CE) {
+ if (CE->getOperator() == OO_Call && CE->getNumArgs() > 0) {
+ Expr *Obj = CE->getArg(0)->IgnoreParenCasts();
+ if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(Obj))
+ Obj = MTE->getSubExpr();
+ if (auto *DRE = dyn_cast<DeclRefExpr>(Obj)) {
+ auto *D = dyn_cast<VarDecl>(DRE->getDecl());
+ if (D->hasInit())
+ Obj = D->getInit();
+ }
+ Visit(Obj);
+ }
+ }
+
+ void VisitLambdaExpr(LambdaExpr *LE) {
+ for (const LambdaCapture &Capture : LE->captures())
+ if (Capture.capturesVariable())
+ if (const VarDecl *VD = dyn_cast<VarDecl>(Capture.getCapturedVar()))
+ if (VD == Var)
+ if (Capture.getCaptureKind() == LCK_ByRef)
+ AllValuesAreNoReturn = false;
+ }
+
+ void VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *MTE) {
+ Visit(MTE->getSubExpr());
+ }
+
+ void VisitExprWithCleanups(FullExpr *FE) {
+ Visit(FE->getSubExpr());
+ }
+
+ void VisitCXXConstructExpr(CXXConstructExpr *CE) {
+ Visit(CE->getArg(0));
+ }
};
} // namespace
diff --git a/clang/test/SemaCXX/noreturn-vars.cpp b/clang/test/SemaCXX/noreturn-vars.cpp
index ca65fcf5ca31d..3b2473c1bc670 100644
--- a/clang/test/SemaCXX/noreturn-vars.cpp
+++ b/clang/test/SemaCXX/noreturn-vars.cpp
@@ -225,3 +225,16 @@ extern void abc_02(func_type *);
abc_02(&func_ptr);
func_ptr();
} // expected-warning {{function declared 'noreturn' should not return}}
+
+[[noreturn]] void test_lambda() {
+ func_type func_ptr = noret;
+ [&func_ptr]() { func_ptr = ordinary; } ();
+ func_ptr();
+} // expected-warning {{function declared 'noreturn' should not return}}
+
+[[noreturn]] void test_lambda_var(int x) {
+ func_type func_ptr = noret;
+ auto LF = [&](){func_ptr = ordinary;};
+ LF();
+ func_ptr();
+} // expected-warning {{function declared 'noreturn' should not return}}
|
You can test this locally with the following command:git-clang-format --diff HEAD~1 HEAD --extensions cpp -- clang/lib/Sema/AnalysisBasedWarnings.cpp clang/test/SemaCXX/noreturn-vars.cpp View the diff from clang-format here.diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp
index fe1498003..e92536b56 100644
--- a/clang/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp
@@ -495,13 +495,9 @@ struct TransferFunctions : public StmtVisitor<TransferFunctions> {
Visit(MTE->getSubExpr());
}
- void VisitExprWithCleanups(FullExpr *FE) {
- Visit(FE->getSubExpr());
- }
+ void VisitExprWithCleanups(FullExpr *FE) { Visit(FE->getSubExpr()); }
- void VisitCXXConstructExpr(CXXConstructExpr *CE) {
- Visit(CE->getArg(0));
- }
+ void VisitCXXConstructExpr(CXXConstructExpr *CE) { Visit(CE->getArg(0)); }
};
} // namespace
|
|
||
[[noreturn]] void test_lambda_var(int x) { | ||
func_type func_ptr = noret; | ||
auto LF = [&](){func_ptr = ordinary;}; |
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.
Would like to see a test for member functions here as well. Also, test that shows capture-by-value doesn't cause this diagnostic.
} | ||
|
||
void VisitCXXConstructExpr(CXXConstructExpr *CE) { | ||
Visit(CE->getArg(0)); |
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.
This doesn't seem right at all. the 'this' argument in a CXXConstructExpr
does NOT get placed in the 0 arg (in fact, they are not present), so you can't assume 0 exists here. AND it isn't really clear why the 0 arg is important here, but others arent?
Anaysis for noreturn attribute now misses the case when an assignment to a variable is made inside a lambda function call. This change fixes that case.