From b2e2c1bd963a262ab00a8c958ac8c3dfc40ff871 Mon Sep 17 00:00:00 2001 From: Aaron Ballman Date: Fri, 24 Oct 2014 13:19:19 +0000 Subject: [PATCH] Report when a function-try-block does not return a value on all control paths. Fixed PR14620. llvm-svn: 220557 --- clang/lib/Sema/AnalysisBasedWarnings.cpp | 65 ++++++++++++++------------------ clang/test/SemaCXX/return-noreturn.cpp | 21 ++++++++++- 2 files changed, 48 insertions(+), 38 deletions(-) diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp index f9b8616..4d3d3e3 100644 --- a/clang/lib/Sema/AnalysisBasedWarnings.cpp +++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp @@ -530,44 +530,37 @@ static void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body, if (CD.checkDiagnostics(Diags, ReturnsVoid, HasNoReturn)) return; - // FIXME: Function try block - if (const CompoundStmt *Compound = dyn_cast(Body)) { - switch (CheckFallThrough(AC)) { - case UnknownFallThrough: - break; + SourceLocation LBrace = Body->getLocStart(), RBrace = Body->getLocEnd(); + // Either in a function body compound statement, or a function-try-block. + switch (CheckFallThrough(AC)) { + case UnknownFallThrough: + break; - case MaybeFallThrough: - if (HasNoReturn) - S.Diag(Compound->getRBracLoc(), - CD.diag_MaybeFallThrough_HasNoReturn); - else if (!ReturnsVoid) - S.Diag(Compound->getRBracLoc(), - CD.diag_MaybeFallThrough_ReturnsNonVoid); - break; - case AlwaysFallThrough: - if (HasNoReturn) - S.Diag(Compound->getRBracLoc(), - CD.diag_AlwaysFallThrough_HasNoReturn); - else if (!ReturnsVoid) - S.Diag(Compound->getRBracLoc(), - CD.diag_AlwaysFallThrough_ReturnsNonVoid); - break; - case NeverFallThroughOrReturn: - if (ReturnsVoid && !HasNoReturn && CD.diag_NeverFallThroughOrReturn) { - if (const FunctionDecl *FD = dyn_cast(D)) { - S.Diag(Compound->getLBracLoc(), CD.diag_NeverFallThroughOrReturn) - << 0 << FD; - } else if (const ObjCMethodDecl *MD = dyn_cast(D)) { - S.Diag(Compound->getLBracLoc(), CD.diag_NeverFallThroughOrReturn) - << 1 << MD; - } else { - S.Diag(Compound->getLBracLoc(), CD.diag_NeverFallThroughOrReturn); - } + case MaybeFallThrough: + if (HasNoReturn) + S.Diag(RBrace, CD.diag_MaybeFallThrough_HasNoReturn); + else if (!ReturnsVoid) + S.Diag(RBrace, CD.diag_MaybeFallThrough_ReturnsNonVoid); + break; + case AlwaysFallThrough: + if (HasNoReturn) + S.Diag(RBrace, CD.diag_AlwaysFallThrough_HasNoReturn); + else if (!ReturnsVoid) + S.Diag(RBrace, CD.diag_AlwaysFallThrough_ReturnsNonVoid); + break; + case NeverFallThroughOrReturn: + if (ReturnsVoid && !HasNoReturn && CD.diag_NeverFallThroughOrReturn) { + if (const FunctionDecl *FD = dyn_cast(D)) { + S.Diag(LBrace, CD.diag_NeverFallThroughOrReturn) << 0 << FD; + } else if (const ObjCMethodDecl *MD = dyn_cast(D)) { + S.Diag(LBrace, CD.diag_NeverFallThroughOrReturn) << 1 << MD; + } else { + S.Diag(LBrace, CD.diag_NeverFallThroughOrReturn); } - break; - case NeverFallThrough: - break; - } + } + break; + case NeverFallThrough: + break; } } diff --git a/clang/test/SemaCXX/return-noreturn.cpp b/clang/test/SemaCXX/return-noreturn.cpp index 174971c..61b45c5 100644 --- a/clang/test/SemaCXX/return-noreturn.cpp +++ b/clang/test/SemaCXX/return-noreturn.cpp @@ -1,5 +1,5 @@ -// RUN: %clang_cc1 %s -fsyntax-only -verify -Wreturn-type -Wmissing-noreturn -Wno-unreachable-code -Wno-covered-switch-default -// RUN: %clang_cc1 %s -fsyntax-only -std=c++11 -verify -Wreturn-type -Wmissing-noreturn -Wno-unreachable-code -Wno-covered-switch-default +// RUN: %clang_cc1 %s -fsyntax-only -fcxx-exceptions -verify -Wreturn-type -Wmissing-noreturn -Wno-unreachable-code -Wno-covered-switch-default +// RUN: %clang_cc1 %s -fsyntax-only -fcxx-exceptions -std=c++11 -verify -Wreturn-type -Wmissing-noreturn -Wno-unreachable-code -Wno-covered-switch-default // A destructor may be marked noreturn and should still influence the CFG. void pr6884_abort() __attribute__((noreturn)); @@ -245,3 +245,20 @@ namespace LambdaVsTemporaryDtor { } // ok, initialization of lambda does not return } #endif + +// Ensure that function-try-blocks also check for return values properly. +int functionTryBlock1(int s) try { + return 0; +} catch (...) { +} // expected-warning {{control may reach end of non-void function}} + +int functionTryBlock2(int s) try { +} catch (...) { + return 0; +} // expected-warning {{control may reach end of non-void function}} + +int functionTryBlock3(int s) try { + return 0; +} catch (...) { + return 0; +} // ok, both paths return. -- 2.7.4