if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(*P)) {
ID.AddInteger(1);
ID.AddBoolean(NTTP->isParameterPack());
+ const Expr *TC = NTTP->getPlaceholderTypeConstraint();
+ ID.AddBoolean(TC != nullptr);
ID.AddPointer(NTTP->getType().getCanonicalType().getAsOpaquePtr());
+ if (TC)
+ TC->Profile(ID, C, /*Canonical=*/true);
if (NTTP->isExpandedParameterPack()) {
ID.AddBoolean(true);
ID.AddInteger(NTTP->getNumExpansionTypes());
!TypeConstraintConcept && !IsDependent)
return getAutoDeductType();
- if (TypeConstraintConcept)
- TypeConstraintConcept = TypeConstraintConcept->getCanonicalDecl();
-
// Look in the folding set for an existing type.
void *InsertPos = nullptr;
llvm::FoldingSetNodeID ID;
QualType Canon;
if (!IsCanon) {
- if (DeducedType.isNull()) {
- SmallVector<TemplateArgument, 4> CanonArgs;
- bool AnyNonCanonArgs =
- ::getCanonicalTemplateArguments(*this, TypeConstraintArgs, CanonArgs);
- if (AnyNonCanonArgs) {
- Canon = getAutoTypeInternal(QualType(), Keyword, IsDependent, IsPack,
- TypeConstraintConcept, CanonArgs, true);
- // Find the insert position again.
- [[maybe_unused]] auto *Nothing =
- AutoTypes.FindNodeOrInsertPos(ID, InsertPos);
- assert(!Nothing && "canonical type broken");
- }
- } else {
+ if (!DeducedType.isNull()) {
Canon = DeducedType.getCanonicalType();
+ } else if (TypeConstraintConcept) {
+ Canon = getAutoTypeInternal(QualType(), Keyword, IsDependent, IsPack,
+ nullptr, {}, true);
+ // Find the insert position again.
+ [[maybe_unused]] auto *Nothing =
+ AutoTypes.FindNodeOrInsertPos(ID, InsertPos);
+ assert(!Nothing && "canonical type broken");
}
}
if (auto *TX = dyn_cast<NonTypeTemplateParmDecl>(X)) {
auto *TY = cast<NonTypeTemplateParmDecl>(Y);
return TX->isParameterPack() == TY->isParameterPack() &&
- TX->getASTContext().hasSameType(TX->getType(), TY->getType());
+ TX->getASTContext().hasSameType(TX->getType(), TY->getType()) &&
+ isSameConstraintExpr(TX->getPlaceholderTypeConstraint(),
+ TY->getPlaceholderTypeConstraint());
}
auto *TX = cast<TemplateTemplateParmDecl>(X);
ID.AddInteger(0);
ID.AddBoolean(NTTP->isParameterPack());
NTTP->getType().getCanonicalType().Profile(ID);
+ ID.AddBoolean(NTTP->hasPlaceholderTypeConstraint());
+ if (const Expr *E = NTTP->getPlaceholderTypeConstraint())
+ E->Profile(ID, C, /*Canonical=*/true);
continue;
}
if (const auto *TTP = dyn_cast<TemplateTypeParmDecl>(D)) {
// C++2a [class.spaceship]p2 [P2002R0]:
// Let R be the declared return type [...]. If R is auto, [...]. Otherwise,
// R shall not contain a placeholder type.
- if (DCK == DefaultedComparisonKind::ThreeWay &&
- FD->getDeclaredReturnType()->getContainedDeducedType() &&
- !Context.hasSameType(FD->getDeclaredReturnType(),
- Context.getAutoDeductType())) {
+ if (QualType RT = FD->getDeclaredReturnType();
+ DCK == DefaultedComparisonKind::ThreeWay &&
+ RT->getContainedDeducedType() &&
+ (!Context.hasSameType(RT, Context.getAutoDeductType()) ||
+ RT->getContainedAutoType()->isConstrained())) {
Diag(FD->getLocation(),
diag::err_defaulted_comparison_deduced_return_type_not_auto)
<< (int)DCK << FD->getDeclaredReturnType() << Context.AutoDeductTy
: Kind),
TemplateArgLoc))
return false;
- } else if (Kind != Sema::TPL_TemplateTemplateArgumentMatch) {
+ }
+
+ if (Kind != Sema::TPL_TemplateTemplateArgumentMatch &&
+ !isa<TemplateTemplateParmDecl>(Old)) {
const Expr *NewC = nullptr, *OldC = nullptr;
- if (const auto *TC = cast<TemplateTypeParmDecl>(New)->getTypeConstraint())
- NewC = TC->getImmediatelyDeclaredConstraint();
- if (const auto *TC = cast<TemplateTypeParmDecl>(Old)->getTypeConstraint())
- OldC = TC->getImmediatelyDeclaredConstraint();
+
+ if (isa<TemplateTypeParmDecl>(New)) {
+ if (const auto *TC = cast<TemplateTypeParmDecl>(New)->getTypeConstraint())
+ NewC = TC->getImmediatelyDeclaredConstraint();
+ if (const auto *TC = cast<TemplateTypeParmDecl>(Old)->getTypeConstraint())
+ OldC = TC->getImmediatelyDeclaredConstraint();
+ } else if (isa<NonTypeTemplateParmDecl>(New)) {
+ if (const Expr *E = cast<NonTypeTemplateParmDecl>(New)
+ ->getPlaceholderTypeConstraint())
+ NewC = E;
+ if (const Expr *E = cast<NonTypeTemplateParmDecl>(Old)
+ ->getPlaceholderTypeConstraint())
+ OldC = E;
+ } else
+ llvm_unreachable("unexpected template parameter type");
auto Diagnose = [&] {
S.Diag(NewC ? NewC->getBeginLoc() : New->getBeginLoc(),
template <typename...> class A {};
template <typename... Ts> C<Ts...> auto e(A<Ts...>) { return 0; }
-
- // FIXME: The error here does not make sense.
template auto e<>(A<>);
- // expected-error@-1 {{explicit instantiation of 'e' does not refer to a function template}}
- // expected-note@-5 {{candidate template ignored: failed template argument deduction}}
-
- // FIXME: Should be able to instantiate this with no errors.
- template C<int> auto e<int>(A<int>);
- // expected-error@-1 {{explicit instantiation of 'e' does not refer to a function template}}
- // expected-note@-10 {{candidate template ignored: could not match 'C<int, Ts...> auto' against 'C<int> auto'}}
-
- template C<> auto e<>(A<>);
+ template auto e<int>(A<int>);
+
+ template <typename... Ts> C<Ts...> auto d(A<Ts...>) { return 0; }
+ template C<> auto d<>(A<>);
+ template C<int> auto d<int>(A<int>);
template <typename... Ts> A<Ts...> c(Ts...);
int f = e(c(1, 2));