https://github.com/hokein updated https://github.com/llvm/llvm-project/pull/89358
>From bf6acda6c7cb9a08b82b149c0df38d90e395f9e1 Mon Sep 17 00:00:00 2001 From: Haojian Wu <hokein...@gmail.com> Date: Fri, 19 Apr 2024 10:54:12 +0200 Subject: [PATCH 1/4] [clang] CTAD: implement the missing IsDeducible constraint for alias templates. Fixes https://github.com/llvm/llvm-project/issues/85192 Fixes https://github.com/llvm/llvm-project/issues/84492 --- clang/include/clang/Basic/TokenKinds.def | 1 + clang/include/clang/Sema/Sema.h | 9 ++ clang/lib/Parse/ParseExprCXX.cpp | 16 ++-- clang/lib/Sema/SemaExprCXX.cpp | 11 +++ clang/lib/Sema/SemaTemplate.cpp | 70 ++++++++++++--- clang/lib/Sema/SemaTemplateDeduction.cpp | 87 +++++++++++++++++++ clang/test/SemaCXX/cxx20-ctad-type-alias.cpp | 26 ++++-- .../test/SemaCXX/type-traits-is-deducible.cpp | 47 ++++++++++ clang/www/cxx_status.html | 8 +- 9 files changed, 243 insertions(+), 32 deletions(-) create mode 100644 clang/test/SemaCXX/type-traits-is-deducible.cpp diff --git a/clang/include/clang/Basic/TokenKinds.def b/clang/include/clang/Basic/TokenKinds.def index a27fbed358a60..74102f4053968 100644 --- a/clang/include/clang/Basic/TokenKinds.def +++ b/clang/include/clang/Basic/TokenKinds.def @@ -537,6 +537,7 @@ TYPE_TRAIT_1(__is_referenceable, IsReferenceable, KEYCXX) TYPE_TRAIT_1(__can_pass_in_regs, CanPassInRegs, KEYCXX) TYPE_TRAIT_2(__reference_binds_to_temporary, ReferenceBindsToTemporary, KEYCXX) TYPE_TRAIT_2(__reference_constructs_from_temporary, ReferenceConstructsFromTemporary, KEYCXX) +TYPE_TRAIT_2(__is_deducible, IsDeducible, KEYCXX) // Embarcadero Expression Traits EXPRESSION_TRAIT(__is_lvalue_expr, IsLValueExpr, KEYCXX) diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index a80ac6dbc7613..6f9a31bbbaf60 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -9597,6 +9597,15 @@ class Sema final : public SemaBase { ArrayRef<TemplateArgument> TemplateArgs, sema::TemplateDeductionInfo &Info); + /// Deduce the template arguments of the given template from \p FromType. + /// Used to implement the IsDeducible constraint for alias CTAD per C++ + /// [over.match.class.deduct]p4. + /// + /// It only supports class or type alias templates. + TemplateDeductionResult + DeduceTemplateArgumentsFromType(TemplateDecl *TD, QualType FromType, + sema::TemplateDeductionInfo &Info); + TemplateDeductionResult DeduceTemplateArguments( TemplateParameterList *TemplateParams, ArrayRef<TemplateArgument> Ps, ArrayRef<TemplateArgument> As, sema::TemplateDeductionInfo &Info, diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp index 0d2ad980696fc..af4e205eeff80 100644 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -3906,14 +3906,18 @@ ExprResult Parser::ParseTypeTrait() { BalancedDelimiterTracker Parens(*this, tok::l_paren); if (Parens.expectAndConsume()) return ExprError(); - + TypeTrait TTKind = TypeTraitFromTokKind(Kind); SmallVector<ParsedType, 2> Args; do { // Parse the next type. - TypeResult Ty = ParseTypeName(/*SourceRange=*/nullptr, - getLangOpts().CPlusPlus - ? DeclaratorContext::TemplateTypeArg - : DeclaratorContext::TypeName); + TypeResult Ty = ParseTypeName( + /*SourceRange=*/nullptr, + getLangOpts().CPlusPlus + // For __is_deducible type trait, the first argument is a template + // specification type without template argument lists. + ? (TTKind == BTT_IsDeducible ? DeclaratorContext::TemplateArg + : DeclaratorContext::TemplateTypeArg) + : DeclaratorContext::TypeName); if (Ty.isInvalid()) { Parens.skipToEnd(); return ExprError(); @@ -3937,7 +3941,7 @@ ExprResult Parser::ParseTypeTrait() { SourceLocation EndLoc = Parens.getCloseLocation(); - return Actions.ActOnTypeTrait(TypeTraitFromTokKind(Kind), Loc, Args, EndLoc); + return Actions.ActOnTypeTrait(TTKind, Loc, Args, EndLoc); } /// ParseArrayTypeTrait - Parse the built-in array type-trait diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index c1cb03e4ec7ae..222e8babdfaaa 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -6116,6 +6116,17 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, const TypeSourceI tok::kw___is_pointer_interconvertible_base_of); return Self.IsPointerInterconvertibleBaseOf(Lhs, Rhs); + } + case BTT_IsDeducible: { + if (const auto *TSTToBeDeduced = + LhsT->getAs<DeducedTemplateSpecializationType>()) { + sema::TemplateDeductionInfo Info(KeyLoc); + return Self.DeduceTemplateArgumentsFromType( + TSTToBeDeduced->getTemplateName().getAsTemplateDecl(), RhsT, + Info) == TemplateDeductionResult::Success; + } + // FIXME: emit a diagnostic. + return false; } default: llvm_unreachable("not a BTT"); } diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 989f3995ca599..7c292a295aacc 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -18,6 +18,7 @@ #include "clang/AST/ExprCXX.h" #include "clang/AST/RecursiveASTVisitor.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" @@ -2774,6 +2775,41 @@ Expr *transformRequireClause(Sema &SemaRef, FunctionTemplateDecl *FTD, return E.getAs<Expr>(); } +// Build the associated constraints for the alias deduction guides. +// C++ [over.match.class.deduct]p3.3: +// The associated constraints ([temp.constr.decl]) are the conjunction of the +// associated constraints of g and a constraint that is satisfied if and only +// if the arguments of A are deducible (see below) from the return type. +Expr * +buildAssociatedConstraints(Sema &SemaRef, TypeAliasTemplateDecl *AliasTemplate, + FunctionTemplateDecl *FTD, + llvm::ArrayRef<TemplateArgument> TransformedArgs, + QualType ReturnType) { + auto &Context = SemaRef.Context; + TemplateName TN(AliasTemplate); + auto TST = Context.getDeducedTemplateSpecializationType(TN, QualType(), true); + // Build the IsDeducible constraint. + SmallVector<TypeSourceInfo *> IsDeducibleTypeTraitArgs = { + Context.getTrivialTypeSourceInfo(TST), + Context.getTrivialTypeSourceInfo(ReturnType)}; + Expr *IsDeducible = TypeTraitExpr::Create( + Context, Context.getLogicalOperationType(), AliasTemplate->getLocation(), + TypeTrait::BTT_IsDeducible, IsDeducibleTypeTraitArgs, + AliasTemplate->getLocation(), false); + + // Substitute new template parameters into requires-clause if present. + if (auto *TransformedRC = + transformRequireClause(SemaRef, FTD, TransformedArgs)) { + auto Conjunction = SemaRef.BuildBinOp( + SemaRef.getCurScope(), SourceLocation{}, BinaryOperatorKind::BO_LAnd, + TransformedRC, IsDeducible); + if (Conjunction.isInvalid()) + return nullptr; + return Conjunction.get(); + } + return IsDeducible; +} + std::pair<TemplateDecl *, llvm::ArrayRef<TemplateArgument>> getRHSTemplateDeclAndArgs(Sema &SemaRef, TypeAliasTemplateDecl *AliasTemplate) { // Unwrap the sugared ElaboratedType. @@ -3000,6 +3036,18 @@ void DeclareImplicitDeductionGuidesForTypeAlias( if (auto *FPrime = SemaRef.InstantiateFunctionDeclaration( F, TemplateArgListForBuildingFPrime, AliasTemplate->getLocation(), Sema::CodeSynthesisContext::BuildingDeductionGuides)) { + Expr *RequireClause = buildAssociatedConstraints( + SemaRef, AliasTemplate, F, TemplateArgsForBuildingFPrime, + FPrime->getReturnType()); + if (!RequireClause) + continue; + auto *FPrimeTemplateParamList = TemplateParameterList::Create( + Context, AliasTemplate->getTemplateParameters()->getTemplateLoc(), + AliasTemplate->getTemplateParameters()->getLAngleLoc(), + FPrimeTemplateParams, + AliasTemplate->getTemplateParameters()->getRAngleLoc(), + RequireClause); + auto *GG = cast<CXXDeductionGuideDecl>(FPrime); // Substitute new template parameters into requires-clause if present. Expr *RequiresClause = @@ -3067,16 +3115,6 @@ FunctionTemplateDecl *DeclareAggregateDeductionGuideForTypeAlias( SemaRef.Context.getInjectedTemplateArg(NewParam)); TransformedTemplateParams.push_back(NewParam); } - // FIXME: implement the is_deducible constraint per C++ - // [over.match.class.deduct]p3.3. - Expr *TransformedRequiresClause = transformRequireClause( - SemaRef, RHSDeductionGuide, TransformedTemplateArgs); - auto *TransformedTemplateParameterList = TemplateParameterList::Create( - SemaRef.Context, AliasTemplate->getTemplateParameters()->getTemplateLoc(), - AliasTemplate->getTemplateParameters()->getLAngleLoc(), - TransformedTemplateParams, - AliasTemplate->getTemplateParameters()->getRAngleLoc(), - TransformedRequiresClause); auto *TransformedTemplateArgList = TemplateArgumentList::CreateCopy( SemaRef.Context, TransformedTemplateArgs); @@ -3084,6 +3122,18 @@ FunctionTemplateDecl *DeclareAggregateDeductionGuideForTypeAlias( RHSDeductionGuide, TransformedTemplateArgList, AliasTemplate->getLocation(), Sema::CodeSynthesisContext::BuildingDeductionGuides)) { + Expr *RequireClause = buildAssociatedConstraints( + SemaRef, AliasTemplate, RHSDeductionGuide, TransformedTemplateArgs, + TransformedDeductionGuide->getReturnType()); + if (!RequireClause) + return nullptr; + auto *TransformedTemplateParameterList = TemplateParameterList::Create( + SemaRef.Context, + AliasTemplate->getTemplateParameters()->getTemplateLoc(), + AliasTemplate->getTemplateParameters()->getLAngleLoc(), + TransformedTemplateParams, + AliasTemplate->getTemplateParameters()->getRAngleLoc(), RequireClause); + auto *GD = llvm::dyn_cast<clang::CXXDeductionGuideDecl>(TransformedDeductionGuide); FunctionTemplateDecl *Result = buildDeductionGuide( diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index 9f9e442282717..072f16e5f5793 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -3239,6 +3239,40 @@ static TemplateDeductionResult FinishTemplateArgumentDeduction( return TemplateDeductionResult::Success; } +/// Complete template argument deduction for DeduceTemplateArgumentsFromType. +/// FIXME: this is mostly duplicated with the above two versions. Deduplicate +/// the three implementations. +static TemplateDeductionResult FinishTemplateArgumentDeduction( + Sema &S, TemplateDecl *TD, + SmallVectorImpl<DeducedTemplateArgument> &Deduced, + TemplateDeductionInfo &Info) { + // Unevaluated SFINAE context. + EnterExpressionEvaluationContext Unevaluated( + S, Sema::ExpressionEvaluationContext::Unevaluated); + Sema::SFINAETrap Trap(S); + + Sema::ContextRAII SavedContext(S, getAsDeclContextOrEnclosing(TD)); + + // C++ [temp.deduct.type]p2: + // [...] or if any template argument remains neither deduced nor + // explicitly specified, template argument deduction fails. + SmallVector<TemplateArgument, 4> SugaredBuilder, CanonicalBuilder; + if (auto Result = ConvertDeducedTemplateArguments( + S, TD, /*IsPartialOrdering=*/false, Deduced, Info, SugaredBuilder, + CanonicalBuilder); + Result != TemplateDeductionResult::Success) + return Result; + + if (Trap.hasErrorOccurred()) + return TemplateDeductionResult::SubstitutionFailure; + + if (auto Result = CheckDeducedArgumentConstraints(S, TD, SugaredBuilder, + CanonicalBuilder, Info); + Result != TemplateDeductionResult::Success) + return Result; + + return TemplateDeductionResult::Success; +} /// Perform template argument deduction to determine whether the given template /// arguments match the given class or variable template partial specialization @@ -3307,6 +3341,59 @@ Sema::DeduceTemplateArguments(VarTemplatePartialSpecializationDecl *Partial, return ::DeduceTemplateArguments(*this, Partial, TemplateArgs, Info); } +TemplateDeductionResult +Sema::DeduceTemplateArgumentsFromType(TemplateDecl *TD, QualType FromType, + sema::TemplateDeductionInfo &Info) { + if (TD->isInvalidDecl()) + return TemplateDeductionResult::Invalid; + + QualType PType; + if (const auto *CTD = dyn_cast<ClassTemplateDecl>(TD)) { + // Use the InjectedClassNameType. + PType = Context.getTypeDeclType(CTD->getTemplatedDecl()); + } else if (const auto *AliasTemplate = dyn_cast<TypeAliasTemplateDecl>(TD)) { + PType = AliasTemplate->getTemplatedDecl() + ->getUnderlyingType() + .getCanonicalType(); + } else { + // FIXME: emit a diagnostic, we only only support alias and class templates. + return TemplateDeductionResult::Invalid; + } + + // Unevaluated SFINAE context. + EnterExpressionEvaluationContext Unevaluated( + *this, Sema::ExpressionEvaluationContext::Unevaluated); + SFINAETrap Trap(*this); + + // This deduction has no relation to any outer instantiation we might be + // performing. + LocalInstantiationScope InstantiationScope(*this); + + SmallVector<DeducedTemplateArgument> Deduced( + TD->getTemplateParameters()->size()); + SmallVector<TemplateArgument> PArgs = {TemplateArgument(PType)}; + SmallVector<TemplateArgument> AArgs = {TemplateArgument(FromType)}; + if (auto DeducedResult = DeduceTemplateArguments( + TD->getTemplateParameters(), PArgs, AArgs, Info, Deduced, false); + DeducedResult != TemplateDeductionResult::Success) { + return DeducedResult; + } + + SmallVector<TemplateArgument, 4> DeducedArgs(Deduced.begin(), Deduced.end()); + InstantiatingTemplate Inst(*this, Info.getLocation(), TD, DeducedArgs, Info); + if (Inst.isInvalid()) + return TemplateDeductionResult::InstantiationDepth; + + if (Trap.hasErrorOccurred()) + return TemplateDeductionResult::SubstitutionFailure; + + TemplateDeductionResult Result; + runWithSufficientStackSpace(Info.getLocation(), [&] { + Result = ::FinishTemplateArgumentDeduction(*this, TD, Deduced, Info); + }); + return Result; +} + /// Determine whether the given type T is a simple-template-id type. static bool isSimpleTemplateIdType(QualType T) { if (const TemplateSpecializationType *Spec diff --git a/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp b/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp index 508a3a5da76a9..8d686ab102fd0 100644 --- a/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp +++ b/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp @@ -109,10 +109,12 @@ struct Foo { }; template <typename X, int Y> -using Bar = Foo<X, sizeof(X)>; +using Bar = Foo<X, sizeof(X)>; // expected-note {{candidate template ignored: couldn't infer template argument 'X'}} \ + // expected-note {{candidate template ignored: constraints not satisfied [with X = int]}} \ + // expected-note {{because '__is_deducible(Bar, Foo<int, 4UL>)' evaluated to false}} -// FIXME: we should reject this case? GCC rejects it, MSVC accepts it. -Bar s = {{1}}; + +Bar s = {{1}}; // expected-error {{no viable constructor or deduction guide }} } // namespace test9 namespace test10 { @@ -133,9 +135,13 @@ A a(2); // Foo<int*> namespace test11 { struct A {}; template<class T> struct Foo { T c; }; -template<class X, class Y=A> using AFoo = Foo<Y>; +template<class X, class Y=A> +using AFoo = Foo<Y>; // expected-note {{candidate template ignored: could not match 'Foo<type-parameter-0-0>' against 'int'}} \ + // expected-note {{candidate template ignored: constraints not satisfied [with T = int]}} \ + // expected-note {{because '__is_deducible(AFoo, Foo<int>)' evaluated to false}} \ + // expected-note {{candidate function template not viable: requires 0 arguments, but 1 was provided}} -AFoo s = {1}; +AFoo s = {1}; // expected-error {{no viable constructor or deduction guide for deduction of template arguments of 'AFoo'}} } // namespace test11 namespace test12 { @@ -190,13 +196,15 @@ template <class T> struct Foo { Foo(T); }; template<class V> using AFoo = Foo<V *>; template<typename> concept False = false; -template<False W> using BFoo = AFoo<W>; +template<False W> +using BFoo = AFoo<W>; // expected-note {{candidate template ignored: constraints not satisfied [with V = int]}} \ + // expected-note {{because '__is_deducible(BFoo, Foo<int *>)' evaluated to false}} \ + // expected-note {{candidate template ignored: could not match 'Foo<type-parameter-0-0 *>' against 'int *'}} int i = 0; AFoo a1(&i); // OK, deduce Foo<int *> -// FIXME: we should reject this case as the W is not deduced from the deduced -// type Foo<int *>. -BFoo b2(&i); +// the W is not deduced from the deduced type Foo<int *>. +BFoo b2(&i); // expected-error {{no viable constructor or deduction guide for deduction of template arguments of 'BFoo'}} } // namespace test15 namespace test16 { diff --git a/clang/test/SemaCXX/type-traits-is-deducible.cpp b/clang/test/SemaCXX/type-traits-is-deducible.cpp new file mode 100644 index 0000000000000..1a9ba19fb6035 --- /dev/null +++ b/clang/test/SemaCXX/type-traits-is-deducible.cpp @@ -0,0 +1,47 @@ +// RUN: %clang_cc1 -fsyntax-only -std=c++20 -verify %s +// expected-no-diagnostics + +template<typename T> +struct Foo {}; +static_assert(__is_deducible(Foo, Foo<int>)); +static_assert(!__is_deducible(Foo, int)); + +template <class T> +using AFoo1 = Foo<T*>; +static_assert(__is_deducible(AFoo1, Foo<int*>)); +static_assert(!__is_deducible(AFoo1, Foo<int>)); + +template <class T> +using AFoo2 = Foo<int>; +static_assert(!__is_deducible(AFoo2, Foo<int>)); + +// default template argument counts. +template <class T = double> +using AFoo3 = Foo<int>; +static_assert(__is_deducible(AFoo3, Foo<int>)); + + +template <int N> +struct Bar { int k = N; }; +static_assert(__is_deducible(Bar, Bar<1>)); + +template <int N> +using ABar1 = Bar<N>; +static_assert(__is_deducible(ABar1, Bar<3>)); +template <int N> +using ABar2 = Bar<1>; +static_assert(!__is_deducible(ABar2, Bar<1>)); + + +template <typename T> +class Forward; +static_assert(__is_deducible(Forward, Forward<int>)); +template <typename T> +using AForward = Forward<T>; +static_assert(__is_deducible(AForward, Forward<int>)); + + +template <class T, T N> +using AArrary = int[N]; +static_assert (__is_deducible(AArrary, int[42])); +static_assert (!__is_deducible(AArrary, double[42])); diff --git a/clang/www/cxx_status.html b/clang/www/cxx_status.html index b39cfbd76df25..cb93642d41572 100755 --- a/clang/www/cxx_status.html +++ b/clang/www/cxx_status.html @@ -875,13 +875,7 @@ <h2 id="cxx20">C++20 implementation status</h2> <tr> <td>Class template argument deduction for alias templates</td> <td><a href="https://wg21.link/p1814r0">P1814R0</a></td> - <td class="partial" align="center"> - <details> - <summary>Clang 19 (Partial)</summary> - The associated constraints (over.match.class.deduct#3.3) for the - synthesized deduction guides are not yet implemented. - </details> - </td> + <td class="partial" align="center">Clang 19 (Partial)</td> </tr> <tr> <td>Permit conversions to arrays of unknown bound</td> >From c524b104cb845dc50415c00ea2a750b999ecd173 Mon Sep 17 00:00:00 2001 From: Haojian Wu <hokein...@gmail.com> Date: Mon, 22 Apr 2024 12:48:29 +0200 Subject: [PATCH 2/4] - rebase to main - add release note for __is_deducible - implement diagnostics for bad argument types for __is_deducible --- clang/docs/ReleaseNotes.rst | 4 ++++ clang/include/clang/Basic/DiagnosticSemaKinds.td | 4 ++++ clang/lib/Sema/SemaExprCXX.cpp | 4 +++- clang/lib/Sema/SemaTemplate.cpp | 13 ------------- clang/lib/Sema/SemaTemplateDeduction.cpp | 3 +-- clang/test/SemaCXX/cxx20-ctad-type-alias.cpp | 2 +- clang/test/SemaCXX/type-traits-is-deducible.cpp | 10 +++++++++- clang/test/SemaTemplate/deduction-guide.cpp | 12 +++++++----- 8 files changed, 29 insertions(+), 23 deletions(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 3a68a6d5efe5f..09719c9dd1494 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -168,6 +168,10 @@ C++20 Feature Support to update the ``__cpp_concepts`` macro to `202002L`. This enables ``<expected>`` from libstdc++ to work correctly with Clang. +- Implemented the `__is_deducible` builtin to check if the template arguments of + a class/alias template can be deduced from a specific type, + [over.match.class.deduct]p4. + C++23 Feature Support ^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index fbb107679d94b..e6b40d6ebd875 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -9156,6 +9156,10 @@ def note_inequality_comparison_to_or_assign : Note< def err_incomplete_type_used_in_type_trait_expr : Error< "incomplete type %0 used in type trait expression">; +def err_deducible_non_class_or_alias_types : Error< + "%0 is not a class or alias template; __is_deducible only supports class or " + "alias templates">; + // C++20 constinit and require_constant_initialization attribute def warn_cxx20_compat_constinit : Warning< "'constinit' specifier is incompatible with C++ standards before C++20">, diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index 222e8babdfaaa..6e9d85619daf7 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -6125,7 +6125,9 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, const TypeSourceI TSTToBeDeduced->getTemplateName().getAsTemplateDecl(), RhsT, Info) == TemplateDeductionResult::Success; } - // FIXME: emit a diagnostic. + Self.Diag(Lhs->getTypeLoc().getBeginLoc(), + diag::err_deducible_non_class_or_alias_types) + << LhsT << Lhs->getTypeLoc().getSourceRange(); return false; } default: llvm_unreachable("not a BTT"); diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 7c292a295aacc..223ea2e96a30a 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -3049,19 +3049,6 @@ void DeclareImplicitDeductionGuidesForTypeAlias( RequireClause); auto *GG = cast<CXXDeductionGuideDecl>(FPrime); - // Substitute new template parameters into requires-clause if present. - Expr *RequiresClause = - transformRequireClause(SemaRef, F, TemplateArgsForBuildingFPrime); - // FIXME: implement the is_deducible constraint per C++ - // [over.match.class.deduct]p3.3: - // ... and a constraint that is satisfied if and only if the arguments - // of A are deducible (see below) from the return type. - auto *FPrimeTemplateParamList = TemplateParameterList::Create( - Context, AliasTemplate->getTemplateParameters()->getTemplateLoc(), - AliasTemplate->getTemplateParameters()->getLAngleLoc(), - FPrimeTemplateParams, - AliasTemplate->getTemplateParameters()->getRAngleLoc(), - /*RequiresClause=*/RequiresClause); buildDeductionGuide(SemaRef, AliasTemplate, FPrimeTemplateParamList, GG->getCorrespondingConstructor(), diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index 072f16e5f5793..1dd3175a7ea18 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -3356,8 +3356,7 @@ Sema::DeduceTemplateArgumentsFromType(TemplateDecl *TD, QualType FromType, ->getUnderlyingType() .getCanonicalType(); } else { - // FIXME: emit a diagnostic, we only only support alias and class templates. - return TemplateDeductionResult::Invalid; + assert(false && "Expected a class or alias template"); } // Unevaluated SFINAE context. diff --git a/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp b/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp index 8d686ab102fd0..cbe00181f74b2 100644 --- a/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp +++ b/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp @@ -111,7 +111,7 @@ struct Foo { template <typename X, int Y> using Bar = Foo<X, sizeof(X)>; // expected-note {{candidate template ignored: couldn't infer template argument 'X'}} \ // expected-note {{candidate template ignored: constraints not satisfied [with X = int]}} \ - // expected-note {{because '__is_deducible(Bar, Foo<int, 4UL>)' evaluated to false}} + // expected-note {{because '__is_deducible}} Bar s = {{1}}; // expected-error {{no viable constructor or deduction guide }} diff --git a/clang/test/SemaCXX/type-traits-is-deducible.cpp b/clang/test/SemaCXX/type-traits-is-deducible.cpp index 1a9ba19fb6035..74753bf60cac2 100644 --- a/clang/test/SemaCXX/type-traits-is-deducible.cpp +++ b/clang/test/SemaCXX/type-traits-is-deducible.cpp @@ -1,5 +1,4 @@ // RUN: %clang_cc1 -fsyntax-only -std=c++20 -verify %s -// expected-no-diagnostics template<typename T> struct Foo {}; @@ -45,3 +44,12 @@ template <class T, T N> using AArrary = int[N]; static_assert (__is_deducible(AArrary, int[42])); static_assert (!__is_deducible(AArrary, double[42])); + +// error cases +bool e1 = __is_deducible(int, int); // expected-error {{'int' is not a class or alias template; __is_deducible only supports class or alias templates}} +template<typename T> T func(); +bool e2 = __is_deducible(func, int); // expected-error {{type name requires a specifier or qualifier}} \ + expected-error {{type-id cannot have a name}} +template<typename T> T var = 1; +bool e3 = __is_deducible(var, int); // expected-error {{type name requires a specifier or qualifier}} \ + expected-error {{type-id cannot have a name}} diff --git a/clang/test/SemaTemplate/deduction-guide.cpp b/clang/test/SemaTemplate/deduction-guide.cpp index ff5e39216762f..4a6d0238fe159 100644 --- a/clang/test/SemaTemplate/deduction-guide.cpp +++ b/clang/test/SemaTemplate/deduction-guide.cpp @@ -275,11 +275,13 @@ using AFoo = Foo<G<U>>; // CHECK-LABEL: Dumping <deduction guide for AFoo> // CHECK: FunctionTemplateDecl {{.*}} implicit <deduction guide for AFoo> // CHECK-NEXT: |-TemplateTypeParmDecl {{.*}} typename depth 0 index 0 U -// CHECK-NEXT: |-ParenExpr {{.*}} 'bool' -// CHECK-NEXT: | `-BinaryOperator {{.*}} 'bool' '==' -// CHECK-NEXT: | |-UnaryExprOrTypeTraitExpr {{.*}} 'G<type-parameter-0-0>' -// CHECK-NEXT: | `-ImplicitCastExpr {{.*}} -// CHECK-NEXT: | `-IntegerLiteral {{.*}} +// CHECK-NEXT: |-BinaryOperator {{.*}} '&&' +// CHECK-NEXT: | |-ParenExpr {{.*}} 'bool' +// CHECK-NEXT: | | `-BinaryOperator {{.*}} 'bool' '==' +// CHECK-NEXT: | | |-UnaryExprOrTypeTraitExpr {{.*}} 'G<type-parameter-0-0>' +// CHECK-NEXT: | | `-ImplicitCastExpr {{.*}} +// CHECK-NEXT: | | `-IntegerLiteral {{.*}} +// CHECK-NEXT: | `-TypeTraitExpr {{.*}} 'bool' __is_deducible // CHECK-NEXT: |-CXXDeductionGuideDecl {{.*}} implicit <deduction guide for AFoo> 'auto (G<type-parameter-0-0>) -> Foo<G<type-parameter-0-0>>' // CHECK-NEXT: | `-ParmVarDecl {{.*}} 'G<type-parameter-0-0>' // CHECK-NEXT: `-CXXDeductionGuideDecl {{.*}} implicit used <deduction guide for AFoo> 'auto (G<int>) -> Foo<G<int>>' implicit_instantiation >From 552156ff7e3230940d4a53bf266267990aee4af8 Mon Sep 17 00:00:00 2001 From: Haojian Wu <hokein...@gmail.com> Date: Wed, 24 Apr 2024 09:47:27 +0200 Subject: [PATCH 3/4] Don't expose __is_deducible trait. --- clang/docs/ReleaseNotes.rst | 4 -- .../clang/Basic/DiagnosticSemaKinds.td | 4 -- clang/include/clang/Basic/TokenKinds.def | 1 - clang/include/clang/Basic/TypeTraits.h | 7 ++- clang/lib/Basic/TypeTraits.cpp | 9 +++ clang/lib/Parse/ParseExprCXX.cpp | 16 ++---- clang/lib/Sema/SemaExprCXX.cpp | 4 +- .../test/SemaCXX/type-traits-is-deducible.cpp | 55 ------------------- clang/test/SemaTemplate/deduction-guide.cpp | 4 +- clang/www/cxx_status.html | 8 ++- 10 files changed, 32 insertions(+), 80 deletions(-) delete mode 100644 clang/test/SemaCXX/type-traits-is-deducible.cpp diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 09719c9dd1494..3a68a6d5efe5f 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -168,10 +168,6 @@ C++20 Feature Support to update the ``__cpp_concepts`` macro to `202002L`. This enables ``<expected>`` from libstdc++ to work correctly with Clang. -- Implemented the `__is_deducible` builtin to check if the template arguments of - a class/alias template can be deduced from a specific type, - [over.match.class.deduct]p4. - C++23 Feature Support ^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index e6b40d6ebd875..fbb107679d94b 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -9156,10 +9156,6 @@ def note_inequality_comparison_to_or_assign : Note< def err_incomplete_type_used_in_type_trait_expr : Error< "incomplete type %0 used in type trait expression">; -def err_deducible_non_class_or_alias_types : Error< - "%0 is not a class or alias template; __is_deducible only supports class or " - "alias templates">; - // C++20 constinit and require_constant_initialization attribute def warn_cxx20_compat_constinit : Warning< "'constinit' specifier is incompatible with C++ standards before C++20">, diff --git a/clang/include/clang/Basic/TokenKinds.def b/clang/include/clang/Basic/TokenKinds.def index 74102f4053968..a27fbed358a60 100644 --- a/clang/include/clang/Basic/TokenKinds.def +++ b/clang/include/clang/Basic/TokenKinds.def @@ -537,7 +537,6 @@ TYPE_TRAIT_1(__is_referenceable, IsReferenceable, KEYCXX) TYPE_TRAIT_1(__can_pass_in_regs, CanPassInRegs, KEYCXX) TYPE_TRAIT_2(__reference_binds_to_temporary, ReferenceBindsToTemporary, KEYCXX) TYPE_TRAIT_2(__reference_constructs_from_temporary, ReferenceConstructsFromTemporary, KEYCXX) -TYPE_TRAIT_2(__is_deducible, IsDeducible, KEYCXX) // Embarcadero Expression Traits EXPRESSION_TRAIT(__is_lvalue_expr, IsLValueExpr, KEYCXX) diff --git a/clang/include/clang/Basic/TypeTraits.h b/clang/include/clang/Basic/TypeTraits.h index eb8b1923152db..f0931439332c8 100644 --- a/clang/include/clang/Basic/TypeTraits.h +++ b/clang/include/clang/Basic/TypeTraits.h @@ -26,8 +26,13 @@ enum TypeTrait { #include "clang/Basic/TokenKinds.def" , #define TYPE_TRAIT_2(Spelling, Name, Key) BTT_##Name, + // IsDeducible is only used internally by clang for CTAD implementation and + // is not exposed to users. + TYPE_TRAIT_2(/**/, IsDeducible, KEYCXX) #include "clang/Basic/TokenKinds.def" - BTT_Last = UTT_Last // BTT_Last == last BTT_XX in the enum. + // +1 for the IsDeducible enumerator. + BTT_Last = UTT_Last + 1 // BTT_Last == last BTT_XX in the enum. + #define TYPE_TRAIT_2(Spelling, Name, Key) +1 #include "clang/Basic/TokenKinds.def" , diff --git a/clang/lib/Basic/TypeTraits.cpp b/clang/lib/Basic/TypeTraits.cpp index 4dbf678dc395b..e9f3c55ea13a0 100644 --- a/clang/lib/Basic/TypeTraits.cpp +++ b/clang/lib/Basic/TypeTraits.cpp @@ -19,6 +19,9 @@ static constexpr const char *TypeTraitNames[] = { #define TYPE_TRAIT_1(Spelling, Name, Key) #Name, #include "clang/Basic/TokenKinds.def" #define TYPE_TRAIT_2(Spelling, Name, Key) #Name, + // IsDeducible is only used internally by clang for CTAD implementation and + // is not exposed to users. + TYPE_TRAIT_2(/**/, IsDeducible, KEYCXX) #include "clang/Basic/TokenKinds.def" #define TYPE_TRAIT_N(Spelling, Name, Key) #Name, #include "clang/Basic/TokenKinds.def" @@ -28,6 +31,9 @@ static constexpr const char *TypeTraitSpellings[] = { #define TYPE_TRAIT_1(Spelling, Name, Key) #Spelling, #include "clang/Basic/TokenKinds.def" #define TYPE_TRAIT_2(Spelling, Name, Key) #Spelling, + // __is_deducible is only used internally by clang for CTAD implementation + // and is not exposed to users. + TYPE_TRAIT_2(__is_deducible, /**/, KEYCXX) #include "clang/Basic/TokenKinds.def" #define TYPE_TRAIT_N(Spelling, Name, Key) #Spelling, #include "clang/Basic/TokenKinds.def" @@ -59,6 +65,9 @@ static constexpr const unsigned TypeTraitArities[] = { #define TYPE_TRAIT_1(Spelling, Name, Key) 1, #include "clang/Basic/TokenKinds.def" #define TYPE_TRAIT_2(Spelling, Name, Key) 2, + // IsDeducible is only used internally by clang for CTAD implementation and + // is not exposed to users. + TYPE_TRAIT_2(/**/, IsDeducible, KEYCXX) #include "clang/Basic/TokenKinds.def" #define TYPE_TRAIT_N(Spelling, Name, Key) 0, #include "clang/Basic/TokenKinds.def" diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp index af4e205eeff80..0d2ad980696fc 100644 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -3906,18 +3906,14 @@ ExprResult Parser::ParseTypeTrait() { BalancedDelimiterTracker Parens(*this, tok::l_paren); if (Parens.expectAndConsume()) return ExprError(); - TypeTrait TTKind = TypeTraitFromTokKind(Kind); + SmallVector<ParsedType, 2> Args; do { // Parse the next type. - TypeResult Ty = ParseTypeName( - /*SourceRange=*/nullptr, - getLangOpts().CPlusPlus - // For __is_deducible type trait, the first argument is a template - // specification type without template argument lists. - ? (TTKind == BTT_IsDeducible ? DeclaratorContext::TemplateArg - : DeclaratorContext::TemplateTypeArg) - : DeclaratorContext::TypeName); + TypeResult Ty = ParseTypeName(/*SourceRange=*/nullptr, + getLangOpts().CPlusPlus + ? DeclaratorContext::TemplateTypeArg + : DeclaratorContext::TypeName); if (Ty.isInvalid()) { Parens.skipToEnd(); return ExprError(); @@ -3941,7 +3937,7 @@ ExprResult Parser::ParseTypeTrait() { SourceLocation EndLoc = Parens.getCloseLocation(); - return Actions.ActOnTypeTrait(TTKind, Loc, Args, EndLoc); + return Actions.ActOnTypeTrait(TypeTraitFromTokKind(Kind), Loc, Args, EndLoc); } /// ParseArrayTypeTrait - Parse the built-in array type-trait diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index 6e9d85619daf7..ce9d370655b1a 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -6125,9 +6125,7 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, const TypeSourceI TSTToBeDeduced->getTemplateName().getAsTemplateDecl(), RhsT, Info) == TemplateDeductionResult::Success; } - Self.Diag(Lhs->getTypeLoc().getBeginLoc(), - diag::err_deducible_non_class_or_alias_types) - << LhsT << Lhs->getTypeLoc().getSourceRange(); + assert("Expect to see DeducedTemplateSpecializationType!"); return false; } default: llvm_unreachable("not a BTT"); diff --git a/clang/test/SemaCXX/type-traits-is-deducible.cpp b/clang/test/SemaCXX/type-traits-is-deducible.cpp deleted file mode 100644 index 74753bf60cac2..0000000000000 --- a/clang/test/SemaCXX/type-traits-is-deducible.cpp +++ /dev/null @@ -1,55 +0,0 @@ -// RUN: %clang_cc1 -fsyntax-only -std=c++20 -verify %s - -template<typename T> -struct Foo {}; -static_assert(__is_deducible(Foo, Foo<int>)); -static_assert(!__is_deducible(Foo, int)); - -template <class T> -using AFoo1 = Foo<T*>; -static_assert(__is_deducible(AFoo1, Foo<int*>)); -static_assert(!__is_deducible(AFoo1, Foo<int>)); - -template <class T> -using AFoo2 = Foo<int>; -static_assert(!__is_deducible(AFoo2, Foo<int>)); - -// default template argument counts. -template <class T = double> -using AFoo3 = Foo<int>; -static_assert(__is_deducible(AFoo3, Foo<int>)); - - -template <int N> -struct Bar { int k = N; }; -static_assert(__is_deducible(Bar, Bar<1>)); - -template <int N> -using ABar1 = Bar<N>; -static_assert(__is_deducible(ABar1, Bar<3>)); -template <int N> -using ABar2 = Bar<1>; -static_assert(!__is_deducible(ABar2, Bar<1>)); - - -template <typename T> -class Forward; -static_assert(__is_deducible(Forward, Forward<int>)); -template <typename T> -using AForward = Forward<T>; -static_assert(__is_deducible(AForward, Forward<int>)); - - -template <class T, T N> -using AArrary = int[N]; -static_assert (__is_deducible(AArrary, int[42])); -static_assert (!__is_deducible(AArrary, double[42])); - -// error cases -bool e1 = __is_deducible(int, int); // expected-error {{'int' is not a class or alias template; __is_deducible only supports class or alias templates}} -template<typename T> T func(); -bool e2 = __is_deducible(func, int); // expected-error {{type name requires a specifier or qualifier}} \ - expected-error {{type-id cannot have a name}} -template<typename T> T var = 1; -bool e3 = __is_deducible(var, int); // expected-error {{type name requires a specifier or qualifier}} \ - expected-error {{type-id cannot have a name}} diff --git a/clang/test/SemaTemplate/deduction-guide.cpp b/clang/test/SemaTemplate/deduction-guide.cpp index 4a6d0238fe159..80d499ddbe320 100644 --- a/clang/test/SemaTemplate/deduction-guide.cpp +++ b/clang/test/SemaTemplate/deduction-guide.cpp @@ -282,7 +282,9 @@ using AFoo = Foo<G<U>>; // CHECK-NEXT: | | `-ImplicitCastExpr {{.*}} // CHECK-NEXT: | | `-IntegerLiteral {{.*}} // CHECK-NEXT: | `-TypeTraitExpr {{.*}} 'bool' __is_deducible -// CHECK-NEXT: |-CXXDeductionGuideDecl {{.*}} implicit <deduction guide for AFoo> 'auto (G<type-parameter-0-0>) -> Foo<G<type-parameter-0-0>>' +// CHECK-NEXT: | |-DeducedTemplateSpecializationType {{.*}} 'AFoo' dependent +// CHECK-NEXT: | `-TemplateSpecializationType {{.*}} 'Foo<G<type-parameter-0-0>>' dependent Foo +// CHECK: |-CXXDeductionGuideDecl {{.*}} implicit <deduction guide for AFoo> 'auto (G<type-parameter-0-0>) -> Foo<G<type-parameter-0-0>>' // CHECK-NEXT: | `-ParmVarDecl {{.*}} 'G<type-parameter-0-0>' // CHECK-NEXT: `-CXXDeductionGuideDecl {{.*}} implicit used <deduction guide for AFoo> 'auto (G<int>) -> Foo<G<int>>' implicit_instantiation // CHECK-NEXT: |-TemplateArgument type 'int' diff --git a/clang/www/cxx_status.html b/clang/www/cxx_status.html index cb93642d41572..8493f18d9d33c 100755 --- a/clang/www/cxx_status.html +++ b/clang/www/cxx_status.html @@ -875,7 +875,13 @@ <h2 id="cxx20">C++20 implementation status</h2> <tr> <td>Class template argument deduction for alias templates</td> <td><a href="https://wg21.link/p1814r0">P1814R0</a></td> - <td class="partial" align="center">Clang 19 (Partial)</td> + <td class="partial" align="center"> + <details> + <summary>Clang 19 (Partial)</summary> + This feature has been initially completed, but the feature macro + __cpp_deduction_guides has not been updated. + </details> + </td> </tr> <tr> <td>Permit conversions to arrays of unknown bound</td> >From 5ef6c00fec3dcbfd0721cf897d2434993ec3f5f7 Mon Sep 17 00:00:00 2001 From: Haojian Wu <hokein...@gmail.com> Date: Tue, 7 May 2024 12:15:00 +0200 Subject: [PATCH 4/4] Refine the implementation of hiding __is_deducible type trait. Apply approach 3. --- clang/include/clang/Basic/TokenKinds.def | 3 +++ clang/include/clang/Basic/TypeTraits.h | 6 +----- clang/lib/Basic/TypeTraits.cpp | 19 ++++++++++--------- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/clang/include/clang/Basic/TokenKinds.def b/clang/include/clang/Basic/TokenKinds.def index a27fbed358a60..1b4b756e6e5ee 100644 --- a/clang/include/clang/Basic/TokenKinds.def +++ b/clang/include/clang/Basic/TokenKinds.def @@ -537,6 +537,9 @@ TYPE_TRAIT_1(__is_referenceable, IsReferenceable, KEYCXX) TYPE_TRAIT_1(__can_pass_in_regs, CanPassInRegs, KEYCXX) TYPE_TRAIT_2(__reference_binds_to_temporary, ReferenceBindsToTemporary, KEYCXX) TYPE_TRAIT_2(__reference_constructs_from_temporary, ReferenceConstructsFromTemporary, KEYCXX) +// IsDeducible is only used internally by clang for CTAD implementation and +// is not exposed to users. +TYPE_TRAIT_2(/*EmptySpellingName*/, IsDeducible, KEYCXX) // Embarcadero Expression Traits EXPRESSION_TRAIT(__is_lvalue_expr, IsLValueExpr, KEYCXX) diff --git a/clang/include/clang/Basic/TypeTraits.h b/clang/include/clang/Basic/TypeTraits.h index f0931439332c8..b4b44c0baa3a2 100644 --- a/clang/include/clang/Basic/TypeTraits.h +++ b/clang/include/clang/Basic/TypeTraits.h @@ -26,12 +26,8 @@ enum TypeTrait { #include "clang/Basic/TokenKinds.def" , #define TYPE_TRAIT_2(Spelling, Name, Key) BTT_##Name, - // IsDeducible is only used internally by clang for CTAD implementation and - // is not exposed to users. - TYPE_TRAIT_2(/**/, IsDeducible, KEYCXX) #include "clang/Basic/TokenKinds.def" - // +1 for the IsDeducible enumerator. - BTT_Last = UTT_Last + 1 // BTT_Last == last BTT_XX in the enum. + BTT_Last = UTT_Last #define TYPE_TRAIT_2(Spelling, Name, Key) +1 #include "clang/Basic/TokenKinds.def" diff --git a/clang/lib/Basic/TypeTraits.cpp b/clang/lib/Basic/TypeTraits.cpp index e9f3c55ea13a0..8d6794223ccaf 100644 --- a/clang/lib/Basic/TypeTraits.cpp +++ b/clang/lib/Basic/TypeTraits.cpp @@ -13,15 +13,13 @@ #include "clang/Basic/TypeTraits.h" #include "llvm/Support/ErrorHandling.h" #include <cassert> +#include <cstring> using namespace clang; static constexpr const char *TypeTraitNames[] = { #define TYPE_TRAIT_1(Spelling, Name, Key) #Name, #include "clang/Basic/TokenKinds.def" #define TYPE_TRAIT_2(Spelling, Name, Key) #Name, - // IsDeducible is only used internally by clang for CTAD implementation and - // is not exposed to users. - TYPE_TRAIT_2(/**/, IsDeducible, KEYCXX) #include "clang/Basic/TokenKinds.def" #define TYPE_TRAIT_N(Spelling, Name, Key) #Name, #include "clang/Basic/TokenKinds.def" @@ -31,9 +29,6 @@ static constexpr const char *TypeTraitSpellings[] = { #define TYPE_TRAIT_1(Spelling, Name, Key) #Spelling, #include "clang/Basic/TokenKinds.def" #define TYPE_TRAIT_2(Spelling, Name, Key) #Spelling, - // __is_deducible is only used internally by clang for CTAD implementation - // and is not exposed to users. - TYPE_TRAIT_2(__is_deducible, /**/, KEYCXX) #include "clang/Basic/TokenKinds.def" #define TYPE_TRAIT_N(Spelling, Name, Key) #Spelling, #include "clang/Basic/TokenKinds.def" @@ -65,9 +60,6 @@ static constexpr const unsigned TypeTraitArities[] = { #define TYPE_TRAIT_1(Spelling, Name, Key) 1, #include "clang/Basic/TokenKinds.def" #define TYPE_TRAIT_2(Spelling, Name, Key) 2, - // IsDeducible is only used internally by clang for CTAD implementation and - // is not exposed to users. - TYPE_TRAIT_2(/**/, IsDeducible, KEYCXX) #include "clang/Basic/TokenKinds.def" #define TYPE_TRAIT_N(Spelling, Name, Key) 0, #include "clang/Basic/TokenKinds.def" @@ -90,6 +82,15 @@ const char *clang::getTraitName(UnaryExprOrTypeTrait T) { const char *clang::getTraitSpelling(TypeTrait T) { assert(T <= TT_Last && "invalid enum value!"); + if (T == BTT_IsDeducible) { + // The __is_deducible is an internal-only type trait. To hide it from + // external users, we define it with an empty spelling name, preventing the + // clang parser from recognizing its token kind. + // However, other components such as the AST dump still require the real + // type trait name. Therefore, we return the real name when needed. + assert(std::strlen(TypeTraitSpellings[T]) == 0); + return "__is_deducible"; + } return TypeTraitSpellings[T]; } _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits