https://github.com/hokein updated https://github.com/llvm/llvm-project/pull/89358
>From 659cf5b5c1216ab9f6a8dbb63b4f93de41cd173d 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/2] [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 - rebase to main - add release note for __is_deducible - implement diagnostics for bad argument types for __is_deducible Don't expose __is_deducible trait. Refine the implementation of hiding __is_deducible type trait. Apply approach 3. --- clang/include/clang/Basic/TokenKinds.def | 3 + clang/include/clang/Sema/Sema.h | 9 ++ clang/lib/Basic/TypeTraits.cpp | 10 +++ clang/lib/Sema/SemaExprCXX.cpp | 10 ++- clang/lib/Sema/SemaTemplate.cpp | 82 +++++++++++++++++-- clang/lib/Sema/SemaTemplateDeduction.cpp | 86 ++++++++++++++++++++ clang/test/AST/ast-dump-ctad-alias.cpp | 20 +++-- clang/test/SemaCXX/cxx20-ctad-type-alias.cpp | 27 ++++-- clang/test/SemaTemplate/deduction-guide.cpp | 16 ++-- clang/www/cxx_status.html | 4 +- 10 files changed, 238 insertions(+), 29 deletions(-) diff --git a/clang/include/clang/Basic/TokenKinds.def b/clang/include/clang/Basic/TokenKinds.def index 56c4b17f769d7..b5a0e9df9f7ae 100644 --- a/clang/include/clang/Basic/TokenKinds.def +++ b/clang/include/clang/Basic/TokenKinds.def @@ -538,6 +538,9 @@ 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(__reference_converts_from_temporary, ReferenceConvertsFromTemporary, 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/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 6a414aa57f32b..66d5e2d4a4ade 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -9492,6 +9492,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/Basic/TypeTraits.cpp b/clang/lib/Basic/TypeTraits.cpp index 4dbf678dc395b..8d6794223ccaf 100644 --- a/clang/lib/Basic/TypeTraits.cpp +++ b/clang/lib/Basic/TypeTraits.cpp @@ -13,6 +13,7 @@ #include "clang/Basic/TypeTraits.h" #include "llvm/Support/ErrorHandling.h" #include <cassert> +#include <cstring> using namespace clang; static constexpr const char *TypeTraitNames[] = { @@ -81,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]; } diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index 34e12078a8c92..e4601f7d6c47d 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -6143,7 +6143,15 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, const TypeSourceI return Self.IsPointerInterconvertibleBaseOf(Lhs, Rhs); } - default: llvm_unreachable("not a BTT"); + case BTT_IsDeducible: { + const auto *TSTToBeDeduced = cast<DeducedTemplateSpecializationType>(LhsT); + sema::TemplateDeductionInfo Info(KeyLoc); + return Self.DeduceTemplateArgumentsFromType( + TSTToBeDeduced->getTemplateName().getAsTemplateDecl(), RhsT, + Info) == TemplateDeductionResult::Success; + } + default: + llvm_unreachable("not a BTT"); } llvm_unreachable("Unknown type trait or not implemented"); } diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index c7aac068e264b..bba8f18ddd038 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -2782,15 +2782,21 @@ NamedDecl *transformTemplateParameter(Sema &SemaRef, DeclContext *DC, llvm_unreachable("Unhandled template parameter types"); } -// Transform the require-clause of F if any. +// 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. +// // The return result is expected to be the require-clause for the synthesized // alias deduction guide. Expr *transformRequireClause(Sema &SemaRef, FunctionTemplateDecl *F, TypeAliasTemplateDecl *AliasTemplate, - ArrayRef<DeducedTemplateArgument> DeduceResults) { + ArrayRef<DeducedTemplateArgument> DeduceResults, + Expr *IsDeducible) { Expr *RC = F->getTemplateParameters()->getRequiresClause(); if (!RC) - return nullptr; + return IsDeducible; auto &Context = SemaRef.Context; LocalInstantiationScope Scope(SemaRef); @@ -2903,7 +2909,69 @@ Expr *transformRequireClause(Sema &SemaRef, FunctionTemplateDecl *F, ExprResult E = SemaRef.SubstExpr(RC, ArgsForBuildingRC); if (E.isInvalid()) return nullptr; - return E.getAs<Expr>(); + + auto Conjunction = + SemaRef.BuildBinOp(SemaRef.getCurScope(), SourceLocation{}, + BinaryOperatorKind::BO_LAnd, E.get(), IsDeducible); + if (Conjunction.isInvalid()) + return nullptr; + Conjunction.getAs<Expr>()->dump(); + return Conjunction.getAs<Expr>(); +} +// Build the is_deducible constraint for the alias deduction guides. +// [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. +Expr *buildIsDeducibleConstraint(Sema &SemaRef, + TypeAliasTemplateDecl *AliasTemplate, + QualType ReturnType, + SmallVector<NamedDecl *> TemplateParams) { + auto &Context = SemaRef.Context; + // Constraint AST nodes must use uninstantiated depth. + if (auto *PrimaryTemplate = + AliasTemplate->getInstantiatedFromMemberTemplate()) { + LocalInstantiationScope Scope(SemaRef); + + // Adjust the depth for TemplateParams. + unsigned AdjustDepth = PrimaryTemplate->getTemplateDepth(); + SmallVector<TemplateArgument> TransformedTemplateArgs; + for (auto *TP : TemplateParams) { + // Rebuild any internal references to earlier parameters and reindex + // as we go. + MultiLevelTemplateArgumentList Args; + Args.setKind(TemplateSubstitutionKind::Rewrite); + Args.addOuterTemplateArguments(TransformedTemplateArgs); + NamedDecl *NewParam = transformTemplateParameter( + SemaRef, AliasTemplate->getDeclContext(), TP, Args, + /*NewIndex=*/TransformedTemplateArgs.size(), + getTemplateParameterDepth(TP) + AdjustDepth); + + auto NewTemplateArgument = Context.getCanonicalTemplateArgument( + Context.getInjectedTemplateArg(NewParam)); + TransformedTemplateArgs.push_back(NewTemplateArgument); + } + // Transformed the ReturnType to restore the uninstantiated depth. + MultiLevelTemplateArgumentList Args; + Args.setKind(TemplateSubstitutionKind::Rewrite); + Args.addOuterTemplateArguments(TransformedTemplateArgs); + ReturnType = SemaRef.SubstType( + ReturnType, Args, AliasTemplate->getLocation(), + Context.DeclarationNames.getCXXDeductionGuideName(AliasTemplate)); + }; + + SmallVector<TypeSourceInfo *> IsDeducibleTypeTraitArgs = { + Context.getTrivialTypeSourceInfo( + Context.getDeducedTemplateSpecializationType( + TemplateName(AliasTemplate), /*DeducedType=*/QualType(), + /*IsDependent=*/true)), // template specialization type whose + // arguments will be deduced. + Context.getTrivialTypeSourceInfo( + ReturnType), // type from which template arguments are deduced. + }; + return TypeTraitExpr::Create( + Context, Context.getLogicalOperationType(), AliasTemplate->getLocation(), + TypeTrait::BTT_IsDeducible, IsDeducibleTypeTraitArgs, + AliasTemplate->getLocation(), /*Value*/ false); } std::pair<TemplateDecl *, llvm::ArrayRef<TemplateArgument>> @@ -3112,8 +3180,10 @@ BuildDeductionGuideForTypeAlias(Sema &SemaRef, Sema::CodeSynthesisContext::BuildingDeductionGuides)) { auto *GG = cast<CXXDeductionGuideDecl>(FPrime); - Expr *RequiresClause = - transformRequireClause(SemaRef, F, AliasTemplate, DeduceResults); + Expr *IsDeducible = buildIsDeducibleConstraint( + SemaRef, AliasTemplate, FPrime->getReturnType(), FPrimeTemplateParams); + Expr *RequiresClause = transformRequireClause(SemaRef, F, AliasTemplate, + DeduceResults, IsDeducible); // FIXME: implement the is_deducible constraint per C++ // [over.match.class.deduct]p3.3: diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index 853c0e1b50619..2ca6d55361c85 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -3237,6 +3237,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 @@ -3305,6 +3339,58 @@ 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 { + assert(false && "Expected a class or alias template"); + } + + // 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/AST/ast-dump-ctad-alias.cpp b/clang/test/AST/ast-dump-ctad-alias.cpp index 423c3454ccb73..b975f8cc8e703 100644 --- a/clang/test/AST/ast-dump-ctad-alias.cpp +++ b/clang/test/AST/ast-dump-ctad-alias.cpp @@ -24,14 +24,24 @@ Out2<double>::AInner t(1.0); // Verify that the require-clause of alias deduction guide is transformed correctly: // - Occurrence T should be replaced with `int`; // - Occurrence V should be replaced with the Y with depth 1 +// - Depth of cccurrence Y in the __is_deducible constraint should be 1 // // CHECK: | `-FunctionTemplateDecl {{.*}} <deduction guide for AInner> // CHECK-NEXT: | |-TemplateTypeParmDecl {{.*}} typename depth 0 index 0 Y -// CHECK-NEXT: | |-UnresolvedLookupExpr {{.*}} '<dependent type>' lvalue (no ADL) = 'Concept' -// CHECK-NEXT: | | |-TemplateArgument type 'int' -// CHECK-NEXT: | | | `-BuiltinType {{.*}} 'int' -// CHECK-NEXT: | | `-TemplateArgument type 'type-parameter-1-0' -// CHECK-NEXT: | | `-TemplateTypeParmType {{.*}} 'type-parameter-1-0' dependent depth 1 index 0 +// CHECK-NEXT: | |-BinaryOperator {{.*}} '<dependent type>' '&&' +// CHECK-NEXT: | | |-UnresolvedLookupExpr {{.*}} '<dependent type>' lvalue (no ADL) = 'Concept' +// CHECK-NEXT: | | | |-TemplateArgument type 'int' +// CHECK-NEXT: | | | | `-BuiltinType {{.*}} 'int' +// CHECK-NEXT: | | | `-TemplateArgument type 'type-parameter-1-0' +// CHECK-NEXT: | | | `-TemplateTypeParmType {{.*}} 'type-parameter-1-0' dependent depth 1 index 0 +// CHECK-NEXT: | | `-TypeTraitExpr {{.*}} 'bool' __is_deducible +// CHECK-NEXT: | | |-DeducedTemplateSpecializationType {{.*}} 'AInner' dependent +// CHECK-NEXT: | | `-ElaboratedType {{.*}} 'Inner<type-parameter-1-0>' sugar dependent +// CHECK-NEXT: | | `-TemplateSpecializationType {{.*}} 'Inner<type-parameter-1-0>' dependent Inner +// CHECK-NEXT: | | `-TemplateArgument type 'type-parameter-1-0' +// CHECK-NEXT: | | `-SubstTemplateTypeParmType {{.*}} 'type-parameter-1-0' +// CHECK-NEXT: | | |-FunctionTemplate {{.*}} '<deduction guide for Inner>' +// CHECK-NEXT: | | `-TemplateTypeParmType {{.*}} 'type-parameter-1-0' dependent depth 1 index 0 // CHECK-NEXT: | |-CXXDeductionGuideDecl {{.*}} <deduction guide for AInner> 'auto (type-parameter-0-0) -> Inner<type-parameter-0-0>' // CHECK-NEXT: | | `-ParmVarDecl {{.*}} 'type-parameter-0-0' // CHECK-NEXT: | `-CXXDeductionGuideDecl {{.*}} used <deduction guide for AInner> 'auto (double) -> Inner<double>' implicit_instantiation diff --git a/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp b/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp index 4c5595e409f28..7c186dc379c7b 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}} -// 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 Y = 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,16 @@ 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>; +// FIXME: emit a more descriptive diagnostic for "__is_deducible" constraint failure. +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/SemaTemplate/deduction-guide.cpp b/clang/test/SemaTemplate/deduction-guide.cpp index 51e1eb49c5de7..a91ab5ec7bcc5 100644 --- a/clang/test/SemaTemplate/deduction-guide.cpp +++ b/clang/test/SemaTemplate/deduction-guide.cpp @@ -282,12 +282,16 @@ 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: |-CXXDeductionGuideDecl {{.*}} implicit <deduction guide for AFoo> 'auto (G<type-parameter-0-0>) -> Foo<G<type-parameter-0-0>>' +// 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: | |-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 06777eaa6df69..6e2fd745e666c 100755 --- a/clang/www/cxx_status.html +++ b/clang/www/cxx_status.html @@ -870,8 +870,8 @@ <h2 id="cxx20">C++20 implementation status</h2> <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. + This feature has been initially completed, but the feature macro + __cpp_deduction_guides has not been updated. </details> </td> </tr> >From a4762ef3111bdd1ec24dace1388c4704bf1da6ea Mon Sep 17 00:00:00 2001 From: Haojian Wu <hokein...@gmail.com> Date: Wed, 15 May 2024 10:11:08 +0200 Subject: [PATCH 2/2] Add missing changes --- clang/lib/Sema/SemaTemplate.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index bba8f18ddd038..dfc2688937933 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -2790,15 +2790,16 @@ NamedDecl *transformTemplateParameter(Sema &SemaRef, DeclContext *DC, // // The return result is expected to be the require-clause for the synthesized // alias deduction guide. -Expr *transformRequireClause(Sema &SemaRef, FunctionTemplateDecl *F, - TypeAliasTemplateDecl *AliasTemplate, - ArrayRef<DeducedTemplateArgument> DeduceResults, - Expr *IsDeducible) { +Expr * +buildAssociatedConstraints(Sema &SemaRef, FunctionTemplateDecl *F, + TypeAliasTemplateDecl *AliasTemplate, + ArrayRef<DeducedTemplateArgument> DeduceResults, + Expr *IsDeducible) { Expr *RC = F->getTemplateParameters()->getRequiresClause(); if (!RC) return IsDeducible; - auto &Context = SemaRef.Context; + ASTContext &Context = SemaRef.Context; LocalInstantiationScope Scope(SemaRef); // In the clang AST, constraint nodes are deliberately not instantiated unless @@ -2915,7 +2916,6 @@ Expr *transformRequireClause(Sema &SemaRef, FunctionTemplateDecl *F, BinaryOperatorKind::BO_LAnd, E.get(), IsDeducible); if (Conjunction.isInvalid()) return nullptr; - Conjunction.getAs<Expr>()->dump(); return Conjunction.getAs<Expr>(); } // Build the is_deducible constraint for the alias deduction guides. @@ -3182,8 +3182,8 @@ BuildDeductionGuideForTypeAlias(Sema &SemaRef, Expr *IsDeducible = buildIsDeducibleConstraint( SemaRef, AliasTemplate, FPrime->getReturnType(), FPrimeTemplateParams); - Expr *RequiresClause = transformRequireClause(SemaRef, F, AliasTemplate, - DeduceResults, IsDeducible); + Expr *RequiresClause = buildAssociatedConstraints( + SemaRef, F, AliasTemplate, DeduceResults, IsDeducible); // FIXME: implement the is_deducible constraint per C++ // [over.match.class.deduct]p3.3: _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits