// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py // Basic C++ test for update_cc_test_checks // RUN: %clang_cc1 -no-opaque-pointers -triple=x86_64-unknown-linux-gnu -emit-llvm -o - %s | FileCheck %s class Foo { int x; public: explicit Foo(int x); ~Foo(); // CHECK-LABEL: @_ZNK3Foo23function_defined_inlineEi( // CHECK-NEXT: entry: // CHECK-NEXT: [[THIS_ADDR:%.*]] = alloca %class.Foo*, align 8 // CHECK-NEXT: [[ARG_ADDR:%.*]] = alloca i32, align 4 // CHECK-NEXT: store %class.Foo* [[THIS:%.*]], %class.Foo** [[THIS_ADDR]], align 8 // CHECK-NEXT: store i32 [[ARG:%.*]], i32* [[ARG_ADDR]], align 4 // CHECK-NEXT: [[THIS1:%.*]] = load %class.Foo*, %class.Foo** [[THIS_ADDR]], align 8 // CHECK-NEXT: [[TMP0:%.*]] = load i32, i32* [[ARG_ADDR]], align 4 // CHECK-NEXT: [[X:%.*]] = getelementptr inbounds [[CLASS_FOO:%.*]], %class.Foo* [[THIS1]], i32 0, i32 0 // CHECK-NEXT: [[TMP1:%.*]] = load i32, i32* [[X]], align 4 // CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP0]], [[TMP1]] // CHECK-NEXT: ret i32 [[ADD]] // inline int function_defined_inline(int arg) const { return arg + x; } inline int function_defined_out_of_line(int arg) const; }; // CHECK-LABEL: @_ZN3FooC1Ei( // CHECK-NEXT: entry: // CHECK-NEXT: [[THIS_ADDR:%.*]] = alloca %class.Foo*, align 8 // CHECK-NEXT: [[X_ADDR:%.*]] = alloca i32, align 4 // CHECK-NEXT: store %class.Foo* [[THIS:%.*]], %class.Foo** [[THIS_ADDR]], align 8 // CHECK-NEXT: store i32 [[X:%.*]], i32* [[X_ADDR]], align 4 // CHECK-NEXT: [[THIS1:%.*]] = load %class.Foo*, %class.Foo** [[THIS_ADDR]], align 8 // CHECK-NEXT: [[TMP0:%.*]] = load i32, i32* [[X_ADDR]], align 4 // CHECK-NEXT: call void @_ZN3FooC2Ei(%class.Foo* noundef nonnull align 4 dereferenceable(4) [[THIS1]], i32 noundef [[TMP0]]) // CHECK-NEXT: ret void // Foo::Foo(int x) : x(x) {} // CHECK-LABEL: @_ZN3FooD1Ev( // CHECK-NEXT: entry: // CHECK-NEXT: [[THIS_ADDR:%.*]] = alloca %class.Foo*, align 8 // CHECK-NEXT: store %class.Foo* [[THIS:%.*]], %class.Foo** [[THIS_ADDR]], align 8 // CHECK-NEXT: [[THIS1:%.*]] = load %class.Foo*, %class.Foo** [[THIS_ADDR]], align 8 // CHECK-NEXT: call void @_ZN3FooD2Ev(%class.Foo* noundef nonnull align 4 dereferenceable(4) [[THIS1]]) #[[ATTR3:[0-9]+]] // CHECK-NEXT: ret void // Foo::~Foo() {} // CHECK-LABEL: @_ZNK3Foo28function_defined_out_of_lineEi( // CHECK-NEXT: entry: // CHECK-NEXT: [[THIS_ADDR:%.*]] = alloca %class.Foo*, align 8 // CHECK-NEXT: [[ARG_ADDR:%.*]] = alloca i32, align 4 // CHECK-NEXT: store %class.Foo* [[THIS:%.*]], %class.Foo** [[THIS_ADDR]], align 8 // CHECK-NEXT: store i32 [[ARG:%.*]], i32* [[ARG_ADDR]], align 4 // CHECK-NEXT: [[THIS1:%.*]] = load %class.Foo*, %class.Foo** [[THIS_ADDR]], align 8 // CHECK-NEXT: [[X:%.*]] = getelementptr inbounds [[CLASS_FOO:%.*]], %class.Foo* [[THIS1]], i32 0, i32 0 // CHECK-NEXT: [[TMP0:%.*]] = load i32, i32* [[X]], align 4 // CHECK-NEXT: [[TMP1:%.*]] = load i32, i32* [[ARG_ADDR]], align 4 // CHECK-NEXT: [[SUB:%.*]] = sub nsw i32 [[TMP0]], [[TMP1]] // CHECK-NEXT: ret i32 [[SUB]] // int Foo::function_defined_out_of_line(int arg) const { return x - arg; } // Call the inline methods to ensure the LLVM IR is generated: // CHECK-LABEL: @main( // CHECK-NEXT: entry: // CHECK-NEXT: [[F:%.*]] = alloca [[CLASS_FOO:%.*]], align 4 // CHECK-NEXT: call void @_ZN3FooC1Ei(%class.Foo* noundef nonnull align 4 dereferenceable(4) [[F]], i32 noundef 1) // CHECK-NEXT: [[CALL:%.*]] = call noundef i32 @_ZNK3Foo23function_defined_inlineEi(%class.Foo* noundef nonnull align 4 dereferenceable(4) [[F]], i32 noundef 2) // CHECK-NEXT: [[CALL1:%.*]] = call noundef i32 @_ZNK3Foo28function_defined_out_of_lineEi(%class.Foo* noundef nonnull align 4 dereferenceable(4) [[F]], i32 noundef 3) // CHECK-NEXT: call void @_ZN3FooD1Ev(%class.Foo* noundef nonnull align 4 dereferenceable(4) [[F]]) #[[ATTR3]] // CHECK-NEXT: ret i32 0 // int main() { Foo f(1); f.function_defined_inline(2); f.function_defined_out_of_line(3); }