forked from OSchip/llvm-project
Specialize noreturn diagnostics for lambda expressions.
llvm-svn: 150586
This commit is contained in:
parent
85dae892a4
commit
cf11eb76ed
|
@ -4045,6 +4045,14 @@ let CategoryName = "Lambda Issue" in {
|
||||||
def ext_lambda_default_arguments : ExtWarn<
|
def ext_lambda_default_arguments : ExtWarn<
|
||||||
"C++11 forbids default arguments for lambda expressions">,
|
"C++11 forbids default arguments for lambda expressions">,
|
||||||
InGroup<LambdaExtensions>;
|
InGroup<LambdaExtensions>;
|
||||||
|
def err_noreturn_lambda_has_return_expr : Error<
|
||||||
|
"lambda declared 'noreturn' should not return">;
|
||||||
|
def warn_maybe_falloff_nonvoid_lambda : Warning<
|
||||||
|
"control may reach end of non-void lambda">,
|
||||||
|
InGroup<ReturnType>;
|
||||||
|
def warn_falloff_nonvoid_lambda : Warning<
|
||||||
|
"control reaches end of non-void lambda">,
|
||||||
|
InGroup<ReturnType>;
|
||||||
}
|
}
|
||||||
|
|
||||||
def err_operator_arrow_circular : Error<
|
def err_operator_arrow_circular : Error<
|
||||||
|
|
|
@ -218,7 +218,8 @@ struct CheckFallThroughDiagnostics {
|
||||||
unsigned diag_AlwaysFallThrough_HasNoReturn;
|
unsigned diag_AlwaysFallThrough_HasNoReturn;
|
||||||
unsigned diag_AlwaysFallThrough_ReturnsNonVoid;
|
unsigned diag_AlwaysFallThrough_ReturnsNonVoid;
|
||||||
unsigned diag_NeverFallThroughOrReturn;
|
unsigned diag_NeverFallThroughOrReturn;
|
||||||
bool funMode;
|
enum { Function, Block, Lambda } funMode;
|
||||||
|
bool IsLambda;
|
||||||
SourceLocation FuncLoc;
|
SourceLocation FuncLoc;
|
||||||
|
|
||||||
static CheckFallThroughDiagnostics MakeForFunction(const Decl *Func) {
|
static CheckFallThroughDiagnostics MakeForFunction(const Decl *Func) {
|
||||||
|
@ -250,7 +251,7 @@ struct CheckFallThroughDiagnostics {
|
||||||
else
|
else
|
||||||
D.diag_NeverFallThroughOrReturn = 0;
|
D.diag_NeverFallThroughOrReturn = 0;
|
||||||
|
|
||||||
D.funMode = true;
|
D.funMode = Function;
|
||||||
return D;
|
return D;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -266,13 +267,28 @@ struct CheckFallThroughDiagnostics {
|
||||||
diag::err_falloff_nonvoid_block;
|
diag::err_falloff_nonvoid_block;
|
||||||
D.diag_NeverFallThroughOrReturn =
|
D.diag_NeverFallThroughOrReturn =
|
||||||
diag::warn_suggest_noreturn_block;
|
diag::warn_suggest_noreturn_block;
|
||||||
D.funMode = false;
|
D.funMode = Block;
|
||||||
|
return D;
|
||||||
|
}
|
||||||
|
|
||||||
|
static CheckFallThroughDiagnostics MakeForLambda() {
|
||||||
|
CheckFallThroughDiagnostics D;
|
||||||
|
D.diag_MaybeFallThrough_HasNoReturn =
|
||||||
|
diag::err_noreturn_lambda_has_return_expr;
|
||||||
|
D.diag_MaybeFallThrough_ReturnsNonVoid =
|
||||||
|
diag::warn_maybe_falloff_nonvoid_lambda;
|
||||||
|
D.diag_AlwaysFallThrough_HasNoReturn =
|
||||||
|
diag::err_noreturn_lambda_has_return_expr;
|
||||||
|
D.diag_AlwaysFallThrough_ReturnsNonVoid =
|
||||||
|
diag::warn_falloff_nonvoid_lambda;
|
||||||
|
D.diag_NeverFallThroughOrReturn = 0;
|
||||||
|
D.funMode = Lambda;
|
||||||
return D;
|
return D;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool checkDiagnostics(DiagnosticsEngine &D, bool ReturnsVoid,
|
bool checkDiagnostics(DiagnosticsEngine &D, bool ReturnsVoid,
|
||||||
bool HasNoReturn) const {
|
bool HasNoReturn) const {
|
||||||
if (funMode) {
|
if (funMode == Function) {
|
||||||
return (ReturnsVoid ||
|
return (ReturnsVoid ||
|
||||||
D.getDiagnosticLevel(diag::warn_maybe_falloff_nonvoid_function,
|
D.getDiagnosticLevel(diag::warn_maybe_falloff_nonvoid_function,
|
||||||
FuncLoc) == DiagnosticsEngine::Ignored)
|
FuncLoc) == DiagnosticsEngine::Ignored)
|
||||||
|
@ -284,9 +300,9 @@ struct CheckFallThroughDiagnostics {
|
||||||
== DiagnosticsEngine::Ignored);
|
== DiagnosticsEngine::Ignored);
|
||||||
}
|
}
|
||||||
|
|
||||||
// For blocks.
|
// For blocks / lambdas.
|
||||||
return ReturnsVoid && !HasNoReturn
|
return ReturnsVoid && !HasNoReturn
|
||||||
&& (!ReturnsVoid ||
|
&& ((funMode == Lambda) ||
|
||||||
D.getDiagnosticLevel(diag::warn_suggest_noreturn_block, FuncLoc)
|
D.getDiagnosticLevel(diag::warn_suggest_noreturn_block, FuncLoc)
|
||||||
== DiagnosticsEngine::Ignored);
|
== DiagnosticsEngine::Ignored);
|
||||||
}
|
}
|
||||||
|
@ -888,7 +904,11 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P,
|
||||||
if (P.enableCheckFallThrough) {
|
if (P.enableCheckFallThrough) {
|
||||||
const CheckFallThroughDiagnostics &CD =
|
const CheckFallThroughDiagnostics &CD =
|
||||||
(isa<BlockDecl>(D) ? CheckFallThroughDiagnostics::MakeForBlock()
|
(isa<BlockDecl>(D) ? CheckFallThroughDiagnostics::MakeForBlock()
|
||||||
: CheckFallThroughDiagnostics::MakeForFunction(D));
|
: (isa<CXXMethodDecl>(D) &&
|
||||||
|
cast<CXXMethodDecl>(D)->getOverloadedOperator() == OO_Call &&
|
||||||
|
cast<CXXMethodDecl>(D)->getParent()->isLambda())
|
||||||
|
? CheckFallThroughDiagnostics::MakeForLambda()
|
||||||
|
: CheckFallThroughDiagnostics::MakeForFunction(D));
|
||||||
CheckFallThroughForBody(S, D, Body, blkExpr, CD, AC);
|
CheckFallThroughForBody(S, D, Body, blkExpr, CD, AC);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1857,12 +1857,18 @@ Sema::ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
|
||||||
QualType FnRetType = CurCap->ReturnType;
|
QualType FnRetType = CurCap->ReturnType;
|
||||||
assert(!FnRetType.isNull());
|
assert(!FnRetType.isNull());
|
||||||
|
|
||||||
if (BlockScopeInfo *CurBlock = dyn_cast<BlockScopeInfo>(CurCap))
|
if (BlockScopeInfo *CurBlock = dyn_cast<BlockScopeInfo>(CurCap)) {
|
||||||
if (CurBlock->FunctionType->getAs<FunctionType>()->getNoReturnAttr()) {
|
if (CurBlock->FunctionType->getAs<FunctionType>()->getNoReturnAttr()) {
|
||||||
Diag(ReturnLoc, diag::err_noreturn_block_has_return_expr);
|
Diag(ReturnLoc, diag::err_noreturn_block_has_return_expr);
|
||||||
return StmtError();
|
return StmtError();
|
||||||
}
|
}
|
||||||
// FIXME: [[noreturn]] for lambdas!
|
} else {
|
||||||
|
LambdaScopeInfo *LSI = cast<LambdaScopeInfo>(CurCap);
|
||||||
|
if (LSI->CallOperator->getType()->getAs<FunctionType>()->getNoReturnAttr()){
|
||||||
|
Diag(ReturnLoc, diag::err_noreturn_lambda_has_return_expr);
|
||||||
|
return StmtError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Otherwise, verify that this result type matches the previous one. We are
|
// Otherwise, verify that this result type matches the previous one. We are
|
||||||
// pickier with blocks than for normal functions because we don't have GCC
|
// pickier with blocks than for normal functions because we don't have GCC
|
||||||
|
|
|
@ -3,7 +3,9 @@
|
||||||
// An attribute-specifier-seq in a lambda-declarator appertains to the
|
// An attribute-specifier-seq in a lambda-declarator appertains to the
|
||||||
// type of the corresponding function call operator.
|
// type of the corresponding function call operator.
|
||||||
void test_attributes() {
|
void test_attributes() {
|
||||||
auto nrl = []() [[noreturn]] {}; // expected-warning{{function declared 'noreturn' should not return}}
|
auto nrl = [](int x) -> int { if (x > 0) return x; }; // expected-warning{{control may reach end of non-void lambda}}
|
||||||
|
|
||||||
|
auto nrl2 = []() [[noreturn]] { return; }; // expected-error{{lambda declared 'noreturn' should not return}}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
// Check that analysis-based warnings work in lambda bodies.
|
// Check that analysis-based warnings work in lambda bodies.
|
||||||
void analysis_based_warnings() {
|
void analysis_based_warnings() {
|
||||||
(void)[]() -> int { }; // expected-warning{{control reaches end of non-void function}}
|
(void)[]() -> int { }; // expected-warning{{control reaches end of non-void lambda}}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that we get the right types of captured variables (the
|
// Check that we get the right types of captured variables (the
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void test_attributes() {
|
void test_attributes() {
|
||||||
auto nrl = []() [[noreturn]] {}; // expected-warning{{function declared 'noreturn' should not return}}
|
auto nrl = []() [[noreturn]] {}; // expected-error{{lambda declared 'noreturn' should not return}}
|
||||||
}
|
}
|
||||||
|
|
||||||
template void test_attributes<int>(); // expected-note{{in instantiation of function}}
|
template void test_attributes<int>(); // expected-note{{in instantiation of function}}
|
||||||
|
|
Loading…
Reference in New Issue