summaryrefslogtreecommitdiff
path: root/clang/test/CodeGenCXX/return.cpp
blob: 584c2921c1e7fb8b0b8ee8b441aef79345e42d33 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
// RUN: %clang_cc1 -emit-llvm -triple %itanium_abi_triple -std=c++11 -o - %s | FileCheck --check-prefixes=CHECK,CHECK-COMMON %s
// RUN: %clang_cc1 -emit-llvm -triple %itanium_abi_triple -std=c++11 -O -o - %s | FileCheck %s --check-prefixes=CHECK-OPT,CHECK-COMMON
// RUN: %clang_cc1 -emit-llvm -triple %itanium_abi_triple -std=c++11 -fno-strict-return -o - %s | FileCheck %s --check-prefixes=CHECK-NOSTRICT,CHECK-COMMON
// RUN: %clang_cc1 -emit-llvm -triple %itanium_abi_triple -std=c++11 -fno-strict-return -Wno-return-type -o - %s | FileCheck %s --check-prefixes=CHECK-NOSTRICT,CHECK-COMMON
// RUN: %clang_cc1 -emit-llvm -triple %itanium_abi_triple -std=c++11 -fno-strict-return -O -o - %s | FileCheck %s --check-prefixes=CHECK-NOSTRICT-OPT,CHECK-COMMON

// CHECK-COMMON-LABEL: @_Z9no_return
int no_return() {
  // CHECK:      call void @llvm.trap
  // CHECK-NEXT: unreachable

  // CHECK-OPT-NOT: call void @llvm.trap
  // CHECK-OPT:     unreachable

  // -fno-strict-return should not emit trap + unreachable but it should return
  // an undefined value instead.

  // CHECK-NOSTRICT: alloca
  // CHECK-NOSTRICT-NEXT: load
  // CHECK-NOSTRICT-NEXT: ret i32
  // CHECK-NOSTRICT-NEXT: }

  // CHECK-NOSTRICT-OPT: ret i32 undef
}

enum Enum {
  A, B
};

// CHECK-COMMON-LABEL: @_Z27returnNotViableDontOptimize4Enum
int returnNotViableDontOptimize(Enum e) {
  switch (e) {
  case A: return 1;
  case B: return 2;
  }
  // Undefined behaviour optimization shouldn't be used when -fno-strict-return
  // is turned on, even if all the enum cases are covered in this function.

  // CHECK-NOSTRICT-NOT: call void @llvm.trap
  // CHECK-NOSTRICT-NOT: unreachable
}

struct Trivial {
  int x;
};

// CHECK-NOSTRICT-LABEL: @_Z7trivialv
Trivial trivial() {
  // This function returns a trivial record so -fno-strict-return should avoid
  // the undefined behaviour optimization.

  // CHECK-NOSTRICT-NOT: call void @llvm.trap
  // CHECK-NOSTRICT-NOT: unreachable
}

struct NonTrivialCopy {
  NonTrivialCopy(const NonTrivialCopy &);
};

// CHECK-NOSTRICT-LABEL: @_Z14nonTrivialCopyv
NonTrivialCopy nonTrivialCopy() {
  // CHECK-NOSTRICT-NOT: call void @llvm.trap
  // CHECK-NOSTRICT-NOT: unreachable
}

struct NonTrivialDefaultConstructor {
  int x;

  NonTrivialDefaultConstructor() { }
};

// CHECK-NOSTRICT-LABEL: @_Z28nonTrivialDefaultConstructorv
NonTrivialDefaultConstructor nonTrivialDefaultConstructor() {
  // CHECK-NOSTRICT-NOT: call void @llvm.trap
  // CHECK-NOSTRICT-NOT: unreachable
}

// Functions that return records with non-trivial destructors should always use
// the -fstrict-return optimization.

struct NonTrivialDestructor {
  ~NonTrivialDestructor();
};

// CHECK-NOSTRICT-LABEL: @_Z20nonTrivialDestructorv
NonTrivialDestructor nonTrivialDestructor() {
  // CHECK-NOSTRICT: call void @llvm.trap
  // CHECK-NOSTRICT-NEXT: unreachable
}

// The behavior for lambdas should be identical to functions.
// CHECK-COMMON-LABEL: @_Z10lambdaTestv
void lambdaTest() {
  auto lambda1 = []() -> int {
  };
  lambda1();

  // CHECK: call void @llvm.trap
  // CHECK-NEXT: unreachable

  // CHECK-NOSTRICT-NOT: call void @llvm.trap
  // CHECK-NOSTRICT-NOT: unreachable
}