probinson created this revision.

If a template instantiation uses a typedef'd name as a template parameter, this 
is usually resolved
to its underlying type when we generate the name of the instance in the debug 
info.
PS4 prefers to see the original parameter as in the source.  Define an option 
that makes that happen,
and have the default for the option depend on debugger tuning.

This also provides some motivation for https://reviews.llvm.org/D14358.


https://reviews.llvm.org/D35715

Files:
  include/clang/AST/PrettyPrinter.h
  include/clang/AST/TemplateBase.h
  include/clang/AST/Type.h
  include/clang/Basic/LangOptions.def
  include/clang/Driver/Options.td
  lib/AST/TemplateBase.cpp
  lib/AST/Type.cpp
  lib/Driver/ToolChains/Clang.cpp
  lib/Frontend/CompilerInvocation.cpp
  lib/Sema/SemaTemplate.cpp
  test/CodeGen/debug-template-types.cpp
  test/Driver/clang_f_opts.c
  test/Index/print-type.cpp

Index: test/Index/print-type.cpp
===================================================================
--- test/Index/print-type.cpp
+++ test/Index/print-type.cpp
@@ -119,7 +119,9 @@
 // CHECK: TemplateRef=Baz:9:8 [type=] [typekind=Invalid] [isPOD=0]
 // CHECK: IntegerLiteral= [type=int] [typekind=Int] [isPOD=1]
 // CHECK: TemplateRef=Foo:4:8 [type=] [typekind=Invalid] [isPOD=0]
-// CHECK: FieldDecl=qux:29:38 (Definition) [type=Qux<int, char *, Foo<int>, outer::inner::Bar::FooType>] [typekind=Unexposed] [templateargs/4= [type=int] [typekind=Int] [type=char *] [typekind=Pointer] [type=Foo<int>] [typekind=Unexposed] [type=outer::inner::Bar::FooType] [typekind=Typedef]] [canonicaltype=outer::Qux<int, char *, outer::Foo<int>, int>] [canonicaltypekind=Record] [canonicaltemplateargs/4= [type=int] [typekind=Int] [type=char *] [typekind=Pointer] [type=outer::Foo<int>] [typekind=Record] [type=int] [typekind=Int]] [isPOD=1]
+// The expression in the next line is for -femit-typedefs-in-template-types
+// which is the default on PS4.
+// CHECK: FieldDecl=qux:29:38 (Definition) [type=Qux<int, char *, Foo<int>, outer::inner::Bar::FooType>] [typekind=Unexposed] [templateargs/4= [type=int] [typekind=Int] [type=char *] [typekind=Pointer] [type=Foo<int>] [typekind=Unexposed] [type=outer::inner::Bar::FooType] [typekind=Typedef]] [canonicaltype=outer::Qux<int, char *, outer::Foo<int>, {{int|outer::inner::Bar::FooType}}>] [canonicaltypekind=Record] [canonicaltemplateargs/4= [type=int] [typekind=Int] [type=char *] [typekind=Pointer] [type=outer::Foo<int>] [typekind=Record] [type=int] [typekind=Int]] [isPOD=1]
 // CHECK: TemplateRef=Qux:12:8 [type=] [typekind=Invalid] [isPOD=0]
 // CHECK: TemplateRef=Foo:4:8 [type=] [typekind=Invalid] [isPOD=0]
 // CHECK: FunctionTemplate=tbar:36:3 [type=T (int)] [typekind=FunctionProto] [canonicaltype=type-parameter-0-0 (int)] [canonicaltypekind=FunctionProto] [resulttype=T] [resulttypekind=Unexposed] [isPOD=0]
Index: test/Driver/clang_f_opts.c
===================================================================
--- test/Driver/clang_f_opts.c
+++ test/Driver/clang_f_opts.c
@@ -496,3 +496,10 @@
 // RUN: %clang -### -S -fno-allow-editor-placeholders %s 2>&1 | FileCheck -check-prefix=CHECK-NO-ALLOW-PLACEHOLDERS %s
 // CHECK-ALLOW-PLACEHOLDERS: -fallow-editor-placeholders
 // CHECK-NO-ALLOW-PLACEHOLDERS-NOT: -fallow-editor-placeholders
