debug-info-static-member.cpp 6.35 KB
// RUN: %clangxx -target x86_64-unknown-unknown -g %s -emit-llvm -S -o - | FileCheck %s
// RUN: %clangxx -target x86_64-unknown-unknown -g -std=c++98 %s -emit-llvm -S -o - | FileCheck %s
// RUN: %clangxx -target x86_64-unknown-unknown -g -std=c++11 %s -emit-llvm -S -o - | FileCheck %s
// RUN: %clang_cc1 -triple x86_64-windows-msvc -gcodeview -debug-info-kind=limited %s -emit-llvm -o - | FileCheck --check-prefix MSVC %s
// PR14471

// CHECK: @_ZN1C1aE = dso_local global i32 4, align 4, !dbg [[A:![0-9]+]]
// CHECK: @_ZN1C1bE = dso_local global i32 2, align 4, !dbg [[B:![0-9]+]]
// CHECK: @_ZN1C1cE = dso_local global i32 1, align 4, !dbg [[C:![0-9]+]]

enum X {
  Y
};
class C
{
  static int a;
  const static bool const_a = true;
protected:
  static int b;
#if __cplusplus >= 201103L
  constexpr static float const_b = 3.14;
#else
  const static float const_b = 3.14;
#endif
public:
  static int c;
  const static int const_c = 18;
  int d;
  static X x_a;
};

// The definition of C::a drives the emission of class C, which is
// why the definition of "a" comes before the declarations while
// "b" and "c" come after.

// CHECK: [[A]] = !DIGlobalVariableExpression(var: [[AV:.*]], expr: !DIExpression())
// CHECK: [[AV]] = distinct !DIGlobalVariable(name: "a",
// CHECK-SAME:                                declaration: ![[DECL_A:[0-9]+]])
// MSVC: distinct !DIGlobalVariable(name: "a"
//
// CHECK: !DICompositeType(tag: DW_TAG_enumeration_type, name: "X"{{.*}}, identifier: "_ZTS1X")
// CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "anon_static_decl_struct"
// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "anon_static_decl_var"
// CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "static_decl_templ<int>"
// CHECK-NOT:              DIFlagFwdDecl
// CHECK-SAME:             ){{$}}
// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "static_decl_templ_var"

int C::a = 4;
// CHECK: [[B]] = !DIGlobalVariableExpression(var: [[BV:.*]], expr: !DIExpression())
// CHECK: [[BV]] = distinct !DIGlobalVariable(name: "b",
// CHECK-SAME:                                declaration: ![[DECL_B:[0-9]+]])
// MSVC: distinct !DIGlobalVariable(name: "b"
// CHECK: ![[DECL_B]] = !DIDerivedType(tag: DW_TAG_member, name: "b"
// CHECK-NOT:                                 size:
// CHECK-NOT:                                 align:
// CHECK-NOT:                                 offset:
// CHECK-SAME:                                flags: DIFlagProtected | DIFlagStaticMember)
//
// CHECK: !DICompositeType(tag: DW_TAG_class_type, name: "C"{{.*}}, identifier: "_ZTS1C")
//
// CHECK: ![[DECL_A]] = !DIDerivedType(tag: DW_TAG_member, name: "a"
// CHECK-NOT:                                 size:
// CHECK-NOT:                                 align:
// CHECK-NOT:                                 offset:
// CHECK-SAME:                                flags: DIFlagStaticMember)
//
// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "const_a"
// CHECK-NOT:            size:
// CHECK-NOT:            align:
// CHECK-NOT:            offset:
// CHECK-SAME:           flags: DIFlagStaticMember,
// CHECK-SAME:           extraData: i1 true)

// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "const_b"
// CHECK-NOT:            size:
// CHECK-NOT:            align:
// CHECK-NOT:            offset:
// CHECK-SAME:           flags: DIFlagProtected | DIFlagStaticMember,
// CHECK-SAME:           extraData: float 0x{{.*}})

// CHECK: ![[DECL_C:[0-9]+]] = !DIDerivedType(tag: DW_TAG_member, name: "c"
// CHECK-NOT:                                 size:
// CHECK-NOT:                                 align:
// CHECK-NOT:                                 offset:
// CHECK-SAME:                                flags: DIFlagPublic | DIFlagStaticMember)
//
// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "const_c"
// CHECK-NOT:            size:
// CHECK-NOT:            align:
// CHECK-NOT:            offset:
// CHECK-SAME:           flags: DIFlagPublic | DIFlagStaticMember,
// CHECK-SAME:           extraData: i32 18)
//
// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "x_a"
// CHECK-SAME:           flags: DIFlagPublic | DIFlagStaticMember)

int C::b = 2;
// CHECK: [[C]] = !DIGlobalVariableExpression(var: [[CV:.*]], expr: !DIExpression())
// CHECK: [[CV]] = distinct !DIGlobalVariable(name: "c", {{.*}} declaration: ![[DECL_C]])
// MSVC: distinct !DIGlobalVariable(name: "c"
int C::c = 1;

int main()
{
        C instance_C;
        instance_C.d = 8;
        return C::c;
}

// CHECK-NOT: !DIGlobalVariable(name: "anon_static_decl_var"

// Test this in an anonymous namespace to ensure the type is retained even when
// it doesn't get automatically retained by the string type reference machinery.
namespace {
struct anon_static_decl_struct {
  static const int anon_static_decl_var = 117;
};
}

int ref() {
  return anon_static_decl_struct::anon_static_decl_var;
}

// In MSVC, static data members should be emitted as global variables when used.
// MSVC: !DIGlobalVariableExpression(var: [[ANON_STATIC_DECL:![0-9]+]],
// MSVC-SAME: !DIExpression(DW_OP_constu, 117, DW_OP_stack_value)
// MSVC: [[ANON_STATIC_DECL]] = distinct !DIGlobalVariable(name: "anon_static_decl_var"
// MSVC: !DIGlobalVariableExpression(var: [[STATIC_DECL_TEMPL:![0-9]+]]
// MSVC-SAME: !DIExpression(DW_OP_constu, 7, DW_OP_stack_value)
// MSVC: [[STATIC_DECL_TEMPL]] = distinct !DIGlobalVariable(name: "static_decl_templ_var"

template<typename T>
struct static_decl_templ {
  static const int static_decl_templ_var = 7;
};

template<typename T>
const int static_decl_templ<T>::static_decl_templ_var;

int static_decl_templ_ref() {
  return static_decl_templ<int>::static_decl_templ_var;
}

// Verify that even when a static member declaration is created lazily when
// creating the definition, the declaration line is that of the canonical
// declaration, not the definition. Also, since we look at the canonical
// definition, we should also correctly emit the constant value (42) into the
// debug info.
struct V {
  virtual ~V(); // cause the definition of 'V' to be omitted by no-standalone-debug optimization
  static const int const_va = 42;
};
// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "const_va",
// CHECK-SAME:           line: [[@LINE-3]]
// CHECK-SAME:           extraData: i32 42
const int V::const_va;

namespace x {
struct y {
// CHECK: !DIGlobalVariable(name: "z",
// CHECK-SAME:              scope: [[NS_X:![0-9]+]]
// CHECK: [[NS_X]] = !DINamespace(name: "x"
  static int z;
};
int y::z;
}