| // NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py |
| // RUN: %clang_cc1 -triple=x86_64-unknown-linux-gnu -emit-llvm -o - %s | FileCheck %s |
| |
| template <typename T> |
| struct Foo { |
| private: |
| T x; |
| |
| public: |
| Foo(T x) : x(x) {} |
| ~Foo() {} |
| |
| T get() { return x; } |
| void set(T _x) { x = _x; } |
| }; |
| |
| template <typename T> |
| struct Bar { |
| private: |
| struct Foo<T> foo; |
| |
| public: |
| Bar(T x) : foo(x) {} |
| ~Bar() {} |
| |
| T get() { return foo.get(); } |
| void set(T _x) { foo.set(_x); } |
| }; |
| |
| template <typename T> |
| struct Baz : Foo<T> { |
| public: |
| Baz(T x) : Foo<T>(x) {} |
| ~Baz() {} |
| }; |
| |
| // These two specializations should generate lines for all of Foo's methods. |
| |
| // CHECK-LABEL: @_ZN3FooIcEC1Ec( |
| // CHECK-NEXT: entry: |
| // CHECK-NEXT: [[THIS_ADDR:%.*]] = alloca %struct.Foo*, align 8 |
| // CHECK-NEXT: [[X_ADDR:%.*]] = alloca i8, align 1 |
| // CHECK-NEXT: store %struct.Foo* [[THIS:%.*]], %struct.Foo** [[THIS_ADDR]], align 8 |
| // CHECK-NEXT: store i8 [[X:%.*]], i8* [[X_ADDR]], align 1 |
| // CHECK-NEXT: [[THIS1:%.*]] = load %struct.Foo*, %struct.Foo** [[THIS_ADDR]], align 8 |
| // CHECK-NEXT: [[TMP0:%.*]] = load i8, i8* [[X_ADDR]], align 1 |
| // CHECK-NEXT: call void @_ZN3FooIcEC2Ec(%struct.Foo* nonnull align 1 dereferenceable(1) [[THIS1]], i8 signext [[TMP0]]) |
| // CHECK-NEXT: ret void |
| // |
| // CHECK-LABEL: @_ZN3FooIcED1Ev( |
| // CHECK-NEXT: entry: |
| // CHECK-NEXT: [[THIS_ADDR:%.*]] = alloca %struct.Foo*, align 8 |
| // CHECK-NEXT: store %struct.Foo* [[THIS:%.*]], %struct.Foo** [[THIS_ADDR]], align 8 |
| // CHECK-NEXT: [[THIS1:%.*]] = load %struct.Foo*, %struct.Foo** [[THIS_ADDR]], align 8 |
| // CHECK-NEXT: call void @_ZN3FooIcED2Ev(%struct.Foo* nonnull align 1 dereferenceable(1) [[THIS1]]) #[[ATTR2:[0-9]+]] |
| // CHECK-NEXT: ret void |
| // |
| // CHECK-LABEL: @_ZN3FooIcE3getEv( |
| // CHECK-NEXT: entry: |
| // CHECK-NEXT: [[THIS_ADDR:%.*]] = alloca %struct.Foo*, align 8 |
| // CHECK-NEXT: store %struct.Foo* [[THIS:%.*]], %struct.Foo** [[THIS_ADDR]], align 8 |
| // CHECK-NEXT: [[THIS1:%.*]] = load %struct.Foo*, %struct.Foo** [[THIS_ADDR]], align 8 |
| // CHECK-NEXT: [[X:%.*]] = getelementptr inbounds [[STRUCT_FOO:%.*]], %struct.Foo* [[THIS1]], i32 0, i32 0 |
| // CHECK-NEXT: [[TMP0:%.*]] = load i8, i8* [[X]], align 1 |
| // CHECK-NEXT: ret i8 [[TMP0]] |
| // |
| // CHECK-LABEL: @_ZN3FooIcE3setEc( |
| // CHECK-NEXT: entry: |
| // CHECK-NEXT: [[THIS_ADDR:%.*]] = alloca %struct.Foo*, align 8 |
| // CHECK-NEXT: [[_X_ADDR:%.*]] = alloca i8, align 1 |
| // CHECK-NEXT: store %struct.Foo* [[THIS:%.*]], %struct.Foo** [[THIS_ADDR]], align 8 |
| // CHECK-NEXT: store i8 [[_X:%.*]], i8* [[_X_ADDR]], align 1 |
| // CHECK-NEXT: [[THIS1:%.*]] = load %struct.Foo*, %struct.Foo** [[THIS_ADDR]], align 8 |
| // CHECK-NEXT: [[TMP0:%.*]] = load i8, i8* [[_X_ADDR]], align 1 |
| // CHECK-NEXT: [[X:%.*]] = getelementptr inbounds [[STRUCT_FOO:%.*]], %struct.Foo* [[THIS1]], i32 0, i32 0 |
| // CHECK-NEXT: store i8 [[TMP0]], i8* [[X]], align 1 |
| // CHECK-NEXT: ret void |
| // |
| template struct Foo<char>; |
| |
| // CHECK-LABEL: @_ZN3FooIsEC1Es( |
| // CHECK-NEXT: entry: |
| // CHECK-NEXT: [[THIS_ADDR:%.*]] = alloca %struct.Foo.0*, align 8 |
| // CHECK-NEXT: [[X_ADDR:%.*]] = alloca i16, align 2 |
| // CHECK-NEXT: store %struct.Foo.0* [[THIS:%.*]], %struct.Foo.0** [[THIS_ADDR]], align 8 |
| // CHECK-NEXT: store i16 [[X:%.*]], i16* [[X_ADDR]], align 2 |
| // CHECK-NEXT: [[THIS1:%.*]] = load %struct.Foo.0*, %struct.Foo.0** [[THIS_ADDR]], align 8 |
| // CHECK-NEXT: [[TMP0:%.*]] = load i16, i16* [[X_ADDR]], align 2 |
| // CHECK-NEXT: call void @_ZN3FooIsEC2Es(%struct.Foo.0* nonnull align 2 dereferenceable(2) [[THIS1]], i16 signext [[TMP0]]) |
| // CHECK-NEXT: ret void |
| // |
| // CHECK-LABEL: @_ZN3FooIsED1Ev( |
| // CHECK-NEXT: entry: |
| // CHECK-NEXT: [[THIS_ADDR:%.*]] = alloca %struct.Foo.0*, align 8 |
| // CHECK-NEXT: store %struct.Foo.0* [[THIS:%.*]], %struct.Foo.0** [[THIS_ADDR]], align 8 |
| // CHECK-NEXT: [[THIS1:%.*]] = load %struct.Foo.0*, %struct.Foo.0** [[THIS_ADDR]], align 8 |
| // CHECK-NEXT: call void @_ZN3FooIsED2Ev(%struct.Foo.0* nonnull align 2 dereferenceable(2) [[THIS1]]) #[[ATTR2]] |
| // CHECK-NEXT: ret void |
| // |
| // CHECK-LABEL: @_ZN3FooIsE3getEv( |
| // CHECK-NEXT: entry: |
| // CHECK-NEXT: [[THIS_ADDR:%.*]] = alloca %struct.Foo.0*, align 8 |
| // CHECK-NEXT: store %struct.Foo.0* [[THIS:%.*]], %struct.Foo.0** [[THIS_ADDR]], align 8 |
| // CHECK-NEXT: [[THIS1:%.*]] = load %struct.Foo.0*, %struct.Foo.0** [[THIS_ADDR]], align 8 |
| // CHECK-NEXT: [[X:%.*]] = getelementptr inbounds [[STRUCT_FOO_0:%.*]], %struct.Foo.0* [[THIS1]], i32 0, i32 0 |
| // CHECK-NEXT: [[TMP0:%.*]] = load i16, i16* [[X]], align 2 |
| // CHECK-NEXT: ret i16 [[TMP0]] |
| // |
| // CHECK-LABEL: @_ZN3FooIsE3setEs( |
| // CHECK-NEXT: entry: |
| // CHECK-NEXT: [[THIS_ADDR:%.*]] = alloca %struct.Foo.0*, align 8 |
| // CHECK-NEXT: [[_X_ADDR:%.*]] = alloca i16, align 2 |
| // CHECK-NEXT: store %struct.Foo.0* [[THIS:%.*]], %struct.Foo.0** [[THIS_ADDR]], align 8 |
| // CHECK-NEXT: store i16 [[_X:%.*]], i16* [[_X_ADDR]], align 2 |
| // CHECK-NEXT: [[THIS1:%.*]] = load %struct.Foo.0*, %struct.Foo.0** [[THIS_ADDR]], align 8 |
| // CHECK-NEXT: [[TMP0:%.*]] = load i16, i16* [[_X_ADDR]], align 2 |
| // CHECK-NEXT: [[X:%.*]] = getelementptr inbounds [[STRUCT_FOO_0:%.*]], %struct.Foo.0* [[THIS1]], i32 0, i32 0 |
| // CHECK-NEXT: store i16 [[TMP0]], i16* [[X]], align 2 |
| // CHECK-NEXT: ret void |
| // |
| template struct Foo<short>; |
| |
| // This should not generate lines for the implicit specialization of Foo, but |
| // should generate lines for the explicit specialization of Bar. |
| |
| // CHECK-LABEL: @_ZN3BarIiEC1Ei( |
| // CHECK-NEXT: entry: |
| // CHECK-NEXT: [[THIS_ADDR:%.*]] = alloca %struct.Bar*, align 8 |
| // CHECK-NEXT: [[X_ADDR:%.*]] = alloca i32, align 4 |
| // CHECK-NEXT: store %struct.Bar* [[THIS:%.*]], %struct.Bar** [[THIS_ADDR]], align 8 |
| // CHECK-NEXT: store i32 [[X:%.*]], i32* [[X_ADDR]], align 4 |
| // CHECK-NEXT: [[THIS1:%.*]] = load %struct.Bar*, %struct.Bar** [[THIS_ADDR]], align 8 |
| // CHECK-NEXT: [[TMP0:%.*]] = load i32, i32* [[X_ADDR]], align 4 |
| // CHECK-NEXT: call void @_ZN3BarIiEC2Ei(%struct.Bar* nonnull align 4 dereferenceable(4) [[THIS1]], i32 [[TMP0]]) |
| // CHECK-NEXT: ret void |
| // |
| // CHECK-LABEL: @_ZN3BarIiED1Ev( |
| // CHECK-NEXT: entry: |
| // CHECK-NEXT: [[THIS_ADDR:%.*]] = alloca %struct.Bar*, align 8 |
| // CHECK-NEXT: store %struct.Bar* [[THIS:%.*]], %struct.Bar** [[THIS_ADDR]], align 8 |
| // CHECK-NEXT: [[THIS1:%.*]] = load %struct.Bar*, %struct.Bar** [[THIS_ADDR]], align 8 |
| // CHECK-NEXT: call void @_ZN3BarIiED2Ev(%struct.Bar* nonnull align 4 dereferenceable(4) [[THIS1]]) #[[ATTR2]] |
| // CHECK-NEXT: ret void |
| // |
| // CHECK-LABEL: @_ZN3BarIiE3getEv( |
| // CHECK-NEXT: entry: |
| // CHECK-NEXT: [[THIS_ADDR:%.*]] = alloca %struct.Bar*, align 8 |
| // CHECK-NEXT: store %struct.Bar* [[THIS:%.*]], %struct.Bar** [[THIS_ADDR]], align 8 |
| // CHECK-NEXT: [[THIS1:%.*]] = load %struct.Bar*, %struct.Bar** [[THIS_ADDR]], align 8 |
| // CHECK-NEXT: [[FOO:%.*]] = getelementptr inbounds [[STRUCT_BAR:%.*]], %struct.Bar* [[THIS1]], i32 0, i32 0 |
| // CHECK-NEXT: [[CALL:%.*]] = call i32 @_ZN3FooIiE3getEv(%struct.Foo.1* nonnull align 4 dereferenceable(4) [[FOO]]) |
| // CHECK-NEXT: ret i32 [[CALL]] |
| // |
| // CHECK-LABEL: @_ZN3BarIiE3setEi( |
| // CHECK-NEXT: entry: |
| // CHECK-NEXT: [[THIS_ADDR:%.*]] = alloca %struct.Bar*, align 8 |
| // CHECK-NEXT: [[_X_ADDR:%.*]] = alloca i32, align 4 |
| // CHECK-NEXT: store %struct.Bar* [[THIS:%.*]], %struct.Bar** [[THIS_ADDR]], align 8 |
| // CHECK-NEXT: store i32 [[_X:%.*]], i32* [[_X_ADDR]], align 4 |
| // CHECK-NEXT: [[THIS1:%.*]] = load %struct.Bar*, %struct.Bar** [[THIS_ADDR]], align 8 |
| // CHECK-NEXT: [[FOO:%.*]] = getelementptr inbounds [[STRUCT_BAR:%.*]], %struct.Bar* [[THIS1]], i32 0, i32 0 |
| // CHECK-NEXT: [[TMP0:%.*]] = load i32, i32* [[_X_ADDR]], align 4 |
| // CHECK-NEXT: call void @_ZN3FooIiE3setEi(%struct.Foo.1* nonnull align 4 dereferenceable(4) [[FOO]], i32 [[TMP0]]) |
| // CHECK-NEXT: ret void |
| // |
| template struct Bar<int>; |
| |
| // This should not generate lines for the implicit specialization of Foo, but |
| // should generate lines for the explicit specialization of Baz. |
| |
| // CHECK-LABEL: @_ZN3BazIlEC1El( |
| // CHECK-NEXT: entry: |
| // CHECK-NEXT: [[THIS_ADDR:%.*]] = alloca %struct.Baz*, align 8 |
| // CHECK-NEXT: [[X_ADDR:%.*]] = alloca i64, align 8 |
| // CHECK-NEXT: store %struct.Baz* [[THIS:%.*]], %struct.Baz** [[THIS_ADDR]], align 8 |
| // CHECK-NEXT: store i64 [[X:%.*]], i64* [[X_ADDR]], align 8 |
| // CHECK-NEXT: [[THIS1:%.*]] = load %struct.Baz*, %struct.Baz** [[THIS_ADDR]], align 8 |
| // CHECK-NEXT: [[TMP0:%.*]] = load i64, i64* [[X_ADDR]], align 8 |
| // CHECK-NEXT: call void @_ZN3BazIlEC2El(%struct.Baz* nonnull align 8 dereferenceable(8) [[THIS1]], i64 [[TMP0]]) |
| // CHECK-NEXT: ret void |
| // |
| // CHECK-LABEL: @_ZN3BazIlED1Ev( |
| // CHECK-NEXT: entry: |
| // CHECK-NEXT: [[THIS_ADDR:%.*]] = alloca %struct.Baz*, align 8 |
| // CHECK-NEXT: store %struct.Baz* [[THIS:%.*]], %struct.Baz** [[THIS_ADDR]], align 8 |
| // CHECK-NEXT: [[THIS1:%.*]] = load %struct.Baz*, %struct.Baz** [[THIS_ADDR]], align 8 |
| // CHECK-NEXT: call void @_ZN3BazIlED2Ev(%struct.Baz* nonnull align 8 dereferenceable(8) [[THIS1]]) #[[ATTR2]] |
| // CHECK-NEXT: ret void |
| // |
| template struct Baz<long>; |