+
+// RUN: %clang -### -femit-typedefs-in-template-types %s 2>&1 | FileCheck -check-prefix=CHECK-EMIT-TYPEDEF-NAMES %s
+// RUN: %clang -### -fno-emit-typedefs-in-template-types %s 2>&1 | FileCheck -check-prefix=CHECK-NO-EMIT-TYPEDEF-NAMES %s
+// RUN: %clang -### -gsce %s 2>&1 | FileCheck -check-prefix=CHECK-EMIT-TYPEDEF-NAMES %s
+// RUN: %clang -### -ggdb %s 2>&1 | FileCheck -check-prefix=CHECK-NO-EMIT-TYPEDEF-NAMES %s
+// CHECK-EMIT-TYPEDEF-NAMES:        -femit-typedefs-in-template-types
+// CHECK-NO-EMIT-TYPEDEF-NAMES-NOT: -femit-typedefs-in-template-types
Index: test/CodeGen/debug-template-types.cpp
===================================================================
--- test/CodeGen/debug-template-types.cpp
+++ test/CodeGen/debug-template-types.cpp
@@ -0,0 +1,94 @@
+// RUN: %clang_cc1 -debug-info-kind=standalone -fgnu-keywords -std=c++11 -femit-typedefs-in-template-types -emit-llvm %s -o - | FileCheck %s
+
+// With -femit-typedefs-in-template-types, template parameter type names should
+// not be stripped of typedef names. This test tries some more complicated
+// cases to check that we don't drop qualifiers and attach them correctly to
+// the typename.
+
+
+class A
+{
+public:
+  int i;
+  A(){}
+};
+
+typedef A myA;
+
+myA a1;
+
+volatile decltype(a1) a;
+
+template <typename T> 
+class B
+{
+  T t;
+};
+
+// See that we collect all the qualifiers while finding the topmost typedef 
+B<const typeof(a)> b;
+// CHECK-DAG: !DICompositeType(tag: DW_TAG_class_type, name: "B<const volatile myA>"
+
+class C
+{
+public:
+  C(){}
+  C(volatile C&){}
+};
+
+typedef volatile C myC;
+
+const myC c;
+
+template <typename T> 
+class D
+{
+  T t;
+};
+
+// See that we don't add the typedef's qualifiers to the type name
+D<decltype(c)> d;
+// CHECK-DAG: !DICompositeType(tag: DW_TAG_class_type, name: "D<const myC>"
+
+
+typedef int func();
+typedef float myFloat;
+
+template <typename ...T>
+class F
+{
+  void foo(T...);
+};
+
+// See that we deal with parameter packs
+F<func, volatile myFloat> f;
+// CHECK-DAG: !DICompositeType(tag: DW_TAG_class_type, name: "F<func, volatile myFloat>"
+
+
+template <typename T, typename S = myA>
+class G
+{
+  T t;
+  S s;
+};
+
+// See that we display parameters that are template types and default 
+// parameters correctly
+G<D<myC>> g;
+// CHECK-DAG: !DICompositeType(tag: DW_TAG_class_type, name: "G<D<myC>, myA>"
+
+template <typename T>
+T foo(T t)
+{
+  return t;
+}
+
+template <> 
+const myC foo<const myC>(const myC)
+{
+  myC c;
+  return c;
+}
+
+// See that we do display the typedef names for function types also
+// CHECK-DAG: !DISubprogram(name: "foo<const myC>"
Index: lib/Sema/SemaTemplate.cpp
===================================================================
--- lib/Sema/SemaTemplate.cpp
+++ lib/Sema/SemaTemplate.cpp
@@ -4165,6 +4165,8 @@
   if (CheckTemplateArgument(Param, TSI))
     return true;
 
+  QualType DisplayArgType = ArgType.getDisplayType(Context);
+
   // Add the converted template type argument.
   ArgType = Context.getCanonicalType(ArgType);
 
@@ -4179,7 +4181,7 @@
     ArgType = Context.getQualifiedType(ArgType, Qs);
   }
 
-  Converted.push_back(TemplateArgument(ArgType));
+  Converted.push_back(TemplateArgument(ArgType, DisplayArgType));
   return false;
 }
 
Index: lib/Frontend/CompilerInvocation.cpp
===================================================================
--- lib/Frontend/CompilerInvocation.cpp
+++ lib/Frontend/CompilerInvocation.cpp
@@ -2386,6 +2386,11 @@
   case 3: Opts.setStackProtector(LangOptions::SSPReq); break;
   }
 
