Skip to content

Commit 4a4573a

Browse files
authored
[clang] simplify placeholder type deduction for constant template parameters (#160439)
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 378b6d5 commit 4a4573a

File tree

4 files changed

+51
-61
lines changed

4 files changed

+51
-61
lines changed

clang/docs/ReleaseNotes.rst

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

clang/lib/Sema/SemaTemplate.cpp

Lines changed: 32 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(
@@ -8569,6 +8562,10 @@ static bool CheckNonTypeTemplatePartialSpecializationArgs(
85698562
continue;
85708563

85718564
Expr *ArgExpr = Args[I].getAsExpr();
8565+
if (ArgExpr->containsErrors()) {
8566+
HasError = true;
8567+
continue;
8568+
}
85728569

85738570
// We can have a pack expansion of any of the bullets below.
85748571
if (PackExpansionExpr *Expansion = dyn_cast<PackExpansionExpr>(ArgExpr))
@@ -8638,7 +8635,7 @@ static bool CheckNonTypeTemplatePartialSpecializationArgs(
86388635
}
86398636
}
86408637

8641-
return false;
8638+
return HasError;
86428639
}
86438640

86448641
bool Sema::CheckTemplatePartialSpecializationArgs(

clang/lib/Sema/SemaTemplateDeduction.cpp

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

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

52795267
QualType DeducedType;
@@ -5323,9 +5311,9 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *Init, QualType &Result,
53235311
Diag(Info.getLocation(), diag::err_auto_inconsistent_deduction)
53245312
<< Info.FirstArg << Info.SecondArg << DeducedFromInitRange
53255313
<< Init->getSourceRange();
5326-
return DeductionFailed(TemplateDeductionResult::AlreadyDiagnosed);
5314+
return TemplateDeductionResult::AlreadyDiagnosed;
53275315
}
5328-
return DeductionFailed(TDK);
5316+
return TDK;
53295317
}
53305318

53315319
if (DeducedFromInitRange.isInvalid() &&
@@ -5347,12 +5335,12 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *Init, QualType &Result,
53475335
OriginalCallArgs,
53485336
/*Decomposed=*/false, /*ArgIdx=*/0, /*TDF=*/0, FailedTSC);
53495337
TDK != TemplateDeductionResult::Success)
5350-
return DeductionFailed(TDK);
5338+
return TDK;
53515339
}
53525340

53535341
// Could be null if somehow 'auto' appears in a non-deduced context.
53545342
if (Deduced[0].getKind() != TemplateArgument::Type)
5355-
return DeductionFailed(TemplateDeductionResult::Incomplete);
5343+
return TemplateDeductionResult::Incomplete;
53565344
DeducedType = Deduced[0].getAsType();
53575345

53585346
if (InitList) {
@@ -5366,7 +5354,7 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *Init, QualType &Result,
53665354
if (!Context.hasSameType(DeducedType, Result)) {
53675355
Info.FirstArg = Result;
53685356
Info.SecondArg = DeducedType;
5369-
return DeductionFailed(TemplateDeductionResult::Inconsistent);
5357+
return TemplateDeductionResult::Inconsistent;
53705358
}
53715359
DeducedType = Context.getCommonSugaredType(Result, DeducedType);
53725360
}
@@ -5390,7 +5378,7 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *Init, QualType &Result,
53905378
CheckOriginalCallArgDeduction(*this, Info, OriginalArg, DeducedA);
53915379
TDK != TemplateDeductionResult::Success) {
53925380
Result = QualType();
5393-
return DeductionFailed(TDK);
5381+
return TDK;
53945382
}
53955383
}
53965384

@@ -5412,13 +5400,17 @@ TypeSourceInfo *Sema::SubstAutoTypeSourceInfo(TypeSourceInfo *TypeWithAuto,
54125400
}
54135401

54145402
QualType Sema::SubstAutoTypeDependent(QualType TypeWithAuto) {
5415-
return SubstituteDeducedTypeTransform(*this, DependentAuto{false})
5403+
return SubstituteDeducedTypeTransform(
5404+
*this,
5405+
DependentAuto{/*IsPack=*/isa<PackExpansionType>(TypeWithAuto)})
54165406
.TransformType(TypeWithAuto);
54175407
}
54185408

54195409
TypeSourceInfo *
54205410
Sema::SubstAutoTypeSourceInfoDependent(TypeSourceInfo *TypeWithAuto) {
5421-
return SubstituteDeducedTypeTransform(*this, DependentAuto{false})
5411+
return SubstituteDeducedTypeTransform(
5412+
*this, DependentAuto{/*IsPack=*/isa<PackExpansionType>(
5413+
TypeWithAuto->getType())})
54225414
.TransformType(TypeWithAuto);
54235415
}
54245416

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)