troyj created this revision.
troyj added a reviewer: bruno.
Herald added a subscriber: martong.
Herald added a reviewer: shafik.
Herald added a project: All.
troyj requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

`__decay(T)` exists as a builtin, but does not use template syntax like the 
other builtin templates `__make_integer_seq` and `__type_pack_element`. With 
template syntax, users can write portable code that uses `__decay<T>` when it's 
available but falls back to a `__decay<T>` in a local namespace when it's not 
available. Template aliasing can provide the same behavior, but at the cost of 
longer compile time. It is faster to compile a direct use of a builtin than a 
use via an alias. This compile time difference is measurable in large TUs that 
make heavy use of templates. Currently the only performant alternative is to 
use preprocessor macros in the user's code.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D137458

Files:
  clang/include/clang/AST/ASTContext.h
  clang/include/clang/Basic/Builtins.h
  clang/include/clang/Serialization/ASTBitCodes.h
  clang/lib/AST/ASTContext.cpp
  clang/lib/AST/ASTImporter.cpp
  clang/lib/AST/DeclTemplate.cpp
  clang/lib/Lex/PPMacroExpansion.cpp
  clang/lib/Sema/SemaLookup.cpp
  clang/lib/Sema/SemaTemplate.cpp
  clang/lib/Serialization/ASTReader.cpp
  clang/lib/Serialization/ASTWriter.cpp
  clang/test/SemaCXX/libstdcxx_transform_type_traits_hack.cpp
  clang/test/SemaCXX/type-traits.cpp

Index: clang/test/SemaCXX/type-traits.cpp
===================================================================
--- clang/test/SemaCXX/type-traits.cpp
+++ clang/test/SemaCXX/type-traits.cpp
@@ -3414,6 +3414,50 @@
   static_assert(__is_same(decay_t<int S::*const volatile &&>, int S::*), "");
 }
 
+void check_decay_template() {
+  static_assert(__is_same(__decay<void>, void), "");
+  static_assert(__is_same(__decay<const volatile void>, void), "");
+  static_assert(__is_same(__decay<int>, int), "");
+  static_assert(__is_same(__decay<const int>, int), "");
+  static_assert(__is_same(__decay<volatile int>, int), "");
+  static_assert(__is_same(__decay<const volatile int>, int), "");
+  static_assert(__is_same(__decay<int *>, int *), "");
+  static_assert(__is_same(__decay<int *const volatile>, int *), "");
+  static_assert(__is_same(__decay<int *const volatile __restrict>, int *), "");
+  static_assert(__is_same(__decay<int const *const volatile>, int const *), "");
+  static_assert(__is_same(__decay<int const *const volatile _Nonnull>, int const *), "");
+  static_assert(__is_same(__decay<int &>, int), "");
+  static_assert(__is_same(__decay<int const volatile &>, int), "");
+  static_assert(__is_same(__decay<int &&>, int), "");
+  static_assert(__is_same(__decay<int const volatile &&>, int), "");
+  static_assert(__is_same(__decay<int()>, int (*)()), "");
+  static_assert(__is_same(__decay<int (*)()>, int (*)()), "");
+  static_assert(__is_same(__decay<int (*const)()>, int (*)()), "");
+  static_assert(__is_same(__decay<int (*volatile)()>, int (*)()), "");
+  static_assert(__is_same(__decay<int (*const volatile)()>, int (*)()), "");
+  static_assert(__is_same(__decay<int (&)()>, int (*)()), "");
+  static_assert(__is_same(__decay<IntAr>, int *), "");
+  static_assert(__is_same(__decay<IntArNB>, int *), "");
+
+  static_assert(__is_same(__decay<S>, S), "");
+  static_assert(__is_same(__decay<S &>, S), "");
+  static_assert(__is_same(__decay<S &&>, S), "");
+  static_assert(__is_same(__decay<const S>, S), "");
+  static_assert(__is_same(__decay<const S &>, S), "");
+  static_assert(__is_same(__decay<const S &&>, S), "");
+  static_assert(__is_same(__decay<volatile S>, S), "");
+  static_assert(__is_same(__decay<volatile S &>, S), "");
+  static_assert(__is_same(__decay<volatile S &&>, S), "");
+  static_assert(__is_same(__decay<const volatile S>, S), "");
+  static_assert(__is_same(__decay<const volatile S &>, S), "");
+  static_assert(__is_same(__decay<const volatile S &&>, S), "");
+  static_assert(__is_same(__decay<int S::*const volatile>, int S::*), "");
+  static_assert(__is_same(__decay<int (S::*const volatile)()>, int(S::*)()), "");
+  static_assert(__is_same(__decay<int S::*const volatile &>, int S::*), "");
+  static_assert(__is_same(__decay<int (S::*const volatile &)()>, int(S::*)()), "");
+  static_assert(__is_same(__decay<int S::*const volatile &&>, int S::*), "");
+}
+
 template <class T> struct CheckAbominableFunction {};
 template <class M>
 struct CheckAbominableFunction<M S::*> {
Index: clang/test/SemaCXX/libstdcxx_transform_type_traits_hack.cpp
===================================================================
--- clang/test/SemaCXX/libstdcxx_transform_type_traits_hack.cpp
+++ clang/test/SemaCXX/libstdcxx_transform_type_traits_hack.cpp
@@ -58,11 +58,6 @@
 template <class T>
 using J = Same<__remove_cvref<T>, __remove_cvref<T>>;
 
-template <class T>
-using __decay = int; // expected-warning{{keyword '__decay' will be made available as an identifier here}}
-template <class T>
-using K = Same<__decay<T>, __decay<T>>;
-
 template <class T>
 using __make_signed = int; // expected-warning{{keyword '__make_signed' will be made available as an identifier here}}
 template <class T>
Index: clang/lib/Serialization/ASTWriter.cpp
===================================================================
--- clang/lib/Serialization/ASTWriter.cpp
+++ clang/lib/Serialization/ASTWriter.cpp
@@ -4621,6 +4621,7 @@
                      PREDEF_DECL_CF_CONSTANT_STRING_TAG_ID);
   RegisterPredefDecl(Context.TypePackElementDecl,
                      PREDEF_DECL_TYPE_PACK_ELEMENT_ID);