+  // Whether to emit template type names while preserving typedef names in the
+  // template parameter types.
+  Opts.EmitTypedefNamesInTemplateTypes = 
+    Args.hasArg(OPT_femit_typedefs_in_template_types);
+
   // Parse -fsanitize= arguments.
   parseSanitizerKinds("-fsanitize=", Args.getAllArgValues(OPT_fsanitize_EQ),
                       Diags, Opts.Sanitize);
Index: lib/Driver/ToolChains/Clang.cpp
===================================================================
--- lib/Driver/ToolChains/Clang.cpp
+++ lib/Driver/ToolChains/Clang.cpp
@@ -2833,6 +2833,12 @@
     CmdArgs.push_back("-generate-type-units");
   }
 
+  // PS4 prefers to keep typedef names in template parameters.
+  if (Args.hasFlag(options::OPT_femit_typedefs_in_template_types,
+                   options::OPT_fno_emit_typedefs_in_template_types,
+                   DebuggerTuning == llvm::DebuggerKind::SCE))
+    CmdArgs.push_back("-femit-typedefs-in-template-types");
+
   RenderDebugInfoCompressionArgs(Args, CmdArgs, D);
 
   bool UseSeparateSections = isUseSeparateSections(Triple);
Index: lib/AST/Type.cpp
===================================================================
--- lib/AST/Type.cpp
+++ lib/AST/Type.cpp
@@ -255,6 +255,24 @@
   }
 }
 
