diff --git a/clang/include/clang/Basic/TransformTypeTraits.def b/clang/include/clang/Basic/TransformTypeTraits.def index e27a2719a9680..15313fb2db01e 100644 --- a/clang/include/clang/Basic/TransformTypeTraits.def +++ b/clang/include/clang/Basic/TransformTypeTraits.def @@ -26,4 +26,6 @@ TRANSFORM_TYPE_TRAIT_DEF(RemoveReference, remove_reference_t) TRANSFORM_TYPE_TRAIT_DEF(RemoveRestrict, remove_restrict) TRANSFORM_TYPE_TRAIT_DEF(RemoveVolatile, remove_volatile) TRANSFORM_TYPE_TRAIT_DEF(EnumUnderlyingType, underlying_type) +TRANSFORM_TYPE_TRAIT_DEF(DedupTemplateArgs, dedup_template_args) + #undef TRANSFORM_TYPE_TRAIT_DEF diff --git a/clang/include/clang/Sema/DeclSpec.h b/clang/include/clang/Sema/DeclSpec.h index 06243f2624876..bad26ef1c243b 100644 --- a/clang/include/clang/Sema/DeclSpec.h +++ b/clang/include/clang/Sema/DeclSpec.h @@ -472,7 +472,7 @@ class DeclSpec { T == TST_class); } static bool isTransformTypeTrait(TST T) { - constexpr std::array Traits = { + constexpr std::array Traits = { #define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) TST_##Trait, #include "clang/Basic/TransformTypeTraits.def" }; diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 1f7e555d1b871..9117ca40b589a 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -14899,6 +14899,7 @@ class Sema final : public SemaBase { QualType BuildUnaryTransformType(QualType BaseType, UTTKind UKind, SourceLocation Loc); QualType BuiltinEnumUnderlyingType(QualType BaseType, SourceLocation Loc); + QualType BuiltinDedupTemplateArgs(QualType BaseType, SourceLocation Loc); QualType BuiltinAddPointer(QualType BaseType, SourceLocation Loc); QualType BuiltinRemovePointer(QualType BaseType, SourceLocation Loc); QualType BuiltinDecay(QualType BaseType, SourceLocation Loc); diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index f8f41d0bafffc..4214f7bd46adb 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -17,7 +17,9 @@ #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/RecursiveASTVisitor.h" +#include "clang/AST/TemplateBase.h" #include "clang/AST/TemplateName.h" +#include "clang/AST/Type.h" #include "clang/AST/TypeVisitor.h" #include "clang/Basic/Builtins.h" #include "clang/Basic/DiagnosticSema.h" @@ -38,9 +40,12 @@ #include "clang/Sema/Template.h" #include "clang/Sema/TemplateDeduction.h" #include "llvm/ADT/BitVector.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/DenseSet.h" #include "llvm/ADT/SmallBitVector.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/Support/TimeProfiler.h" #include #include diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 4b1bb05464f7d..a7590dc27561c 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -50,6 +50,7 @@ #include "llvm/IR/DerivedTypes.h" #include "llvm/Support/Casting.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/TimeProfiler.h" #include #include @@ -9584,6 +9585,33 @@ QualType Sema::BuiltinEnumUnderlyingType(QualType BaseType, return GetEnumUnderlyingType(*this, BaseType, Loc); } +QualType Sema::BuiltinDedupTemplateArgs(QualType BaseType, SourceLocation Loc) { + llvm::TimeTraceScope TimeTrace("BuiltinDedupTemplateArgs"); + if (RequireCompleteType(Loc, BaseType, + diag::err_incomplete_type_used_in_type_trait_expr)) + return QualType(); + const ElaboratedType *ET = cast(BaseType); + auto *TST = ET->getNamedType()->castAs(); + if (!TST) { + Diag(Loc, diag::err_incomplete_type_used_in_type_trait_expr) << BaseType; + return QualType(); + } + TemplateArgumentListInfo Args(Loc, Loc); + llvm::DenseSet SeenArgTypes; + for (const auto &Arg : TST->template_arguments()) { + if (!SeenArgTypes.insert(Arg.getAsType().getCanonicalType()).second) + continue; + Args.addArgument(TemplateArgumentLoc( + Arg, Context.getTrivialTypeSourceInfo(Arg.getAsType(), Loc))); + } + QualType DedupedTypes = + CheckTemplateIdType(TST->getTemplateName(), Loc, Args); + if (RequireCompleteType(Loc, DedupedTypes, + diag::err_incomplete_type_used_in_type_trait_expr)) + return QualType(); + return DedupedTypes; +} + QualType Sema::BuiltinAddPointer(QualType BaseType, SourceLocation Loc) { QualType Pointer = BaseType.isReferenceable() || BaseType->isVoidType() ? BuildPointerType(BaseType.getNonReferenceType(), Loc, @@ -9758,6 +9786,10 @@ QualType Sema::BuildUnaryTransformType(QualType BaseType, UTTKind UKind, Result = BuiltinEnumUnderlyingType(BaseType, Loc); break; } + case UnaryTransformType::DedupTemplateArgs: { + Result = BuiltinDedupTemplateArgs(BaseType, Loc); + break; + } case UnaryTransformType::AddPointer: { Result = BuiltinAddPointer(BaseType, Loc); break; diff --git a/clang/test/SemaCXX/type-traits.cpp b/clang/test/SemaCXX/type-traits.cpp index bf069d9bc082c..7dbf7a1c4edb6 100644 --- a/clang/test/SemaCXX/type-traits.cpp +++ b/clang/test/SemaCXX/type-traits.cpp @@ -5014,3 +5014,10 @@ void remove_all_extents() { using SomeArray = int[1][2]; static_assert(__is_same(remove_all_extents_t, const int)); } + +template using dedup_template_args_t = __dedup_template_args(T); +template struct TypeList{}; +void dedup_types() { + static_assert(__is_same(dedup_template_args_t>, + TypeList)); +}