+  RegisterPredefDecl(Context.DecayDecl, PREDEF_DECL_DECAY_ID);
 
   // Build a record containing all of the tentative definitions in this file, in
   // TentativeDefinitions order.  Generally, this record will be empty for
Index: clang/lib/Serialization/ASTReader.cpp
===================================================================
--- clang/lib/Serialization/ASTReader.cpp
+++ clang/lib/Serialization/ASTReader.cpp
@@ -7433,6 +7433,9 @@
 
   case PREDEF_DECL_TYPE_PACK_ELEMENT_ID:
     return Context.getTypePackElementDecl();
+
+  case PREDEF_DECL_DECAY_ID:
+    return Context.getDecayDecl();
   }
   llvm_unreachable("PredefinedDeclIDs unknown enum value");
 }
Index: clang/lib/Sema/SemaTemplate.cpp
===================================================================
--- clang/lib/Sema/SemaTemplate.cpp
+++ clang/lib/Sema/SemaTemplate.cpp
@@ -3634,7 +3634,7 @@
                                        TemplateLoc, SyntheticTemplateArgs);
   }
 
-  case BTK__type_pack_element:
+  case BTK__type_pack_element: {
     // Specializations of
     //    __type_pack_element<Index, T_1, ..., T_N>
     // are treated like T_Index.
@@ -3660,6 +3660,12 @@
     int64_t N = Index.getExtValue();
     return Ts.getPackAsArray()[N].getAsType();
   }
+
+  case BTK__decay:
+    assert(Converted.size() == 1 && "__decay should be given a single type");
+    TemplateArgument Ty = Converted[0];
+    return SemaRef.BuiltinDecay(Ty.getAsType(), TemplateArgs[0].getLocation());
+  }
   llvm_unreachable("unexpected BuiltinTemplateDecl!");
 }
 
Index: clang/lib/Sema/SemaLookup.cpp
===================================================================
--- clang/lib/Sema/SemaLookup.cpp
+++ clang/lib/Sema/SemaLookup.cpp
@@ -918,6 +918,9 @@
         } else if (II == getASTContext().getTypePackElementName()) {
           R.addDecl(getASTContext().getTypePackElementDecl());
           return true;
+        } else if (II == getASTContext().getDecayName()) {
+          R.addDecl(getASTContext().getDecayDecl());
+          return true;
         }
       }
 
Index: clang/lib/Lex/PPMacroExpansion.cpp
===================================================================
--- clang/lib/Lex/PPMacroExpansion.cpp
+++ clang/lib/Lex/PPMacroExpansion.cpp
@@ -1730,6 +1730,7 @@
               // Report builtin templates as being builtins.
               .Case("__make_integer_seq", getLangOpts().CPlusPlus)
               .Case("__type_pack_element", getLangOpts().CPlusPlus)
+              .Case("__decay", getLangOpts().CPlusPlus)
               // Likewise for some builtin preprocessor macros.
               // FIXME: This is inconsistent; we usually suggest detecting
               // builtin macros via #ifdef. Don't add more cases here.
Index: clang/lib/AST/DeclTemplate.cpp
===================================================================
--- clang/lib/AST/DeclTemplate.cpp
+++ clang/lib/AST/DeclTemplate.cpp
@@ -1520,6 +1520,20 @@
                                        SourceLocation(), nullptr);
 }
 
