[clang] e772a26 - [Clang] Emit DW_TAG_template_alias for template aliases (#87623)

via cfe-commits cfe-commits at lists.llvm.org
Thu Apr 18 13:08:36 PDT 2024


Author: Orlando Cazalet-Hyams
Date: 2024-04-18T21:08:31+01:00
New Revision: e772a268ef75332b72dd9b9ca0341a6af8b0db72

URL: https://github.com/llvm/llvm-project/commit/e772a268ef75332b72dd9b9ca0341a6af8b0db72
DIFF: https://github.com/llvm/llvm-project/commit/e772a268ef75332b72dd9b9ca0341a6af8b0db72.diff

LOG: [Clang] Emit DW_TAG_template_alias for template aliases (#87623)

Fix issue https://github.com/llvm/llvm-project/issues/54624

Add front end flags -gtemplate-alias (also a cc1 flag) and -gno-template-alias
to enable/disable usage of the feature. It's enabled by default in the front
end for SCE debugger tuning only.

GCC emits DW_TAG_typedef for template aliases (as does Clang with this feature
disabled), and GDB and LLDB appear not to support DW_TAG_template_alias.

The -Xclang option -gsimple-template-names=mangled is treated the same as
=full, which is not a regression from current behaviour for template
aliases.

The current implementation omits defaulted arguments and as a consequence
also omits empty parameter packs that come after defaulted arguments. Again,
this isn't a regression as the DW_TAG_typedef name doesn't contain defaulted
arguments.

LLVM support added in https://github.com/llvm/llvm-project/pull/88943

Added template-alias.cpp - Check the metadata construction & interaction with
      -gsimple-template-names.
Added variadic-template-alias.cpp - Check template parameter packs work.
Added defaulted-template-alias.cpp - Check defaulted args (don't) work.
Modified debug-options.c - Check Clang generates correct cc1 flags.

Added: 
    clang/test/CodeGenCXX/defaulted-template-alias.cpp
    clang/test/CodeGenCXX/template-alias.cpp
    clang/test/CodeGenCXX/variadic-template-alias.cpp

Modified: 
    clang/include/clang/Basic/DebugOptions.def
    clang/include/clang/Driver/Options.td
    clang/lib/CodeGen/CGDebugInfo.cpp
    clang/lib/CodeGen/CGDebugInfo.h
    clang/lib/Driver/ToolChains/Clang.cpp
    clang/lib/Frontend/CompilerInvocation.cpp
    clang/test/CodeGenCXX/debug-info-alias.cpp
    clang/test/Driver/debug-options.c

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/Basic/DebugOptions.def b/clang/include/clang/Basic/DebugOptions.def
index 7cd3edf08a17ea..b94f6aef9ac60b 100644
--- a/clang/include/clang/Basic/DebugOptions.def
+++ b/clang/include/clang/Basic/DebugOptions.def
@@ -129,6 +129,9 @@ DEBUGOPT(CodeViewCommandLine, 1, 0)
 /// Whether emit extra debug info for sample pgo profile collection.
 DEBUGOPT(DebugInfoForProfiling, 1, 0)
 
+/// Whether to emit DW_TAG_template_alias for template aliases.
+DEBUGOPT(DebugTemplateAlias, 1, 0)
+
 /// Whether to emit .debug_gnu_pubnames section instead of .debug_pubnames.
 DEBUGOPT(DebugNameTable, 2, 0)
 

diff  --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index 8c38acb72362c7..d682a24ab3da55 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -4309,6 +4309,8 @@ def gsplit_dwarf_EQ : Joined<["-"], "gsplit-dwarf=">, Group<g_flags_Group>,
   Values<"split,single">;
 def gno_split_dwarf : Flag<["-"], "gno-split-dwarf">, Group<g_flags_Group>,
   Visibility<[ClangOption, CLOption, DXCOption]>;
+def gtemplate_alias : Flag<["-"], "gtemplate-alias">, Group<g_flags_Group>, Visibility<[ClangOption, CC1Option]>;
+def gno_template_alias : Flag<["-"], "gno-template-alias">, Group<g_flags_Group>, Visibility<[ClangOption]>;
 def gsimple_template_names : Flag<["-"], "gsimple-template-names">, Group<g_flags_Group>;
 def gsimple_template_names_EQ
     : Joined<["-"], "gsimple-template-names=">,

diff  --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp
index 8c284c332171a1..539ded5cca5e1b 100644
--- a/clang/lib/CodeGen/CGDebugInfo.cpp
+++ b/clang/lib/CodeGen/CGDebugInfo.cpp
@@ -1313,6 +1313,44 @@ llvm::DIType *CGDebugInfo::CreateType(const BlockPointerType *Ty,
   return DBuilder.createPointerType(EltTy, Size);
 }
 
+static llvm::SmallVector<TemplateArgument>
+GetTemplateArgs(const TemplateDecl *TD, const TemplateSpecializationType *Ty) {
+  assert(Ty->isTypeAlias());
+  // TemplateSpecializationType doesn't know if its template args are
+  // being substituted into a parameter pack. We can find out if that's
+  // the case now by inspecting the TypeAliasTemplateDecl template
+  // parameters. Insert Ty's template args into SpecArgs, bundling args
+  // passed to a parameter pack into a TemplateArgument::Pack. It also
+  // doesn't know the value of any defaulted args, so collect those now
+  // too.
+  SmallVector<TemplateArgument> SpecArgs;
+  ArrayRef SubstArgs = Ty->template_arguments();
+  for (const NamedDecl *Param : TD->getTemplateParameters()->asArray()) {
+    // If Param is a parameter pack, pack the remaining arguments.
+    if (Param->isParameterPack()) {
+      SpecArgs.push_back(TemplateArgument(SubstArgs));
+      break;
+    }
+
+    // Skip defaulted args.
+    // FIXME: Ideally, we wouldn't do this. We can read the default values
+    // for each parameter. However, defaulted arguments which are dependent
+    // values or dependent types can't (easily?) be resolved here.
+    if (SubstArgs.empty()) {
+      // If SubstArgs is now empty (we're taking from it each iteration) and
+      // this template parameter isn't a pack, then that should mean we're
+      // using default values for the remaining template parameters (after
+      // which there may be an empty pack too which we will ignore).
+      break;
+    }
+
+    // Take the next argument.
+    SpecArgs.push_back(SubstArgs.front());
+    SubstArgs = SubstArgs.drop_front();
+  }
+  return SpecArgs;
+}
+
 llvm::DIType *CGDebugInfo::CreateType(const TemplateSpecializationType *Ty,
                                       llvm::DIFile *Unit) {
   assert(Ty->isTypeAlias());
@@ -1332,6 +1370,31 @@ llvm::DIType *CGDebugInfo::CreateType(const TemplateSpecializationType *Ty,
   auto PP = getPrintingPolicy();
   Ty->getTemplateName().print(OS, PP, TemplateName::Qualified::None);
 
+  SourceLocation Loc = AliasDecl->getLocation();
+
+  if (CGM.getCodeGenOpts().DebugTemplateAlias) {
+    auto ArgVector = ::GetTemplateArgs(TD, Ty);
+    TemplateArgs Args = {TD->getTemplateParameters(), ArgVector};
+
+    // FIXME: Respect DebugTemplateNameKind::Mangled, e.g. by using GetName.
+    // Note we can't use GetName without additional work: TypeAliasTemplateDecl
+    // doesn't have instantiation information, so
+    // TypeAliasTemplateDecl::getNameForDiagnostic wouldn't have access to the
+    // template args.
+    std::string Name;
+    llvm::raw_string_ostream OS(Name);
+    TD->getNameForDiagnostic(OS, PP, /*Qualified=*/false);
+    if (CGM.getCodeGenOpts().getDebugSimpleTemplateNames() !=
+            llvm::codegenoptions::DebugTemplateNamesKind::Simple ||
+        !HasReconstitutableArgs(Args.Args))
+      printTemplateArgumentList(OS, Args.Args, PP);
+
+    llvm::DIDerivedType *AliasTy = DBuilder.createTemplateAlias(
+        Src, Name, getOrCreateFile(Loc), getLineNumber(Loc),
+        getDeclContextDescriptor(AliasDecl), CollectTemplateParams(Args, Unit));
+    return AliasTy;
+  }
+
   // Disable PrintCanonicalTypes here because we want
   // the DW_AT_name to benefit from the TypePrinter's ability
   // to skip defaulted template arguments.
@@ -1343,8 +1406,6 @@ llvm::DIType *CGDebugInfo::CreateType(const TemplateSpecializationType *Ty,
   PP.PrintCanonicalTypes = false;
   printTemplateArgumentList(OS, Ty->template_arguments(), PP,
                             TD->getTemplateParameters());
-
-  SourceLocation Loc = AliasDecl->getLocation();
   return DBuilder.createTypedef(Src, OS.str(), getOrCreateFile(Loc),
                                 getLineNumber(Loc),
                                 getDeclContextDescriptor(AliasDecl));
@@ -5363,6 +5424,54 @@ static bool IsReconstitutableType(QualType QT) {
   return T.Reconstitutable;
 }
 
+bool CGDebugInfo::HasReconstitutableArgs(
+    ArrayRef<TemplateArgument> Args) const {
+  return llvm::all_of(Args, [&](const TemplateArgument &TA) {
+    switch (TA.getKind()) {
+    case TemplateArgument::Template:
+      // Easy to reconstitute - the value of the parameter in the debug
+      // info is the string name of the template. The template name
+      // itself won't benefit from any name rebuilding, but that's a
+      // representational limitation - maybe DWARF could be
+      // changed/improved to use some more structural representation.
+      return true;
+    case TemplateArgument::Declaration:
+      // Reference and pointer non-type template parameters point to
+      // variables, functions, etc and their value is, at best (for
+      // variables) represented as an address - not a reference to the
+      // DWARF describing the variable/function/etc. This makes it hard,
+      // possibly impossible to rebuild the original name - looking up
+      // the address in the executable file's symbol table would be
+      // needed.
+      return false;
+    case TemplateArgument::NullPtr:
+      // These could be rebuilt, but figured they're close enough to the
+      // declaration case, and not worth rebuilding.
+      return false;
+    case TemplateArgument::Pack:
+      // A pack is invalid if any of the elements of the pack are
+      // invalid.
+      return HasReconstitutableArgs(TA.getPackAsArray());
+    case TemplateArgument::Integral:
+      // Larger integers get encoded as DWARF blocks which are a bit
+      // harder to parse back into a large integer, etc - so punting on
+      // this for now. Re-parsing the integers back into APInt is
+      // probably feasible some day.
+      return TA.getAsIntegral().getBitWidth() <= 64 &&
+             IsReconstitutableType(TA.getIntegralType());
+    case TemplateArgument::StructuralValue:
+      return false;
+    case TemplateArgument::Type:
+      return IsReconstitutableType(TA.getAsType());
+    case TemplateArgument::Expression:
+      return IsReconstitutableType(TA.getAsExpr()->getType());
+    default:
+      llvm_unreachable("Other, unresolved, template arguments should "
+                       "not be seen here");
+    }
+  });
+}
+
 std::string CGDebugInfo::GetName(const Decl *D, bool Qualified) const {
   std::string Name;
   llvm::raw_string_ostream OS(Name);
@@ -5389,49 +5498,7 @@ std::string CGDebugInfo::GetName(const Decl *D, bool Qualified) const {
   } else if (auto *VD = dyn_cast<VarDecl>(ND)) {
     Args = GetTemplateArgs(VD);
   }
-  std::function<bool(ArrayRef<TemplateArgument>)> HasReconstitutableArgs =
-      [&](ArrayRef<TemplateArgument> Args) {
-        return llvm::all_of(Args, [&](const TemplateArgument &TA) {
-          switch (TA.getKind()) {
-          case TemplateArgument::Template:
-            // Easy to reconstitute - the value of the parameter in the debug
-            // info is the string name of the template. (so the template name
-            // itself won't benefit from any name rebuilding, but that's a
-            // representational limitation - maybe DWARF could be
-            // changed/improved to use some more structural representation)
-            return true;
-          case TemplateArgument::Declaration:
-            // Reference and pointer non-type template parameters point to
-            // variables, functions, etc and their value is, at best (for
-            // variables) represented as an address - not a reference to the
-            // DWARF describing the variable/function/etc. This makes it hard,
-            // possibly impossible to rebuild the original name - looking up the
-            // address in the executable file's symbol table would be needed.
-            return false;
-          case TemplateArgument::NullPtr:
-            // These could be rebuilt, but figured they're close enough to the
-            // declaration case, and not worth rebuilding.
-            return false;
-          case TemplateArgument::Pack:
-            // A pack is invalid if any of the elements of the pack are invalid.
-            return HasReconstitutableArgs(TA.getPackAsArray());
-          case TemplateArgument::Integral:
-            // Larger integers get encoded as DWARF blocks which are a bit
-            // harder to parse back into a large integer, etc - so punting on
-            // this for now. Re-parsing the integers back into APInt is probably
-            // feasible some day.
-            return TA.getAsIntegral().getBitWidth() <= 64 &&
-                   IsReconstitutableType(TA.getIntegralType());
-          case TemplateArgument::StructuralValue:
-            return false;
-          case TemplateArgument::Type:
-            return IsReconstitutableType(TA.getAsType());
-          default:
-            llvm_unreachable("Other, unresolved, template arguments should "
-                             "not be seen here");
-          }
-        });
-      };
+
   // A conversion operator presents complications/ambiguity if there's a
   // conversion to class template that is itself a template, eg:
   // template<typename T>

diff  --git a/clang/lib/CodeGen/CGDebugInfo.h b/clang/lib/CodeGen/CGDebugInfo.h
index 7b60e94555d060..d6db4d711366ac 100644
--- a/clang/lib/CodeGen/CGDebugInfo.h
+++ b/clang/lib/CodeGen/CGDebugInfo.h
@@ -626,7 +626,8 @@ class CGDebugInfo {
     llvm::DIType *WrappedType;
   };
 
-  std::string GetName(const Decl*, bool Qualified = false) const;
+  bool HasReconstitutableArgs(ArrayRef<TemplateArgument> Args) const;
+  std::string GetName(const Decl *, bool Qualified = false) const;
 
   /// Build up structure info for the byref.  See \a BuildByRefType.
   BlockByRefType EmitTypeForVarWithBlocksAttr(const VarDecl *VD,

diff  --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index 096ed14f957046..456ea74caadb00 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -4632,6 +4632,21 @@ renderDebugOptions(const ToolChain &TC, const Driver &D, const llvm::Triple &T,
     }
   }
 
+  // Emit DW_TAG_template_alias for template aliases? True by default for SCE.
+  bool UseDebugTemplateAlias =
+      DebuggerTuning == llvm::DebuggerKind::SCE && RequestedDWARFVersion >= 5;
+  if (const auto *DebugTemplateAlias = Args.getLastArg(
+          options::OPT_gtemplate_alias, options::OPT_gno_template_alias)) {
+    // DW_TAG_template_alias is only supported from DWARFv5 but if a user
+    // asks for it we should let them have it (if the target supports it).
+    if (checkDebugInfoOption(DebugTemplateAlias, Args, D, TC)) {
+      const auto &Opt = DebugTemplateAlias->getOption();
+      UseDebugTemplateAlias = Opt.matches(options::OPT_gtemplate_alias);
+    }
+  }
+  if (UseDebugTemplateAlias)
+    CmdArgs.push_back("-gtemplate-alias");
+
   if (const Arg *A = Args.getLastArg(options::OPT_gsrc_hash_EQ)) {
     StringRef v = A->getValue();
     CmdArgs.push_back(Args.MakeArgString("-gsrc-hash=" + v));

diff  --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp
index 1f1f5440ddd75f..5531e938e0f4f4 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -1556,6 +1556,9 @@ void CompilerInvocationBase::GenerateCodeGenArgs(const CodeGenOptions &Opts,
                llvm::DICompileUnit::DebugNameTableKind::Default))
     GenerateArg(Consumer, OPT_gpubnames);
 
+  if (Opts.DebugTemplateAlias)
+    GenerateArg(Consumer, OPT_gtemplate_alias);
+
   auto TNK = Opts.getDebugSimpleTemplateNames();
   if (TNK != llvm::codegenoptions::DebugTemplateNamesKind::Full) {
     if (TNK == llvm::codegenoptions::DebugTemplateNamesKind::Simple)
@@ -1827,6 +1830,8 @@ bool CompilerInvocation::ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args,
   Opts.BinutilsVersion =
       std::string(Args.getLastArgValue(OPT_fbinutils_version_EQ));
 
+  Opts.DebugTemplateAlias = Args.hasArg(OPT_gtemplate_alias);
+
   Opts.DebugNameTable = static_cast<unsigned>(
       Args.hasArg(OPT_ggnu_pubnames)
           ? llvm::DICompileUnit::DebugNameTableKind::GNU

diff  --git a/clang/test/CodeGenCXX/debug-info-alias.cpp b/clang/test/CodeGenCXX/debug-info-alias.cpp
index 3d3f87ed1f6fa8..bf2dbee4659592 100644
--- a/clang/test/CodeGenCXX/debug-info-alias.cpp
+++ b/clang/test/CodeGenCXX/debug-info-alias.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang -g -std=c++11 -S -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang -g -gno-template-alias -std=c++11 -S -emit-llvm %s -o - | FileCheck %s
 
 template<typename T>
 struct foo {

diff  --git a/clang/test/CodeGenCXX/defaulted-template-alias.cpp b/clang/test/CodeGenCXX/defaulted-template-alias.cpp
new file mode 100644
index 00000000000000..a038aa0d9dc208
--- /dev/null
+++ b/clang/test/CodeGenCXX/defaulted-template-alias.cpp
@@ -0,0 +1,38 @@
+// RUN: %clang_cc1 -triple x86_64-unk-unk -o - -emit-llvm -debug-info-kind=standalone -gtemplate-alias %s -gsimple-template-names=simple \
+// RUN: | FileCheck %s
+
+//// Check that -gtemplate-alias causes DW_TAG_template_alias emission for
+//// template aliases with default parameter values. See template-alias.cpp for
+////  more template alias tests.
+//// FIXME: We currently do not emit defaulted arguments.
+
+template<typename T>
+struct X {
+  char m;
+};
+
+template<typename T>
+struct Y {
+  char n;
+};
+
+template <typename NonDefault, template <typename C> class T = Y, int I = 5, typename... Ts>
+using A = X<NonDefault>;
+
+//// We should be able to emit type alias metadata which describes all the
+//// values, including the defaulted parameters and empty parameter pack.
+A<int> a;
+
+// CHECK: !DIDerivedType(tag: DW_TAG_template_alias, name: "A", file: ![[#]], line: [[#]], baseType: ![[baseType:[0-9]+]], extraData: ![[extraData:[0-9]+]])
+// CHECK: ![[baseType]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "X",
+// CHECK: ![[int:[0-9]+]] = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+// CHECK: ![[extraData]] = !{![[NonDefault:[0-9]+]]}
+// CHECK: ![[NonDefault]] = !DITemplateTypeParameter(name: "NonDefault", type: ![[int]])
+
+//// FIXME: Ideally, we would describe the deafulted args, like this:
+// : ![[extraData]] = !{![[NonDefault:[0-9]+]], ![[T:[0-9]+]], ![[I:[0-9]+]], ![[Ts:[0-9]+]]}
+// : ![[NonDefault]] = !DITemplateTypeParameter(name: "NonDefault", type: ![[int]])
+// : ![[T]] = !DITemplateValueParameter(tag: DW_TAG_GNU_template_template_param, name: "T", defaulted: true, value: !"Y")
+// : ![[I]] = !DITemplateValueParameter(name: "I", type: ![[int]], defaulted: true, value: i32 5)
+// : ![[Ts]] = !DITemplateValueParameter(tag: DW_TAG_GNU_template_parameter_pack, name: "Ts", value: ![[types:[0-9]+]])
+// : ![[types]] = !{}

diff  --git a/clang/test/CodeGenCXX/template-alias.cpp b/clang/test/CodeGenCXX/template-alias.cpp
new file mode 100644
index 00000000000000..256ed693aa2fe7
--- /dev/null
+++ b/clang/test/CodeGenCXX/template-alias.cpp
@@ -0,0 +1,47 @@
+// RUN: %clang_cc1 -triple x86_64-unk-unk -o - -emit-llvm -debug-info-kind=standalone -gtemplate-alias %s -gsimple-template-names=simple \
+// RUN: | FileCheck %s --check-prefixes=ALIAS-SIMPLE,ALIAS-ALL
+
+// RUN: %clang_cc1 -triple x86_64-unk-unk -o - -emit-llvm -debug-info-kind=standalone -gtemplate-alias %s -gsimple-template-names=mangled \
+// RUN: | FileCheck %s --check-prefixes=ALIAS-MANGLED,ALIAS-ALL
+
+// RUN: %clang_cc1 -triple x86_64-unk-unk -o - -emit-llvm -debug-info-kind=standalone -gtemplate-alias %s  \
+// RUN: | FileCheck %s --check-prefixes=ALIAS-FULL,ALIAS-ALL
+
+// RUN: %clang_cc1 -triple x86_64-unk-unk -o - -emit-llvm -debug-info-kind=standalone  %s \
+// RUN: | FileCheck %s --check-prefixes=TYPEDEF
+
+
+//// Check that -gtemplate-alias causes DW_TAG_template_alias emission for
+//// template aliases, and that respects gsimple-template-names.
+////
+//// Test type and value template parameters.
+
+template<typename Y, int Z>
+struct X {
+  Y m1 = Z;
+};
+
+template<typename B, int C>
+using A = X<B, C>;
+
+A<int, 5> a;
+
+
+// ALIAS-SIMPLE: !DIDerivedType(tag: DW_TAG_template_alias, name: "A", file: ![[#]], line: [[#]], baseType: ![[baseType:[0-9]+]], extraData: ![[extraData:[0-9]+]])
+// ALIAS-SIMPLE: ![[baseType]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "X",
+
+// FIXME: Mangled name is wrong (not a regression).
+// ALIAS-MANGLED: !DIDerivedType(tag: DW_TAG_template_alias, name: "A<int, 5>", file: ![[#]], line: [[#]], baseType: ![[baseType:[0-9]+]], extraData: ![[extraData:[0-9]+]])
+// ALIAS-MANGLED: ![[baseType]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "_STN|X|<int, 5>",
+
+// ALIAS-FULL: !DIDerivedType(tag: DW_TAG_template_alias, name: "A<int, 5>", file: ![[#]], line: [[#]], baseType: ![[baseType:[0-9]+]], extraData: ![[extraData:[0-9]+]])
+// ALIAS-FULL: ![[baseType]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "X<int, 5>",
+
+// ALIAS-ALL: ![[int:[0-9]+]] = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+// ALIAS-ALL: ![[extraData]] = !{![[B:[0-9]+]], ![[C:[0-9]+]]}
+// ALIAS-ALL: ![[B]] = !DITemplateTypeParameter(name: "B", type: ![[int]])
+// ALIAS-ALL: ![[C]] = !DITemplateValueParameter(name: "C", type: ![[int]], value: i32 5)
+
+// TYPEDEF: !DIDerivedType(tag: DW_TAG_typedef, name: "A<int, 5>", file: ![[#]], line: [[#]], baseType: ![[baseType:[0-9]+]])
+// TYPEDEF: ![[baseType]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "X<int, 5>",
+// TYPEDEF: ![[int:[0-9]+]] = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)

diff  --git a/clang/test/CodeGenCXX/variadic-template-alias.cpp b/clang/test/CodeGenCXX/variadic-template-alias.cpp
new file mode 100644
index 00000000000000..b4340d60aa6ad9
--- /dev/null
+++ b/clang/test/CodeGenCXX/variadic-template-alias.cpp
@@ -0,0 +1,25 @@
+// RUN: %clang_cc1 -triple x86_64-unk-unk -o - -emit-llvm -debug-info-kind=standalone -gtemplate-alias %s -gsimple-template-names=simple \
+// RUN: | FileCheck %s
+
+//// Check that -gtemplate-alias causes DW_TAG_template_alias emission for
+//// variadic template aliases. See template-alias.cpp for more template alias
+//// tests.
+
+template<typename Y, int Z>
+struct X {
+  Y m1 = Z;
+};
+
+template<int I, typename... Ts>
+using A = X<Ts..., I>;
+
+A<5, int> a;
+
+// CHECK: !DIDerivedType(tag: DW_TAG_template_alias, name: "A", file: ![[#]], line: [[#]], baseType: ![[baseType:[0-9]+]], extraData: ![[extraData:[0-9]+]])
+// CHECK: ![[baseType]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "X",
+// CHECK: ![[int:[0-9]+]] = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+// CHECK: ![[extraData]] = !{![[I:[0-9]+]], ![[Ts:[0-9]+]]}
+// CHECK: ![[I]] = !DITemplateValueParameter(name: "I", type: ![[int]], value: i32 5)
+// CHECK: ![[Ts]] = !DITemplateValueParameter(tag: DW_TAG_GNU_template_parameter_pack, name: "Ts", value: ![[types:[0-9]+]])
+// CHECK: ![[types]] = !{![[int_template_param:[0-9]+]]}
+// CHECK: ![[int_template_param]] = !DITemplateTypeParameter(type: ![[int]])

diff  --git a/clang/test/Driver/debug-options.c b/clang/test/Driver/debug-options.c
index e4809511ac91a0..a6acfe88a38611 100644
--- a/clang/test/Driver/debug-options.c
+++ b/clang/test/Driver/debug-options.c
@@ -465,3 +465,13 @@
 // MANGLED_TEMP_NAMES: error: unknown argument '-gsimple-template-names=mangled'; did you mean '-Xclang -gsimple-template-names=mangled'
 // RUN: %clang -### -target x86_64 -c -g %s 2>&1 | FileCheck --check-prefix=FULL_TEMP_NAMES --implicit-check-not=debug-forward-template-params %s
 // FULL_TEMP_NAMES-NOT: -gsimple-template-names
+
+//// Test -g[no-]template-alias (enabled by default with SCE debugger tuning and DWARFv5).
+// RUN: %clang -### -target x86_64 -c -gdwarf-5 -gsce %s 2>&1 | FileCheck %s --check-prefixes=TEMPLATE-ALIAS
+// RUN: %clang -### -target x86_64 -c -gdwarf-4 -gsce %s 2>&1 | FileCheck %s --check-prefixes=NO-TEMPLATE-ALIAS
+// RUN: %clang -### -target x86_64 -c -gdwarf-5 -gsce -gtemplate-alias %s 2>&1 | FileCheck %s --check-prefixes=TEMPLATE-ALIAS
+// RUN: %clang -### -target x86_64 -c -gdwarf-5 -gsce -gno-template-alias %s 2>&1 | FileCheck %s --check-prefixes=NO-TEMPLATE-ALIAS
+// RUN: %clang -### -target x86_64 -c -gdwarf-5 -gtemplate-alias %s 2>&1 | FileCheck %s --check-prefixes=TEMPLATE-ALIAS
+// RUN: %clang -### -target x86_64 -c -gdwarf-5 -gtemplate-alias -gno-template-alias %s 2>&1 | FileCheck %s --check-prefixes=NO-TEMPLATE-ALIAS
+// TEMPLATE-ALIAS: "-gtemplate-alias"
+// NO-TEMPLATE-ALIAS-NOT: "-gtemplate-alias"


        


More information about the cfe-commits mailing list