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