-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[clang] CTAD: implement the missing IsDeducible constraint for alias templates #89358
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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; | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is missing a consistency check, ie [temp.deduct.type]p1. Otherwise we would incorrectly accept a match where there would be a non-deduced mismatch. |
||
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, | ||
Comment on lines
+3342
to
+3343
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We have a lot of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This function is public (the documentation and comments are in |
||
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 | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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}} \ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we want to add code in this PR to improve the diagnostic There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you think this is a blocker for landing this PR? The current state is acceptable to me, although not ideal. I plan to send out a follow-up patch to address it. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I certainly think it's not a good user-facing diagnostic, and i don't think the fix would be difficult There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd prefer to do it in a follow up (this patch is quite large already). Added a FIXME. |
||
// 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 { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is that something you would be willing to do in a follow up patch?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is in my TODO list, but its priority is currently low, so I don't anticipate addressing it in the near future. This seems like a good candidate for a "GoodFirst" issue, so I'm thinking we can file an issue in case someone wants to contribute.