+// Returns a type that removes decltype and typeof but preserves typedef types
+// as well as all qualifers that are not provided by the typedef types
+// themselves.  The goal is to provide a type that looks reasonably close to
+// what is in the source.
+QualType QualType::getDisplayType(const ASTContext &Context) const {
+  QualifierCollector Qs;
+
+  QualType Cur = *this;
+  while (true) {
+    // Collect the qualifiers in Qs as we are desugaring the type 
+    const Type *CurTy = Qs.strip(Cur);
+    QualType Desugar = Cur.getSingleStepDesugaredType(Context); 
+    if (Cur == Desugar || CurTy->getTypeClass() == Type::Typedef)
+      return Qs.apply(Context, CurTy);
+    Cur = Desugar; 
+  }
+}
+
 SplitQualType QualType::getSplitUnqualifiedTypeImpl(QualType type) {
   SplitQualType split = type.split();
 
Index: lib/AST/TemplateBase.cpp
===================================================================
--- lib/AST/TemplateBase.cpp
+++ lib/AST/TemplateBase.cpp
@@ -386,7 +386,10 @@
   case Type: {
     PrintingPolicy SubPolicy(Policy);
     SubPolicy.SuppressStrongLifetime = true;
-    getAsType().print(Out, SubPolicy);
+    if (SubPolicy.PrintTemplateTypesWithTypedefs)
+      getAsDisplayType().print(Out, SubPolicy);
+    else
+      getAsType().print(Out, SubPolicy);
     break;
   }
     
Index: include/clang/Driver/Options.td
===================================================================
--- include/clang/Driver/Options.td
+++ include/clang/Driver/Options.td
@@ -1381,6 +1381,14 @@
   HelpText<"Emit macro debug information">;
 def fno_debug_macro : Flag<["-"], "fno-debug-macro">, Group<f_Group>, Flags<[CoreOption]>,
   HelpText<"Do not emit macro debug information">;
+def femit_typedefs_in_template_types :
+  Flag<["-"], "femit-typedefs-in-template-types">, Group<f_Group>,
+  Flags<[CC1Option, HelpHidden]>,
+  HelpText<"Preserve typedef names in debug info for template types">;
+def fno_emit_typedefs_in_template_types :
+  Flag<["-"], "fno-emit-typedefs-in-template-types">, Group<f_Group>,
+  Flags<[CC1Option, HelpHidden]>,
+  HelpText<"Use canonical type names in debug info for template types">;
 def fstrict_aliasing : Flag<["-"], "fstrict-aliasing">, Group<f_Group>,
   Flags<[DriverOption, CoreOption]>;
 def fstrict_enums : Flag<["-"], "fstrict-enums">, Group<f_Group>, Flags<[CC1Option]>,
Index: include/clang/Basic/LangOptions.def
===================================================================
--- include/clang/Basic/LangOptions.def
+++ include/clang/Basic/LangOptions.def
@@ -260,6 +260,11 @@
 
 LANGOPT(ApplePragmaPack, 1, 0, "Apple gcc-compatible #pragma pack handling")
 
+// Emit template type names with typedef names in the template parameters,
+// when recording them in DWARF, rather than the canonical type.
+LANGOPT(EmitTypedefNamesInTemplateTypes, 1, 0,
+        "emit typedef names in template types (DWARF)")
+
 LANGOPT(RetainCommentsFromSystemHeaders, 1, 0, "retain documentation comments from system headers in the AST")
 
 LANGOPT(SanitizeAddressFieldPadding, 2, 0, "controls how aggressive is ASan "
Index: include/clang/AST/Type.h
===================================================================
--- include/clang/AST/Type.h
+++ include/clang/AST/Type.h
@@ -843,6 +843,10 @@
 
   QualType getCanonicalType() const;
 
+  /// Returns the type that should be used in contexts that require
+  /// representation that closely resembles what is written in the source. 
+  QualType getDisplayType(const ASTContext &Context) const;
+
   /// \brief Return this type with all of the instance-specific qualifiers
   /// removed, but without removing any qualifiers that may have been applied
   /// through typedefs.
Index: include/clang/AST/TemplateBase.h
===================================================================
--- include/clang/AST/TemplateBase.h
+++ include/clang/AST/TemplateBase.h
@@ -106,6 +106,9 @@
   struct TV {
     unsigned Kind;
     uintptr_t V;
+    // This is the type that most closely resembles what is in the source.
+    // At the moment it is retaining typedefs, but not decltype or typeof.
+    uintptr_t DisplayType;
   };
   union {
     struct DA DeclArg;
@@ -119,12 +122,21 @@
   
 public:
   /// \brief Construct an empty, invalid template argument.
-  constexpr TemplateArgument() : TypeOrValue({Null, 0}) {}
+  constexpr TemplateArgument() : TypeOrValue({Null, 0, 0}) {}
 
   /// \brief Construct a template type argument.
   TemplateArgument(QualType T, bool isNullPtr = false) {
     TypeOrValue.Kind = isNullPtr ? NullPtr : Type;
+    TypeOrValue.V = TypeOrValue.DisplayType =
+      reinterpret_cast<uintptr_t>(T.getAsOpaquePtr());
+  }
+
+  /// Construct a template type argument and record the display type.
+  TemplateArgument(QualType T, QualType DisplayType, bool isNullPtr = false) {
+    TypeOrValue.Kind = isNullPtr ? NullPtr : Type;
     TypeOrValue.V = reinterpret_cast<uintptr_t>(T.getAsOpaquePtr());
+    TypeOrValue.DisplayType = 
+      reinterpret_cast<uintptr_t>(DisplayType.getAsOpaquePtr());
   }
 
   /// \brief Construct a template argument that refers to a
@@ -237,6 +249,12 @@
     return QualType::getFromOpaquePtr(reinterpret_cast<void*>(TypeOrValue.V));
   }
 
+  /// Retrieve the display type for a type template argument.
+  QualType getAsDisplayType() const {
+    assert(getKind() == Type && "Unexpected kind");
+    return QualType::getFromOpaquePtr(reinterpret_cast<void*>(TypeOrValue.DisplayType));
+  }
+
   /// \brief Retrieve the declaration for a declaration non-type
   /// template argument.
   ValueDecl *getAsDecl() const {
Index: include/clang/AST/PrettyPrinter.h
===================================================================
--- include/clang/AST/PrettyPrinter.h
+++ include/clang/AST/PrettyPrinter.h
@@ -50,7 +50,8 @@
       UseVoidForZeroParams(!LO.CPlusPlus),
       TerseOutput(false), PolishForDeclaration(false),
       Half(LO.Half), MSWChar(LO.MicrosoftExt && !LO.WChar),
-      IncludeNewlines(true), MSVCFormatting(false) { }
+      IncludeNewlines(true), MSVCFormatting(false),
+      PrintTemplateTypesWithTypedefs(LO.EmitTypedefNamesInTemplateTypes) { }
 
   /// \brief Adjust this printing policy for cases where it's known that
   /// we're printing C++ code (for instance, if AST dumping reaches a
@@ -200,6 +201,9 @@
   /// prints anonymous namespaces as `anonymous namespace' and does not insert
   /// spaces after template arguments.
   bool MSVCFormatting : 1;
+
+  /// \brief When true, print template type arguments without removing typedefs.
+  unsigned PrintTemplateTypesWithTypedefs : 1;
 };
 
 } // end namespace clang
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to