Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,8 @@ Improvements to Clang's diagnostics
"format specifies type 'unsigned int' but the argument has type 'int', which differs in signedness [-Wformat-signedness]"
"signedness of format specifier 'u' is incompatible with 'c' [-Wformat-signedness]"
and the API-visible diagnostic id will be appropriate.

- Clang now produces better diagnostics for template template parameter matching
involving 'auto' template parameters.
- Fixed false positives in ``-Waddress-of-packed-member`` diagnostics when
potential misaligned members get processed before they can get discarded.
(#GH144729)
Expand Down
67 changes: 32 additions & 35 deletions clang/lib/Sema/SemaTemplate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7068,22 +7068,8 @@ ExprResult Sema::CheckTemplateArgument(NamedDecl *Param, QualType ParamType,

// If the parameter type somehow involves auto, deduce the type now.
DeducedType *DeducedT = ParamType->getContainedDeducedType();
if (getLangOpts().CPlusPlus17 && DeducedT && !DeducedT->isDeduced()) {
// During template argument deduction, we allow 'decltype(auto)' to
// match an arbitrary dependent argument.
// FIXME: The language rules don't say what happens in this case.
// FIXME: We get an opaque dependent type out of decltype(auto) if the
// expression is merely instantiation-dependent; is this enough?
if (DeductionArg->isTypeDependent()) {
auto *AT = dyn_cast<AutoType>(DeducedT);
if (AT && AT->isDecltypeAuto()) {
SugaredConverted = TemplateArgument(Arg, /*IsCanonical=*/false);
CanonicalConverted = TemplateArgument(
Context.getCanonicalTemplateArgument(SugaredConverted));
return Arg;
}
}

bool IsDeduced = DeducedT && !DeducedT->isDeduced();
if (IsDeduced) {
// When checking a deduced template argument, deduce from its type even if
// the type is dependent, in order to check the types of non-type template
// arguments line up properly in partial ordering.
Expand Down Expand Up @@ -7112,17 +7098,21 @@ ExprResult Sema::CheckTemplateArgument(NamedDecl *Param, QualType ParamType,
// along with the other associated constraints after
// checking the template argument list.
/*IgnoreConstraints=*/true);
if (Result == TemplateDeductionResult::AlreadyDiagnosed) {
return ExprError();
} else if (Result != TemplateDeductionResult::Success) {
if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Param)) {
Diag(Arg->getExprLoc(),
diag::err_non_type_template_parm_type_deduction_failure)
<< Param->getDeclName() << NTTP->getType() << Arg->getType()
<< Arg->getSourceRange();
if (Result != TemplateDeductionResult::Success) {
ParamType = TSI->getType();
if (StrictCheck || !DeductionArg->isTypeDependent()) {
if (Result == TemplateDeductionResult::AlreadyDiagnosed)
return ExprError();
if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Param))
Diag(Arg->getExprLoc(),
diag::err_non_type_template_parm_type_deduction_failure)
<< Param->getDeclName() << NTTP->getType() << Arg->getType()
<< Arg->getSourceRange();
NoteTemplateParameterLocation(*Param);
return ExprError();
}
NoteTemplateParameterLocation(*Param);
return ExprError();
ParamType = SubstAutoTypeDependent(ParamType);
assert(!ParamType.isNull() && "substituting DependentTy can't fail");
}
}
// CheckNonTypeTemplateParameterType will produce a diagnostic if there's
Expand All @@ -7144,14 +7134,16 @@ ExprResult Sema::CheckTemplateArgument(NamedDecl *Param, QualType ParamType,
// type-dependent, there's nothing we can check now.
if (ParamType->isDependentType() || DeductionArg->isTypeDependent()) {
// Force the argument to the type of the parameter to maintain invariants.
ExprResult E = ImpCastExprToType(
DeductionArg, ParamType.getNonLValueExprType(Context), CK_Dependent,
ParamType->isLValueReferenceType() ? VK_LValue
: ParamType->isRValueReferenceType() ? VK_XValue
: VK_PRValue);
if (E.isInvalid())
return ExprError();
setDeductionArg(E.get());
if (!IsDeduced) {
ExprResult E = ImpCastExprToType(
DeductionArg, ParamType.getNonLValueExprType(Context), CK_Dependent,
ParamType->isLValueReferenceType() ? VK_LValue
: ParamType->isRValueReferenceType() ? VK_XValue
: VK_PRValue);
if (E.isInvalid())
return ExprError();
setDeductionArg(E.get());
}
SugaredConverted = TemplateArgument(Arg, /*IsCanonical=*/false);
CanonicalConverted = TemplateArgument(
Context.getCanonicalTemplateArgument(SugaredConverted));
Expand Down Expand Up @@ -8555,6 +8547,7 @@ static SourceRange findTemplateParameter(unsigned Depth, TypeLoc TL) {
static bool CheckNonTypeTemplatePartialSpecializationArgs(
Sema &S, SourceLocation TemplateNameLoc, NonTypeTemplateParmDecl *Param,
const TemplateArgument *Args, unsigned NumArgs, bool IsDefaultArgument) {
bool HasError = false;
for (unsigned I = 0; I != NumArgs; ++I) {
if (Args[I].getKind() == TemplateArgument::Pack) {
if (CheckNonTypeTemplatePartialSpecializationArgs(
Expand All @@ -8569,6 +8562,10 @@ static bool CheckNonTypeTemplatePartialSpecializationArgs(
continue;

Expr *ArgExpr = Args[I].getAsExpr();
if (ArgExpr->containsErrors()) {
HasError = true;
continue;
}

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

return false;
return HasError;
}

bool Sema::CheckTemplatePartialSpecializationArgs(
Expand Down
32 changes: 12 additions & 20 deletions clang/lib/Sema/SemaTemplateDeduction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5262,18 +5262,6 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *Init, QualType &Result,
SmallVector<DeducedTemplateArgument, 1> Deduced;
Deduced.resize(1);

// If deduction failed, don't diagnose if the initializer is dependent; it
// might acquire a matching type in the instantiation.
auto DeductionFailed = [&](TemplateDeductionResult TDK) {
if (Init->isTypeDependent()) {
Result =
SubstituteDeducedTypeTransform(*this, DependentResult).Apply(Type);
assert(!Result.isNull() && "substituting DependentTy can't fail");
return TemplateDeductionResult::Success;
}
return TDK;
};

SmallVector<OriginalCallArg, 4> OriginalCallArgs;

QualType DeducedType;
Expand Down Expand Up @@ -5323,9 +5311,9 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *Init, QualType &Result,
Diag(Info.getLocation(), diag::err_auto_inconsistent_deduction)
<< Info.FirstArg << Info.SecondArg << DeducedFromInitRange
<< Init->getSourceRange();
return DeductionFailed(TemplateDeductionResult::AlreadyDiagnosed);
return TemplateDeductionResult::AlreadyDiagnosed;
}
return DeductionFailed(TDK);
return TDK;
}

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

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

if (InitList) {
Expand All @@ -5366,7 +5354,7 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *Init, QualType &Result,
if (!Context.hasSameType(DeducedType, Result)) {
Info.FirstArg = Result;
Info.SecondArg = DeducedType;
return DeductionFailed(TemplateDeductionResult::Inconsistent);
return TemplateDeductionResult::Inconsistent;
}
DeducedType = Context.getCommonSugaredType(Result, DeducedType);
}
Expand All @@ -5390,7 +5378,7 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *Init, QualType &Result,
CheckOriginalCallArgDeduction(*this, Info, OriginalArg, DeducedA);
TDK != TemplateDeductionResult::Success) {
Result = QualType();
return DeductionFailed(TDK);
return TDK;
}
}

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

QualType Sema::SubstAutoTypeDependent(QualType TypeWithAuto) {
return SubstituteDeducedTypeTransform(*this, DependentAuto{false})
return SubstituteDeducedTypeTransform(
*this,
DependentAuto{/*IsPack=*/isa<PackExpansionType>(TypeWithAuto)})
.TransformType(TypeWithAuto);
}

TypeSourceInfo *
Sema::SubstAutoTypeSourceInfoDependent(TypeSourceInfo *TypeWithAuto) {
return SubstituteDeducedTypeTransform(*this, DependentAuto{false})
return SubstituteDeducedTypeTransform(
*this, DependentAuto{/*IsPack=*/isa<PackExpansionType>(
TypeWithAuto->getType())})
.TransformType(TypeWithAuto);
}

Expand Down
10 changes: 5 additions & 5 deletions clang/test/SemaTemplate/temp_arg_template_p0522.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,11 +83,11 @@ namespace DependentType {
namespace Auto {
template<template<int> typename T> struct TInt {}; // #TInt
template<template<int*> typename T> struct TIntPtr {}; // #TIntPtr
template<template<auto> typename T> struct TAuto {};
template<template<auto> typename T> struct TAuto {}; // #TAuto
template<template<auto*> typename T> struct TAutoPtr {};
template<template<decltype(auto)> typename T> struct TDecltypeAuto {};
template<template<decltype(auto)> typename T> struct TDecltypeAuto {}; // #TDecltypeAuto
template<auto> struct Auto;
template<auto*> struct AutoPtr; // #AutoPtr
template<auto*> struct AutoPtr;
template<decltype(auto)> struct DecltypeAuto;
template<int> struct Int;
template<int*> struct IntPtr;
Expand All @@ -108,7 +108,7 @@ namespace Auto {
TIntPtr<IntPtr> ipip;

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

int n;
Expand Down