+static TemplateParameterList *createDecayParameterList(const ASTContext &C,
+                                                       DeclContext *DC) {
+  // typename
+  auto *T = TemplateTypeParmDecl::Create(
+      C, DC, SourceLocation(), SourceLocation(), /*Depth=*/0, /*Position=*/0,
+      /*Id=*/nullptr, /*Typename=*/true, /*ParameterPack=*/false,
+      /*HasTypeConstraint=*/false);
+
+  NamedDecl *Params[] = {T};
+  return TemplateParameterList::Create(C, SourceLocation(), SourceLocation(),
+                                       llvm::makeArrayRef(Params),
+                                       SourceLocation(), nullptr);
+}
+
 static TemplateParameterList *createBuiltinTemplateParameterList(
     const ASTContext &C, DeclContext *DC, BuiltinTemplateKind BTK) {
   switch (BTK) {
@@ -1527,6 +1541,8 @@
     return createMakeIntegerSeqParameterList(C, DC);
   case BTK__type_pack_element:
     return createTypePackElementParameterList(C, DC);
+  case BTK__decay:
+    return createDecayParameterList(C, DC);
   }
 
   llvm_unreachable("unhandled BuiltinTemplateKind!");
Index: clang/lib/AST/ASTImporter.cpp
===================================================================
--- clang/lib/AST/ASTImporter.cpp
+++ clang/lib/AST/ASTImporter.cpp
@@ -5097,6 +5097,9 @@
   case BuiltinTemplateKind::BTK__type_pack_element:
     ToD = Importer.getToContext().getTypePackElementDecl();
     break;
+  case BuiltinTemplateKind::BTK__decay:
+    ToD = Importer.getToContext().getDecayDecl();
+    break;
   }
   assert(ToD && "BuiltinTemplateDecl of unsupported kind!");
   Importer.MapImported(D, ToD);
Index: clang/lib/AST/ASTContext.cpp
===================================================================
--- clang/lib/AST/ASTContext.cpp
+++ clang/lib/AST/ASTContext.cpp
@@ -1238,6 +1238,12 @@
   return TypePackElementDecl;
 }
 
+BuiltinTemplateDecl *ASTContext::getDecayDecl() const {
+  if (!DecayDecl)
+    DecayDecl = buildBuiltinTemplateDecl(BTK__decay, getDecayName());
+  return DecayDecl;
+}
+
 RecordDecl *ASTContext::buildImplicitRecord(StringRef Name,
                                             RecordDecl::TagKind TK) const {
   SourceLocation Loc;
Index: clang/include/clang/Serialization/ASTBitCodes.h
===================================================================
--- clang/include/clang/Serialization/ASTBitCodes.h
+++ clang/include/clang/Serialization/ASTBitCodes.h
@@ -1211,6 +1211,9 @@
 
   /// The internal '__type_pack_element' template.
   PREDEF_DECL_TYPE_PACK_ELEMENT_ID = 17,
+
+  /// The internal '__decay' template.
+  PREDEF_DECL_DECAY_ID = 18,
 };
 
 /// The number of declaration IDs that are predefined.
Index: clang/include/clang/Basic/Builtins.h
===================================================================
--- clang/include/clang/Basic/Builtins.h
+++ clang/include/clang/Basic/Builtins.h
@@ -292,7 +292,10 @@
   BTK__make_integer_seq,
 
   /// This names the __type_pack_element BuiltinTemplateDecl.
-  BTK__type_pack_element
+  BTK__type_pack_element,
+
+  /// This names the __decay BuiltinTemplateDecl.
+  BTK__decay
 };
 
 } // end namespace clang
Index: clang/include/clang/AST/ASTContext.h
===================================================================
--- clang/include/clang/AST/ASTContext.h
+++ clang/include/clang/AST/ASTContext.h
@@ -408,6 +408,9 @@
   /// The identifier '__type_pack_element'.
   mutable IdentifierInfo *TypePackElementName = nullptr;
 
+  /// The identifier '__decay'
+  mutable IdentifierInfo *DecayName = nullptr;
+
   QualType ObjCConstantStringType;
   mutable RecordDecl *CFConstantStringTagDecl = nullptr;
   mutable TypedefDecl *CFConstantStringTypeDecl = nullptr;
@@ -607,6 +610,7 @@
   mutable ExternCContextDecl *ExternCContext = nullptr;
   mutable BuiltinTemplateDecl *MakeIntegerSeqDecl = nullptr;
   mutable BuiltinTemplateDecl *TypePackElementDecl = nullptr;
+  mutable BuiltinTemplateDecl *DecayDecl = nullptr;
 
   /// The associated SourceManager object.
   SourceManager &SourceMgr;
@@ -1102,6 +1106,7 @@
   ExternCContextDecl *getExternCContextDecl() const;
   BuiltinTemplateDecl *getMakeIntegerSeqDecl() const;
   BuiltinTemplateDecl *getTypePackElementDecl() const;
+  BuiltinTemplateDecl *getDecayDecl() const;
 
   // Builtin Types.
   CanQualType VoidTy;
@@ -1922,6 +1927,12 @@
     return TypePackElementName;
   }
 
+  IdentifierInfo *getDecayName() const {
+    if (!DecayName)
+      DecayName = &Idents.get("__decay");
+    return DecayName;
+  }
+
   /// Retrieve the Objective-C "instancetype" type, if already known;
   /// otherwise, returns a NULL type;
   QualType getObjCInstanceType() {
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to