Skip to content

Commit 87c8359

Browse files
committed
[clang] simplify placeholder type deduction for constant template parameters
This makes the deduction for dependent types operate in more similar ways to the non-dependent one, such as when matching template template parameters, making errors in those generate similar diagnostics to the non-dependent ones. This also removes some superfluous implicit casts, simplifying the resulting AST a little bit.
1 parent 09539af commit 87c8359

File tree

4 files changed

+52
-61
lines changed

4 files changed

+52
-61
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,8 @@ Improvements to Clang's diagnostics
292292
"format specifies type 'unsigned int' but the argument has type 'int', which differs in signedness [-Wformat-signedness]"
293293
"signedness of format specifier 'u' is incompatible with 'c' [-Wformat-signedness]"
294294
and the API-visible diagnostic id will be appropriate.
295-
295+
- Clang now produces better diagnostics for template template parameter matching
296+
involving 'auto' template parameters.
296297
- Fixed false positives in ``-Waddress-of-packed-member`` diagnostics when
297298
potential misaligned members get processed before they can get discarded.
298299
(#GH144729)

clang/lib/Sema/SemaTemplate.cpp

Lines changed: 33 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -7068,22 +7068,8 @@ ExprResult Sema::CheckTemplateArgument(NamedDecl *Param, QualType ParamType,
70687068

70697069
// If the parameter type somehow involves auto, deduce the type now.
70707070
DeducedType *DeducedT = ParamType->getContainedDeducedType();
7071-
if (getLangOpts().CPlusPlus17 && DeducedT && !DeducedT->isDeduced()) {
7072-
// During template argument deduction, we allow 'decltype(auto)' to
7073-
// match an arbitrary dependent argument.
7074-
// FIXME: The language rules don't say what happens in this case.
7075-
// FIXME: We get an opaque dependent type out of decltype(auto) if the
7076-
// expression is merely instantiation-dependent; is this enough?
7077-
if (DeductionArg->isTypeDependent()) {
7078-
auto *AT = dyn_cast<AutoType>(DeducedT);
7079-
if (AT && AT->isDecltypeAuto()) {
7080-
SugaredConverted = TemplateArgument(Arg, /*IsCanonical=*/false);
7081-
CanonicalConverted = TemplateArgument(
7082-
Context.getCanonicalTemplateArgument(SugaredConverted));
7083-
return Arg;
7084-
}
7085-
}
7086-
7071+
bool IsDeduced = DeducedT && !DeducedT->isDeduced();
7072+
if (IsDeduced) {
70877073
// When checking a deduced template argument, deduce from its type even if
70887074
// the type is dependent, in order to check the types of non-type template
70897075
// arguments line up properly in partial ordering.
@@ -7112,17 +7098,21 @@ ExprResult Sema::CheckTemplateArgument(NamedDecl *Param, QualType ParamType,
71127098
// along with the other associated constraints after
71137099
// checking the template argument list.
71147100
/*IgnoreConstraints=*/true);
7115-
if (Result == TemplateDeductionResult::AlreadyDiagnosed) {
7116-
return ExprError();
7117-
} else if (Result != TemplateDeductionResult::Success) {
7118-
if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Param)) {
7119-
Diag(Arg->getExprLoc(),
7120-
diag::err_non_type_template_parm_type_deduction_failure)
7121-
<< Param->getDeclName() << NTTP->getType() << Arg->getType()
7122-
<< Arg->getSourceRange();
7101+
if (Result != TemplateDeductionResult::Success) {
7102+
ParamType = TSI->getType();
7103+
if (StrictCheck || !DeductionArg->isTypeDependent()) {
7104+
if (Result == TemplateDeductionResult::AlreadyDiagnosed)
7105+
return ExprError();
7106+
if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Param))
7107+
Diag(Arg->getExprLoc(),
7108+
diag::err_non_type_template_parm_type_deduction_failure)
7109+
<< Param->getDeclName() << NTTP->getType() << Arg->getType()
7110+
<< Arg->getSourceRange();
7111+
NoteTemplateParameterLocation(*Param);
7112+
return ExprError();
71237113
}
7124-
NoteTemplateParameterLocation(*Param);
7125-
return ExprError();
7114+
ParamType = SubstAutoTypeDependent(ParamType);
7115+
assert(!ParamType.isNull() && "substituting DependentTy can't fail");
71267116
}
71277117
}
71287118
// CheckNonTypeTemplateParameterType will produce a diagnostic if there's
@@ -7144,14 +7134,16 @@ ExprResult Sema::CheckTemplateArgument(NamedDecl *Param, QualType ParamType,
71447134
// type-dependent, there's nothing we can check now.
71457135
if (ParamType->isDependentType() || DeductionArg->isTypeDependent()) {
71467136
// Force the argument to the type of the parameter to maintain invariants.
7147-
ExprResult E = ImpCastExprToType(
7148-
DeductionArg, ParamType.getNonLValueExprType(Context), CK_Dependent,
7149-
ParamType->isLValueReferenceType() ? VK_LValue
7150-
: ParamType->isRValueReferenceType() ? VK_XValue
7151-
: VK_PRValue);
7152-
if (E.isInvalid())
7153-
return ExprError();
7154-
setDeductionArg(E.get());
7137+
if (!IsDeduced) {
7138+
ExprResult E = ImpCastExprToType(
7139+
DeductionArg, ParamType.getNonLValueExprType(Context), CK_Dependent,
7140+
ParamType->isLValueReferenceType() ? VK_LValue
7141+
: ParamType->isRValueReferenceType() ? VK_XValue
7142+
: VK_PRValue);
7143+
if (E.isInvalid())
7144+
return ExprError();
7145+
setDeductionArg(E.get());
7146+
}
71557147
SugaredConverted = TemplateArgument(Arg, /*IsCanonical=*/false);
71567148
CanonicalConverted = TemplateArgument(
71577149
Context.getCanonicalTemplateArgument(SugaredConverted));
@@ -8555,6 +8547,7 @@ static SourceRange findTemplateParameter(unsigned Depth, TypeLoc TL) {
85558547
static bool CheckNonTypeTemplatePartialSpecializationArgs(
85568548
Sema &S, SourceLocation TemplateNameLoc, NonTypeTemplateParmDecl *Param,
85578549
const TemplateArgument *Args, unsigned NumArgs, bool IsDefaultArgument) {
8550+
bool HasError = false;
85588551
for (unsigned I = 0; I != NumArgs; ++I) {
85598552
if (Args[I].getKind() == TemplateArgument::Pack) {
85608553
if (CheckNonTypeTemplatePartialSpecializationArgs(
@@ -8595,6 +8588,11 @@ static bool CheckNonTypeTemplatePartialSpecializationArgs(
85958588
continue;
85968589
}
85978590

8591+
if (isa<RecoveryExpr>(ArgExpr)) {
8592+
HasError = true;
8593+
continue;
8594+
}
8595+
85988596
// C++ [temp.class.spec]p9:
85998597
// Within the argument list of a class template partial
86008598
// specialization, the following restrictions apply:
@@ -8638,7 +8636,7 @@ static bool CheckNonTypeTemplatePartialSpecializationArgs(
86388636
}
86398637
}
86408638

8641-
return false;
8639+
return HasError;
86428640
}
86438641

86448642
bool Sema::CheckTemplatePartialSpecializationArgs(

clang/lib/Sema/SemaTemplateDeduction.cpp

Lines changed: 12 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -5267,18 +5267,6 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *Init, QualType &Result,
52675267
SmallVector<DeducedTemplateArgument, 1> Deduced;
52685268
Deduced.resize(1);
52695269

5270-
// If deduction failed, don't diagnose if the initializer is dependent; it
5271-
// might acquire a matching type in the instantiation.
5272-
auto DeductionFailed = [&](TemplateDeductionResult TDK) {
5273-
if (Init->isTypeDependent()) {
5274-
Result =
5275-
SubstituteDeducedTypeTransform(*this, DependentResult).Apply(Type);
5276-
assert(!Result.isNull() && "substituting DependentTy can't fail");
5277-
return TemplateDeductionResult::Success;
5278-
}
5279-
return TDK;
5280-
};
5281-
52825270
SmallVector<OriginalCallArg, 4> OriginalCallArgs;
52835271

52845272
QualType DeducedType;
@@ -5328,9 +5316,9 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *Init, QualType &Result,
53285316
Diag(Info.getLocation(), diag::err_auto_inconsistent_deduction)
53295317
<< Info.FirstArg << Info.SecondArg << DeducedFromInitRange
53305318
<< Init->getSourceRange();
5331-
return DeductionFailed(TemplateDeductionResult::AlreadyDiagnosed);
5319+
return TemplateDeductionResult::AlreadyDiagnosed;
53325320
}
5333-
return DeductionFailed(TDK);
5321+
return TDK;
53345322
}
53355323

53365324
if (DeducedFromInitRange.isInvalid() &&
@@ -5352,12 +5340,12 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *Init, QualType &Result,
53525340
OriginalCallArgs,
53535341
/*Decomposed=*/false, /*ArgIdx=*/0, /*TDF=*/0, FailedTSC);
53545342
TDK != TemplateDeductionResult::Success)
5355-
return DeductionFailed(TDK);
5343+
return TDK;
53565344
}
53575345

53585346
// Could be null if somehow 'auto' appears in a non-deduced context.
53595347
if (Deduced[0].getKind() != TemplateArgument::Type)
5360-
return DeductionFailed(TemplateDeductionResult::Incomplete);
5348+
return TemplateDeductionResult::Incomplete;
53615349
DeducedType = Deduced[0].getAsType();
53625350

53635351
if (InitList) {
@@ -5371,7 +5359,7 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *Init, QualType &Result,
53715359
if (!Context.hasSameType(DeducedType, Result)) {
53725360
Info.FirstArg = Result;
53735361
Info.SecondArg = DeducedType;
5374-
return DeductionFailed(TemplateDeductionResult::Inconsistent);
5362+
return TemplateDeductionResult::Inconsistent;
53755363
}
53765364
DeducedType = Context.getCommonSugaredType(Result, DeducedType);
53775365
}
@@ -5395,7 +5383,7 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *Init, QualType &Result,
53955383
CheckOriginalCallArgDeduction(*this, Info, OriginalArg, DeducedA);
53965384
TDK != TemplateDeductionResult::Success) {
53975385
Result = QualType();
5398-
return DeductionFailed(TDK);
5386+
return TDK;
53995387
}
54005388
}
54015389

@@ -5417,13 +5405,17 @@ TypeSourceInfo *Sema::SubstAutoTypeSourceInfo(TypeSourceInfo *TypeWithAuto,
54175405
}
54185406

54195407
QualType Sema::SubstAutoTypeDependent(QualType TypeWithAuto) {
5420-
return SubstituteDeducedTypeTransform(*this, DependentAuto{false})
5408+
return SubstituteDeducedTypeTransform(
5409+
*this,
5410+
DependentAuto{/*IsPack=*/isa<PackExpansionType>(TypeWithAuto)})
54215411
.TransformType(TypeWithAuto);
54225412
}
54235413

54245414
TypeSourceInfo *
54255415
Sema::SubstAutoTypeSourceInfoDependent(TypeSourceInfo *TypeWithAuto) {
5426-
return SubstituteDeducedTypeTransform(*this, DependentAuto{false})
5416+
return SubstituteDeducedTypeTransform(
5417+
*this, DependentAuto{/*IsPack=*/isa<PackExpansionType>(
5418+
TypeWithAuto->getType())})
54275419
.TransformType(TypeWithAuto);
54285420
}
54295421

clang/test/SemaTemplate/temp_arg_template_p0522.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -83,11 +83,11 @@ namespace DependentType {
8383
namespace Auto {
8484
template<template<int> typename T> struct TInt {}; // #TInt
8585
template<template<int*> typename T> struct TIntPtr {}; // #TIntPtr
86-
template<template<auto> typename T> struct TAuto {};
86+
template<template<auto> typename T> struct TAuto {}; // #TAuto
8787
template<template<auto*> typename T> struct TAutoPtr {};
88-
template<template<decltype(auto)> typename T> struct TDecltypeAuto {};
88+
template<template<decltype(auto)> typename T> struct TDecltypeAuto {}; // #TDecltypeAuto
8989
template<auto> struct Auto;
90-
template<auto*> struct AutoPtr; // #AutoPtr
90+
template<auto*> struct AutoPtr;
9191
template<decltype(auto)> struct DecltypeAuto;
9292
template<int> struct Int;
9393
template<int*> struct IntPtr;
@@ -108,7 +108,7 @@ namespace Auto {
108108
TIntPtr<IntPtr> ipip;
109109

110110
TAuto<Auto> aa;
111-
TAuto<AutoPtr> aap; // expected-error@#AutoPtr {{could not match 'auto *' against 'auto'}}
111+
TAuto<AutoPtr> aap; // expected-error@#TAuto {{non-type template parameter '' with type 'auto *' has incompatible initializer of type 'auto'}}
112112
// expected-note@-1 {{different template parameters}}
113113
TAuto<Int> ai; // FIXME: ill-formed (?)
114114
TAuto<IntPtr> aip; // FIXME: ill-formed (?)
@@ -130,7 +130,7 @@ namespace Auto {
130130
// parameters (such as 'user-defined-type &') that are not valid 'auto'
131131
// parameters.
132132
TDecltypeAuto<Auto> daa;
133-
TDecltypeAuto<AutoPtr> daap; // expected-error@#AutoPtr {{could not match 'auto *' against 'decltype(auto)'}}
133+
TDecltypeAuto<AutoPtr> daap; // expected-error@#TDecltypeAuto {{non-type template parameter '' with type 'auto *' has incompatible initializer of type 'decltype(auto)'}}
134134
// expected-note@-1 {{different template parameters}}
135135

136136
int n;

0 commit comments

Comments
 (0)