diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h --- a/clang/include/clang/AST/ASTContext.h +++ b/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() { diff --git a/clang/include/clang/Basic/Builtins.h b/clang/include/clang/Basic/Builtins.h --- a/clang/include/clang/Basic/Builtins.h +++ b/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 diff --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h --- a/clang/include/clang/Serialization/ASTBitCodes.h +++ b/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. diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp --- a/clang/lib/AST/ASTContext.cpp +++ b/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; diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp --- a/clang/lib/AST/ASTImporter.cpp +++ b/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); diff --git a/clang/lib/AST/DeclTemplate.cpp b/clang/lib/AST/DeclTemplate.cpp --- a/clang/lib/AST/DeclTemplate.cpp +++ b/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!"); diff --git a/clang/lib/Lex/PPMacroExpansion.cpp b/clang/lib/Lex/PPMacroExpansion.cpp --- a/clang/lib/Lex/PPMacroExpansion.cpp +++ b/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. diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp --- a/clang/lib/Sema/SemaLookup.cpp +++ b/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; } } diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/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 // 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!"); } diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp --- a/clang/lib/Serialization/ASTReader.cpp +++ b/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"); } diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/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 diff --git a/clang/test/SemaCXX/libstdcxx_transform_type_traits_hack.cpp b/clang/test/SemaCXX/libstdcxx_transform_type_traits_hack.cpp --- a/clang/test/SemaCXX/libstdcxx_transform_type_traits_hack.cpp +++ b/clang/test/SemaCXX/libstdcxx_transform_type_traits_hack.cpp @@ -58,11 +58,6 @@ template using J = Same<__remove_cvref, __remove_cvref>; -template -using __decay = int; // expected-warning{{keyword '__decay' will be made available as an identifier here}} -template -using K = Same<__decay, __decay>; - template using __make_signed = int; // expected-warning{{keyword '__make_signed' will be made available as an identifier here}} template diff --git a/clang/test/SemaCXX/type-traits.cpp b/clang/test/SemaCXX/type-traits.cpp --- a/clang/test/SemaCXX/type-traits.cpp +++ b/clang/test/SemaCXX/type-traits.cpp @@ -3414,6 +3414,50 @@ static_assert(__is_same(decay_t, int S::*), ""); } +void check_decay_template() { + static_assert(__is_same(__decay, void), ""); + static_assert(__is_same(__decay, void), ""); + static_assert(__is_same(__decay, int), ""); + static_assert(__is_same(__decay, int), ""); + static_assert(__is_same(__decay, int), ""); + static_assert(__is_same(__decay, int), ""); + static_assert(__is_same(__decay, int *), ""); + static_assert(__is_same(__decay, int *), ""); + static_assert(__is_same(__decay, int *), ""); + static_assert(__is_same(__decay, int const *), ""); + static_assert(__is_same(__decay, int const *), ""); + static_assert(__is_same(__decay, int), ""); + static_assert(__is_same(__decay, int), ""); + static_assert(__is_same(__decay, int), ""); + static_assert(__is_same(__decay, int), ""); + static_assert(__is_same(__decay, int (*)()), ""); + static_assert(__is_same(__decay, int (*)()), ""); + static_assert(__is_same(__decay, int (*)()), ""); + static_assert(__is_same(__decay, int (*)()), ""); + static_assert(__is_same(__decay, int (*)()), ""); + static_assert(__is_same(__decay, int (*)()), ""); + static_assert(__is_same(__decay, int *), ""); + static_assert(__is_same(__decay, int *), ""); + + static_assert(__is_same(__decay, S), ""); + static_assert(__is_same(__decay, S), ""); + static_assert(__is_same(__decay, S), ""); + static_assert(__is_same(__decay, S), ""); + static_assert(__is_same(__decay, S), ""); + static_assert(__is_same(__decay, S), ""); + static_assert(__is_same(__decay, S), ""); + static_assert(__is_same(__decay, S), ""); + static_assert(__is_same(__decay, S), ""); + static_assert(__is_same(__decay, S), ""); + static_assert(__is_same(__decay, S), ""); + static_assert(__is_same(__decay, S), ""); + static_assert(__is_same(__decay, int S::*), ""); + static_assert(__is_same(__decay, int(S::*)()), ""); + static_assert(__is_same(__decay, int S::*), ""); + static_assert(__is_same(__decay, int(S::*)()), ""); + static_assert(__is_same(__decay, int S::*), ""); +} + template struct CheckAbominableFunction {}; template struct CheckAbominableFunction {