If we flow off the end of a value-returning function:
authorRichard Smith <richard-llvm@metafoo.co.uk>
Thu, 4 Oct 2012 23:52:29 +0000 (23:52 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Thu, 4 Oct 2012 23:52:29 +0000 (23:52 +0000)
 - outside C++, return undef (behavior is not undefined unless the value is used)
 - in C++, with -fcatch-undefined-behavior, perform an appropriate trap
 - in C++, produce an 'unreachable' (behavior is undefined immediately)

llvm-svn: 165273

clang/lib/CodeGen/CodeGenFunction.cpp
clang/test/CodeGen/catch-undef-behavior.c
clang/test/CodeGenCXX/catch-undef-behavior.cpp
clang/test/CodeGenCXX/return.cpp [new file with mode: 0644]

index 1d02861..5c0247a 100644 (file)
@@ -535,6 +535,20 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn,
   else
     EmitFunctionBody(Args);
 
+  // C++11 [stmt.return]p2:
+  //   Flowing off the end of a function [...] results in undefined behavior in
+  //   a value-returning function.
+  // C11 6.9.1p12:
+  //   If the '}' that terminates a function is reached, and the value of the
+  //   function call is used by the caller, the behavior is undefined.
+  if (getContext().getLangOpts().CPlusPlus && !FD->hasImplicitReturnZero() &&
+      !FD->getResultType()->isVoidType() && Builder.GetInsertBlock()) {
+    if (CatchUndefined)
+      EmitCheck(Builder.getFalse());
+    Builder.CreateUnreachable();
+    Builder.ClearInsertionPoint();
+  }
+
   // Emit the standard function epilogue.
   FinishFunction(BodyRange.getEnd());
 
index 5832b6c..53dda5c 100644 (file)
@@ -44,3 +44,11 @@ int rsh_inbounds(int a, int b) {
   // CHECK-NEXT: ret i32 %[[RET]]
   return a >> b;
 }
+
+// CHECK: @no_return
+int no_return() {
+  // Reaching the end of a noreturn function is fine in C.
+  // CHECK-NOT: call
+  // CHECK-NOT: unreachable
+  // CHECK: ret i32
+}
index 0ec1cc1..fdc2b00 100644 (file)
@@ -86,3 +86,9 @@ int lsh_overflow(int a, int b) {
   // CHECK-NEXT: ret i32 %[[RET]]
   return a << b;
 }
+
+// CHECK: @_Z9no_return
+int no_return() {
+  // CHECK: call void @llvm.trap
+  // CHECK: unreachable
+}
diff --git a/clang/test/CodeGenCXX/return.cpp b/clang/test/CodeGenCXX/return.cpp
new file mode 100644 (file)
index 0000000..2af1a52
--- /dev/null
@@ -0,0 +1,6 @@
+// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck %s
+
+// CHECK: @_Z9no_return
+int no_return() {
+  // CHECK: unreachable
+}