steakhal created this revision.
steakhal added reviewers: NoQ, xazax.hun, aaron.ballman.
Herald added subscribers: martong, rnkovacs.
Herald added a reviewer: Szelethus.
Herald added a project: All.
steakhal requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Previously, only `void` returning functions were considered for `noreturn`
attribute candidates. This patch removes this artificial restriction.

Notice the zero-initializations of the `CheckFallThroughDiagnostics`
objects. In some cases, such as inside `MakeForCoroutine()`, some struct
members were left uninitialized (probably by accident).
This way all the fields will be zero-initialized, preventing accidental
uninitialized reads during diagnostics construction.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D139195

Files:
  clang/lib/Sema/AnalysisBasedWarnings.cpp
  clang/test/SemaCXX/return-noreturn.cpp
  clang/test/SemaObjC/return.m

Index: clang/test/SemaObjC/return.m
===================================================================
--- clang/test/SemaObjC/return.m
+++ clang/test/SemaObjC/return.m
@@ -1,6 +1,6 @@
 // RUN: %clang_cc1 -fsyntax-only -verify -Wmissing-noreturn -fobjc-exceptions -Wno-objc-root-class %s
 
-int test1(void) {
+__attribute__((noreturn)) int test1(void) {
   id a;
   @throw a;
 }
Index: clang/test/SemaCXX/return-noreturn.cpp
===================================================================
--- clang/test/SemaCXX/return-noreturn.cpp
+++ clang/test/SemaCXX/return-noreturn.cpp
@@ -15,28 +15,28 @@
 // the presence of switches, case statements, labels, and blocks. These tests
 // try to cover bugs reported in both PR6884 and PR10063.
 namespace abort_struct_complex_cfgs {
-  int basic(int x) {
+  __attribute__((noreturn)) int basic(int x) {
     switch (x) { default: pr6884_abort(); }
   }
-  int f1(int x) {
+  __attribute__((noreturn)) int f1(int x) {
     switch (x) default: pr6884_abort_struct();
   }
-  int f2(int x) {
+  __attribute__((noreturn)) int f2(int x) {
     switch (x) { default: pr6884_abort_struct(); }
   }
   int f2_positive(int x) {
     switch (x) { default: ; }
   } // expected-warning {{non-void function does not return a value}}
-  int f3(int x) {
+  __attribute__((noreturn)) int f3(int x) {
     switch (x) { default: { pr6884_abort_struct(); } }
   }
-  int f4(int x) {
+  __attribute__((noreturn)) int f4(int x) {
     switch (x) default: L1: L2: case 4: pr6884_abort_struct();
   }
-  int f5(int x) {
+  __attribute__((noreturn)) int f5(int x) {
     switch (x) default: L1: { L2: case 4: pr6884_abort_struct(); }
   }
-  int f6(int x) {
+  __attribute__((noreturn)) int f6(int x) {
     switch (x) default: L1: L2: case 4: { pr6884_abort_struct(); }
   }
 
@@ -50,11 +50,11 @@
 
   // Test that these constructs work even when extraneous blocks are created
   // before and after the switch due to implicit destructors.
-  int g1(int x) {
+  __attribute__((noreturn)) int g1(int x) {
     other o;
     switch (x) default: pr6884_abort_struct();
   }
-  int g2(int x) {
+  __attribute__((noreturn)) int g2(int x) {
     other o;
     switch (x) { default: pr6884_abort_struct(); }
   }
@@ -62,46 +62,46 @@
     other o;
     switch (x) { default: ; }
   } // expected-warning {{non-void function does not return a value}}
-  int g3(int x) {
+  __attribute__((noreturn)) int g3(int x) {
     other o;
     switch (x) { default: { pr6884_abort_struct(); } }
   }
-  int g4(int x) {
+  __attribute__((noreturn)) int g4(int x) {
     other o;
     switch (x) default: L1: L2: case 4: pr6884_abort_struct();
   }
-  int g5(int x) {
+  __attribute__((noreturn)) int g5(int x) {
     other o;
     switch (x) default: L1: { L2: case 4: pr6884_abort_struct(); }
   }
-  int g6(int x) {
+  __attribute__((noreturn)) int g6(int x) {
     other o;
     switch (x) default: L1: L2: case 4: { pr6884_abort_struct(); }
   }
 
   // Test that these constructs work even with variables carrying the no-return
   // destructor instead of temporaries.
-  int h1(int x) {
+  __attribute__((noreturn)) int h1(int x) {
     other o;
     switch (x) default: pr6884_abort_struct a;
   }
-  int h2(int x) {
+  __attribute__((noreturn)) int h2(int x) {
     other o;
     switch (x) { default: pr6884_abort_struct a; }
   }
-  int h3(int x) {
+  __attribute__((noreturn)) int h3(int x) {
     other o;
     switch (x) { default: { pr6884_abort_struct a; } }
   }
-  int h4(int x) {
+  __attribute__((noreturn)) int h4(int x) {
     other o;
     switch (x) default: L1: L2: case 4: pr6884_abort_struct a;
   }
-  int h5(int x) {
+  __attribute__((noreturn)) int h5(int x) {
     other o;
     switch (x) default: L1: { L2: case 4: pr6884_abort_struct a; }
   }
-  int h6(int x) {
+  __attribute__((noreturn)) int h6(int x) {
     other o;
     switch (x) default: L1: L2: case 4: { pr6884_abort_struct a; }
   }
@@ -155,11 +155,11 @@
   operator bool() const;
 };
 
-int testTernaryUnconditionalNoreturn() {
+__attribute__((noreturn)) int testTernaryUnconditionalNoreturn() {
   true ? NoReturn() : NoReturn();
 }
 
-int testTernaryStaticallyConditionalNoretrunOnTrue() {
+__attribute__((noreturn)) int testTernaryStaticallyConditionalNoretrunOnTrue() {
   true ? NoReturn() : Return();
 }
 
@@ -167,7 +167,7 @@
   true ? Return() : NoReturn();
 } // expected-warning {{non-void function does not return a value}}
 
-int testTernaryStaticallyConditionalNoretrunOnFalse() {
+__attribute__((noreturn)) int testTernaryStaticallyConditionalNoretrunOnFalse() {
   false ? Return() : NoReturn();
 }
 
@@ -191,11 +191,11 @@
   value || (false ? true : NoReturn());
 } // expected-warning {{non-void function does not return a value in all control paths}}
 
-int testStaticallyExecutedLogicalOrBranch() {
+__attribute__((noreturn)) int testStaticallyExecutedLogicalOrBranch() {
   false || NoReturn();
 }
 
-int testStaticallyExecutedLogicalAndBranch() {
+__attribute__((noreturn)) int testStaticallyExecutedLogicalAndBranch() {
   true && NoReturn();
 }
 
@@ -215,11 +215,11 @@
   (true && value) || (true && NoReturn());
 } // expected-warning {{non-void function does not return a value in all control paths}}
 
-int testConditionallyExecutedComplexLogicalBranch3(bool value) {
+__attribute__((noreturn)) int testConditionallyExecutedComplexLogicalBranch3(bool value) {
   (false && (Return() || true)) || (true && NoReturn());
 }
 
-int testConditionallyExecutedComplexLogicalBranch4(bool value) {
+__attribute__((noreturn)) int testConditionallyExecutedComplexLogicalBranch4(bool value) {
   false || ((Return() || true) && (true && NoReturn()));
 }
 
@@ -238,7 +238,7 @@
     foo();
   } // expected-warning {{non-void function does not return a value}}
 
-  int baz() {
+  __attribute__((noreturn)) int baz() {
     FatalCopy fc;
     X work([fc](){});
     foo();
Index: clang/lib/Sema/AnalysisBasedWarnings.cpp
===================================================================
--- clang/lib/Sema/AnalysisBasedWarnings.cpp
+++ clang/lib/Sema/AnalysisBasedWarnings.cpp
@@ -520,11 +520,11 @@
 namespace {
 
 struct CheckFallThroughDiagnostics {
-  unsigned diag_MaybeFallThrough_HasNoReturn;
-  unsigned diag_MaybeFallThrough_ReturnsNonVoid;
-  unsigned diag_AlwaysFallThrough_HasNoReturn;
-  unsigned diag_AlwaysFallThrough_ReturnsNonVoid;
-  unsigned diag_NeverFallThroughOrReturn;
+  unsigned diag_MaybeFallThrough_HasNoReturn = 0;
+  unsigned diag_MaybeFallThrough_ReturnsNonVoid = 0;
+  unsigned diag_AlwaysFallThrough_HasNoReturn = 0;
+  unsigned diag_AlwaysFallThrough_ReturnsNonVoid = 0;
+  unsigned diag_NeverFallThroughOrReturn = 0;
   enum { Function, Block, Lambda, Coroutine } funMode;
   SourceLocation FuncLoc;
 
@@ -554,8 +554,6 @@
     if (!isVirtualMethod && !isTemplateInstantiation)
       D.diag_NeverFallThroughOrReturn =
         diag::warn_suggest_noreturn_function;
-    else
-      D.diag_NeverFallThroughOrReturn = 0;
 
     D.funMode = Function;
     return D;
@@ -564,10 +562,8 @@
   static CheckFallThroughDiagnostics MakeForCoroutine(const Decl *Func) {
     CheckFallThroughDiagnostics D;
     D.FuncLoc = Func->getLocation();
-    D.diag_MaybeFallThrough_HasNoReturn = 0;
     D.diag_MaybeFallThrough_ReturnsNonVoid =
         diag::warn_maybe_falloff_nonvoid_coroutine;
-    D.diag_AlwaysFallThrough_HasNoReturn = 0;
     D.diag_AlwaysFallThrough_ReturnsNonVoid =
         diag::warn_falloff_nonvoid_coroutine;
     D.funMode = Coroutine;
@@ -584,7 +580,6 @@
       diag::err_noreturn_block_has_return_expr;
     D.diag_AlwaysFallThrough_ReturnsNonVoid =
       diag::err_falloff_nonvoid_block;
-    D.diag_NeverFallThroughOrReturn = 0;
     D.funMode = Block;
     return D;
   }
@@ -599,7 +594,6 @@
       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;
   }
@@ -700,7 +694,7 @@
         EmitDiag(RBrace, CD.diag_AlwaysFallThrough_ReturnsNonVoid);
       break;
     case NeverFallThroughOrReturn:
-      if (ReturnsVoid && !HasNoReturn && CD.diag_NeverFallThroughOrReturn) {
+      if (!HasNoReturn && CD.diag_NeverFallThroughOrReturn) {
         if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
           S.Diag(LBrace, CD.diag_NeverFallThroughOrReturn) << 0 << FD;
         } else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to