[clang] [clang] check deduction consistency when partial ordering function templates (PR #100692)
Matheus Izvekov via cfe-commits
cfe-commits at lists.llvm.org
Wed Aug 28 11:31:07 PDT 2024
https://github.com/mizvekov updated https://github.com/llvm/llvm-project/pull/100692
>From f8fd471a954f5e304f3118df3236cf7ff4ef1020 Mon Sep 17 00:00:00 2001
From: Matheus Izvekov <mizvekov at gmail.com>
Date: Wed, 24 Jul 2024 03:59:41 -0300
Subject: [PATCH 1/4] [clang] check deduction consistency when partial ordering
function templates
This makes partial ordering of function templates consistent with
other entities.
Fixes #18291
---
clang/docs/ReleaseNotes.rst | 2 +
clang/include/clang/Sema/Sema.h | 7 +-
clang/lib/AST/ExprConstant.cpp | 1 -
clang/lib/Sema/SemaTemplateDeduction.cpp | 827 ++++++++++++------
clang/lib/Sema/SemaTemplateInstantiate.cpp | 29 +-
.../test/CodeCompletion/variadic-template.cpp | 2 +-
clang/test/Index/complete-call.cpp | 5 +-
clang/test/SemaCXX/cxx2b-deducing-this.cpp | 43 +
clang/test/SemaTemplate/GH18291.cpp | 32 +
clang/test/SemaTemplate/cwg2398.cpp | 14 +
clang/test/SemaTemplate/temp_arg_nontype.cpp | 14 +-
clang/test/SemaTemplate/temp_arg_type.cpp | 7 +-
.../Templight/templight-empty-entries-fix.cpp | 92 +-
13 files changed, 761 insertions(+), 314 deletions(-)
create mode 100644 clang/test/SemaTemplate/GH18291.cpp
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 249249971dec7c..5f9c3e1969640d 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -276,6 +276,8 @@ Bug Fixes to C++ Support
- Clang now properly handles the order of attributes in `extern` blocks. (#GH101990).
- Fixed an assertion failure by preventing null explicit object arguments from being deduced. (#GH102025).
- Correctly check constraints of explicit instantiations of member functions. (#GH46029)
+- When performing partial ordering of function templates, clang now checks that
+ the deduction was consistent. Fixes (#GH18291).
Bug Fixes to AST Handling
^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 299a916b9abf8d..b2bfd0e035e95f 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -13273,6 +13273,10 @@ class Sema final : public SemaBase {
/// \param AllowDeducedTST Whether a DeducedTemplateSpecializationType is
/// acceptable as the top level type of the result.
///
+ /// \param IsIncompleteSubstitution If provided, the pointee will be set
+ /// whenever substitution would perform a replacement with a null or
+ /// non-existent template argument.
+ ///
/// \returns If the instantiation succeeds, the instantiated
/// type. Otherwise, produces diagnostics and returns a NULL type.
TypeSourceInfo *SubstType(TypeSourceInfo *T,
@@ -13282,7 +13286,8 @@ class Sema final : public SemaBase {
QualType SubstType(QualType T,
const MultiLevelTemplateArgumentList &TemplateArgs,
- SourceLocation Loc, DeclarationName Entity);
+ SourceLocation Loc, DeclarationName Entity,
+ bool *IsIncompleteSubstitution = nullptr);
TypeSourceInfo *SubstType(TypeLoc TL,
const MultiLevelTemplateArgumentList &TemplateArgs,
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 5540f58b526705..91c1883e7ab24e 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -5399,7 +5399,6 @@ static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info,
const Expr *RetExpr = cast<ReturnStmt>(S)->getRetValue();
FullExpressionRAII Scope(Info);
if (RetExpr && RetExpr->isValueDependent()) {
- EvaluateDependentExpr(RetExpr, Info);
// We know we returned, but we don't know what the value is.
return ESR_Failed;
}
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp
index 35bc8cd713f06c..8ddc7a4df62444 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -138,7 +138,7 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
Sema &S, TemplateParameterList *TemplateParams, QualType Param,
QualType Arg, TemplateDeductionInfo &Info,
SmallVectorImpl<DeducedTemplateArgument> &Deduced, unsigned TDF,
- bool PartialOrdering = false, bool DeducedFromArrayBound = false);
+ bool PartialOrdering, bool DeducedFromArrayBound, bool *HasDeducedAnyParam);
enum class PackFold { ParameterToArgument, ArgumentToParameter };
static TemplateDeductionResult
@@ -147,8 +147,8 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams,
ArrayRef<TemplateArgument> As,
TemplateDeductionInfo &Info,
SmallVectorImpl<DeducedTemplateArgument> &Deduced,
- bool NumberOfArgumentsMustMatch,
- PackFold PackFold = PackFold::ParameterToArgument);
+ bool NumberOfArgumentsMustMatch, PackFold PackFold,
+ bool *HasDeducedAnyParam);
static void MarkUsedTemplateParameters(ASTContext &Ctx,
const TemplateArgument &TemplateArg,
@@ -396,12 +396,13 @@ checkDeducedTemplateArguments(ASTContext &Context,
/// Deduce the value of the given non-type template parameter
/// as the given deduced template argument. All non-type template parameter
/// deduction is funneled through here.
-static TemplateDeductionResult DeduceNonTypeTemplateArgument(
- Sema &S, TemplateParameterList *TemplateParams,
- const NonTypeTemplateParmDecl *NTTP,
- const DeducedTemplateArgument &NewDeduced, QualType ValueType,
- TemplateDeductionInfo &Info,
- SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
+static TemplateDeductionResult
+DeduceNonTypeTemplateArgument(Sema &S, TemplateParameterList *TemplateParams,
+ const NonTypeTemplateParmDecl *NTTP,
+ const DeducedTemplateArgument &NewDeduced,
+ QualType ValueType, TemplateDeductionInfo &Info,
+ SmallVectorImpl<DeducedTemplateArgument> &Deduced,
+ bool *HasDeducedAnyParam) {
assert(NTTP->getDepth() == Info.getDeducedDepth() &&
"deducing non-type template argument with wrong depth");
@@ -445,7 +446,7 @@ static TemplateDeductionResult DeduceNonTypeTemplateArgument(
return DeduceTemplateArgumentsByTypeMatch(
S, TemplateParams, ParamType, ValueType, Info, Deduced,
TDF_SkipNonDependent, /*PartialOrdering=*/false,
- /*ArrayBound=*/NewDeduced.wasDeducedFromArrayBound());
+ /*ArrayBound=*/NewDeduced.wasDeducedFromArrayBound(), HasDeducedAnyParam);
}
/// Deduce the value of the given non-type template parameter
@@ -454,21 +455,23 @@ static TemplateDeductionResult DeduceNonTypeTemplateArgument(
Sema &S, TemplateParameterList *TemplateParams,
const NonTypeTemplateParmDecl *NTTP, const llvm::APSInt &Value,
QualType ValueType, bool DeducedFromArrayBound, TemplateDeductionInfo &Info,
- SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
+ SmallVectorImpl<DeducedTemplateArgument> &Deduced,
+ bool *HasDeducedAnyParam) {
return DeduceNonTypeTemplateArgument(
S, TemplateParams, NTTP,
DeducedTemplateArgument(S.Context, Value, ValueType,
DeducedFromArrayBound),
- ValueType, Info, Deduced);
+ ValueType, Info, Deduced, HasDeducedAnyParam);
}
/// Deduce the value of the given non-type template parameter
/// from the given null pointer template argument type.
-static TemplateDeductionResult DeduceNullPtrTemplateArgument(
- Sema &S, TemplateParameterList *TemplateParams,
- const NonTypeTemplateParmDecl *NTTP, QualType NullPtrType,
- TemplateDeductionInfo &Info,
- SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
+static TemplateDeductionResult
+DeduceNullPtrTemplateArgument(Sema &S, TemplateParameterList *TemplateParams,
+ const NonTypeTemplateParmDecl *NTTP,
+ QualType NullPtrType, TemplateDeductionInfo &Info,
+ SmallVectorImpl<DeducedTemplateArgument> &Deduced,
+ bool *HasDeducedAnyParam) {
Expr *Value = S.ImpCastExprToType(
new (S.Context) CXXNullPtrLiteralExpr(S.Context.NullPtrTy,
NTTP->getLocation()),
@@ -476,37 +479,40 @@ static TemplateDeductionResult DeduceNullPtrTemplateArgument(
NullPtrType->isMemberPointerType() ? CK_NullToMemberPointer
: CK_NullToPointer)
.get();
- return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP,
- DeducedTemplateArgument(Value),
- Value->getType(), Info, Deduced);
+ return DeduceNonTypeTemplateArgument(
+ S, TemplateParams, NTTP, DeducedTemplateArgument(Value), Value->getType(),
+ Info, Deduced, HasDeducedAnyParam);
}
/// Deduce the value of the given non-type template parameter
/// from the given type- or value-dependent expression.
///
/// \returns true if deduction succeeded, false otherwise.
-static TemplateDeductionResult DeduceNonTypeTemplateArgument(
- Sema &S, TemplateParameterList *TemplateParams,
- const NonTypeTemplateParmDecl *NTTP, Expr *Value,
- TemplateDeductionInfo &Info,
- SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
- return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP,
- DeducedTemplateArgument(Value),
- Value->getType(), Info, Deduced);
+static TemplateDeductionResult
+DeduceNonTypeTemplateArgument(Sema &S, TemplateParameterList *TemplateParams,
+ const NonTypeTemplateParmDecl *NTTP, Expr *Value,
+ TemplateDeductionInfo &Info,
+ SmallVectorImpl<DeducedTemplateArgument> &Deduced,
+ bool *HasDeducedAnyParam) {
+ return DeduceNonTypeTemplateArgument(
+ S, TemplateParams, NTTP, DeducedTemplateArgument(Value), Value->getType(),
+ Info, Deduced, HasDeducedAnyParam);
}
/// Deduce the value of the given non-type template parameter
/// from the given declaration.
///
/// \returns true if deduction succeeded, false otherwise.
-static TemplateDeductionResult DeduceNonTypeTemplateArgument(
- Sema &S, TemplateParameterList *TemplateParams,
- const NonTypeTemplateParmDecl *NTTP, ValueDecl *D, QualType T,
- TemplateDeductionInfo &Info,
- SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
+static TemplateDeductionResult
+DeduceNonTypeTemplateArgument(Sema &S, TemplateParameterList *TemplateParams,
+ const NonTypeTemplateParmDecl *NTTP, ValueDecl *D,
+ QualType T, TemplateDeductionInfo &Info,
+ SmallVectorImpl<DeducedTemplateArgument> &Deduced,
+ bool *HasDeducedAnyParam) {
TemplateArgument New(D, T);
- return DeduceNonTypeTemplateArgument(
- S, TemplateParams, NTTP, DeducedTemplateArgument(New), T, Info, Deduced);
+ return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP,
+ DeducedTemplateArgument(New), T, Info,
+ Deduced, HasDeducedAnyParam);
}
/// Create a shallow copy of a given template parameter declaration, with
@@ -569,7 +575,8 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams,
TemplateName Param, TemplateName Arg,
TemplateDeductionInfo &Info,
ArrayRef<TemplateArgument> DefaultArguments,
- SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
+ SmallVectorImpl<DeducedTemplateArgument> &Deduced,
+ bool *HasDeducedAnyParam) {
TemplateDecl *ParamDecl = Param.getAsTemplateDecl();
if (!ParamDecl) {
// The parameter type is dependent and is not a template template parameter,
@@ -626,6 +633,8 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams,
}
Deduced[TempParam->getIndex()] = Result;
+ if (HasDeducedAnyParam)
+ *HasDeducedAnyParam = true;
return TemplateDeductionResult::Success;
}
@@ -673,7 +682,8 @@ static TemplateDeductionResult
DeduceTemplateSpecArguments(Sema &S, TemplateParameterList *TemplateParams,
const QualType P, QualType A,
TemplateDeductionInfo &Info,
- SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
+ SmallVectorImpl<DeducedTemplateArgument> &Deduced,
+ bool *HasDeducedAnyParam) {
QualType UP = P;
if (const auto *IP = P->getAs<InjectedClassNameType>())
UP = IP->getInjectedSpecializationType();
@@ -720,17 +730,19 @@ DeduceTemplateSpecArguments(Sema &S, TemplateParameterList *TemplateParams,
->template_arguments();
// Perform template argument deduction for the template name.
- if (auto Result = DeduceTemplateArguments(S, TemplateParams, TNP, TNA, Info,
- AResolved, Deduced);
+ if (auto Result =
+ DeduceTemplateArguments(S, TemplateParams, TNP, TNA, Info,
+ AResolved, Deduced, HasDeducedAnyParam);
Result != TemplateDeductionResult::Success)
return Result;
// Perform template argument deduction on each template
// argument. Ignore any missing/extra arguments, since they could be
// filled in by default arguments.
- return DeduceTemplateArguments(S, TemplateParams, PResolved, AResolved,
- Info, Deduced,
- /*NumberOfArgumentsMustMatch=*/false);
+ return DeduceTemplateArguments(
+ S, TemplateParams, PResolved, AResolved, Info, Deduced,
+ /*NumberOfArgumentsMustMatch=*/false, PackFold::ParameterToArgument,
+ HasDeducedAnyParam);
}
// If the argument type is a class template specialization, we
@@ -751,16 +763,18 @@ DeduceTemplateSpecArguments(Sema &S, TemplateParameterList *TemplateParams,
*NNS, false, TemplateName(SA->getSpecializedTemplate()));
// Perform template argument deduction for the template name.
- if (auto Result =
- DeduceTemplateArguments(S, TemplateParams, TNP, TNA, Info,
- SA->getTemplateArgs().asArray(), Deduced);
+ if (auto Result = DeduceTemplateArguments(S, TemplateParams, TNP, TNA, Info,
+ SA->getTemplateArgs().asArray(),
+ Deduced, HasDeducedAnyParam);
Result != TemplateDeductionResult::Success)
return Result;
// Perform template argument deduction for the template arguments.
return DeduceTemplateArguments(S, TemplateParams, PResolved,
SA->getTemplateArgs().asArray(), Info, Deduced,
- /*NumberOfArgumentsMustMatch=*/true);
+ /*NumberOfArgumentsMustMatch=*/true,
+ PackFold::ParameterToArgument,
+ HasDeducedAnyParam);
}
static bool IsPossiblyOpaquelyQualifiedTypeInternal(const Type *T) {
@@ -834,12 +848,16 @@ namespace {
class PackDeductionScope {
public:
/// Prepare to deduce the packs named within Pattern.
+ /// \param FinishingDeduction Don't attempt to deduce the pack. Useful when
+ /// just checking a previous deduction of the pack.
PackDeductionScope(Sema &S, TemplateParameterList *TemplateParams,
SmallVectorImpl<DeducedTemplateArgument> &Deduced,
TemplateDeductionInfo &Info, TemplateArgument Pattern,
- bool DeducePackIfNotAlreadyDeduced = false)
+ bool DeducePackIfNotAlreadyDeduced = false,
+ bool FinishingDeduction = false)
: S(S), TemplateParams(TemplateParams), Deduced(Deduced), Info(Info),
- DeducePackIfNotAlreadyDeduced(DeducePackIfNotAlreadyDeduced){
+ DeducePackIfNotAlreadyDeduced(DeducePackIfNotAlreadyDeduced),
+ FinishingDeduction(FinishingDeduction) {
unsigned NumNamedPacks = addPacks(Pattern);
finishConstruction(NumNamedPacks);
}
@@ -859,8 +877,10 @@ class PackDeductionScope {
// by this pack expansion, then clear out the deduction.
DeducedFromEarlierParameter = !Deduced[Index].isNull();
DeducedPack Pack(Index);
- Pack.Saved = Deduced[Index];
- Deduced[Index] = TemplateArgument();
+ if (!FinishingDeduction) {
+ Pack.Saved = Deduced[Index];
+ Deduced[Index] = TemplateArgument();
+ }
// FIXME: What if we encounter multiple packs with different numbers of
// pre-expanded expansions? (This should already have been diagnosed
@@ -976,7 +996,7 @@ class PackDeductionScope {
// FIXME: If we could represent a "depth i, index j, pack elem k"
// parameter, we could substitute the partially-substituted pack
// everywhere and avoid this.
- if (!IsPartiallyExpanded)
+ if (!FinishingDeduction && !IsPartiallyExpanded)
Deduced[Pack.Index] = Pack.New[PackElements];
}
}
@@ -1026,18 +1046,20 @@ class PackDeductionScope {
// Capture the deduced template arguments for each parameter pack expanded
// by this pack expansion, add them to the list of arguments we've deduced
// for that pack, then clear out the deduced argument.
- for (auto &Pack : Packs) {
- DeducedTemplateArgument &DeducedArg = Deduced[Pack.Index];
- if (!Pack.New.empty() || !DeducedArg.isNull()) {
- while (Pack.New.size() < PackElements)
- Pack.New.push_back(DeducedTemplateArgument());
- if (Pack.New.size() == PackElements)
- Pack.New.push_back(DeducedArg);
- else
- Pack.New[PackElements] = DeducedArg;
- DeducedArg = Pack.New.size() > PackElements + 1
- ? Pack.New[PackElements + 1]
- : DeducedTemplateArgument();
+ if (!FinishingDeduction) {
+ for (auto &Pack : Packs) {
+ DeducedTemplateArgument &DeducedArg = Deduced[Pack.Index];
+ if (!Pack.New.empty() || !DeducedArg.isNull()) {
+ while (Pack.New.size() < PackElements)
+ Pack.New.push_back(DeducedTemplateArgument());
+ if (Pack.New.size() == PackElements)
+ Pack.New.push_back(DeducedArg);
+ else
+ Pack.New[PackElements] = DeducedArg;
+ DeducedArg = Pack.New.size() > PackElements + 1
+ ? Pack.New[PackElements + 1]
+ : DeducedTemplateArgument();
+ }
}
}
++PackElements;
@@ -1047,11 +1069,14 @@ class PackDeductionScope {
/// producing the argument packs and checking for consistency with prior
/// deductions.
TemplateDeductionResult finish() {
+ if (FinishingDeduction)
+ return TemplateDeductionResult::Success;
// Build argument packs for each of the parameter packs expanded by this
// pack expansion.
for (auto &Pack : Packs) {
// Put back the old value for this pack.
- Deduced[Pack.Index] = Pack.Saved;
+ if (!FinishingDeduction)
+ Deduced[Pack.Index] = Pack.Saved;
// Always make sure the size of this pack is correct, even if we didn't
// deduce any values for it.
@@ -1151,6 +1176,7 @@ class PackDeductionScope {
bool IsPartiallyExpanded = false;
bool DeducePackIfNotAlreadyDeduced = false;
bool DeducedFromEarlierParameter = false;
+ bool FinishingDeduction = false;
/// The number of expansions, if we have a fully-expanded pack in this scope.
std::optional<unsigned> FixedNumExpansions;
@@ -1159,43 +1185,13 @@ class PackDeductionScope {
} // namespace
-/// Deduce the template arguments by comparing the list of parameter
-/// types to the list of argument types, as in the parameter-type-lists of
-/// function types (C++ [temp.deduct.type]p10).
-///
-/// \param S The semantic analysis object within which we are deducing
-///
-/// \param TemplateParams The template parameters that we are deducing
-///
-/// \param Params The list of parameter types
-///
-/// \param NumParams The number of types in \c Params
-///
-/// \param Args The list of argument types
-///
-/// \param NumArgs The number of types in \c Args
-///
-/// \param Info information about the template argument deduction itself
-///
-/// \param Deduced the deduced template arguments
-///
-/// \param TDF bitwise OR of the TemplateDeductionFlags bits that describe
-/// how template argument deduction is performed.
-///
-/// \param PartialOrdering If true, we are performing template argument
-/// deduction for during partial ordering for a call
-/// (C++0x [temp.deduct.partial]).
-///
-/// \returns the result of template argument deduction so far. Note that a
-/// "success" result means that template argument deduction has not yet failed,
-/// but it may still fail, later, for other reasons.
-static TemplateDeductionResult
-DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams,
- const QualType *Params, unsigned NumParams,
- const QualType *Args, unsigned NumArgs,
- TemplateDeductionInfo &Info,
- SmallVectorImpl<DeducedTemplateArgument> &Deduced,
- unsigned TDF, bool PartialOrdering = false) {
+template <class T>
+static TemplateDeductionResult DeduceForEachType(
+ Sema &S, TemplateParameterList *TemplateParams, const QualType *Params,
+ unsigned NumParams, const QualType *Args, unsigned NumArgs,
+ TemplateDeductionInfo &Info,
+ SmallVectorImpl<DeducedTemplateArgument> &Deduced, bool PartialOrdering,
+ bool FinishingDeduction, T &&DeductFunc) {
// C++0x [temp.deduct.type]p10:
// Similarly, if P has a form that contains (T), then each parameter type
// Pi of the respective parameter-type- list of P is compared with the
@@ -1221,11 +1217,11 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams,
return TemplateDeductionResult::MiscellaneousDeductionFailure;
}
- if (TemplateDeductionResult Result = DeduceTemplateArgumentsByTypeMatch(
- S, TemplateParams, Params[ParamIdx].getUnqualifiedType(),
- Args[ArgIdx].getUnqualifiedType(), Info, Deduced, TDF,
- PartialOrdering,
- /*DeducedFromArrayBound=*/false);
+ if (TemplateDeductionResult Result =
+ DeductFunc(S, TemplateParams, ParamIdx, ArgIdx,
+ Params[ParamIdx].getUnqualifiedType(),
+ Args[ArgIdx].getUnqualifiedType(), Info, Deduced,
+ PartialOrdering);
Result != TemplateDeductionResult::Success)
return Result;
@@ -1241,20 +1237,21 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams,
// template parameter packs expanded by the function parameter pack.
QualType Pattern = Expansion->getPattern();
- PackDeductionScope PackScope(S, TemplateParams, Deduced, Info, Pattern);
+ PackDeductionScope PackScope(S, TemplateParams, Deduced, Info, Pattern,
+ /*DeducePackIfNotAlreadyDeduced=*/false,
+ FinishingDeduction);
// A pack scope with fixed arity is not really a pack any more, so is not
// a non-deduced context.
if (ParamIdx + 1 == NumParams || PackScope.hasFixedArity()) {
for (; ArgIdx < NumArgs && PackScope.hasNextElement(); ++ArgIdx) {
// Deduce template arguments from the pattern.
- if (TemplateDeductionResult Result = DeduceTemplateArgumentsByTypeMatch(
- S, TemplateParams, Pattern.getUnqualifiedType(),
- Args[ArgIdx].getUnqualifiedType(), Info, Deduced, TDF,
- PartialOrdering, /*DeducedFromArrayBound=*/false);
+ if (TemplateDeductionResult Result = DeductFunc(
+ S, TemplateParams, ParamIdx, ArgIdx,
+ Pattern.getUnqualifiedType(), Args[ArgIdx].getUnqualifiedType(),
+ Info, Deduced, PartialOrdering);
Result != TemplateDeductionResult::Success)
return Result;
-
PackScope.nextPackElement();
}
} else {
@@ -1307,6 +1304,68 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams,
return TemplateDeductionResult::Success;
}
+/// Deduce the template arguments by comparing the list of parameter
+/// types to the list of argument types, as in the parameter-type-lists of
+/// function types (C++ [temp.deduct.type]p10).
+///
+/// \param S The semantic analysis object within which we are deducing
+///
+/// \param TemplateParams The template parameters that we are deducing
+///
+/// \param Params The list of parameter types
+///
+/// \param NumParams The number of types in \c Params
+///
+/// \param Args The list of argument types
+///
+/// \param NumArgs The number of types in \c Args
+///
+/// \param Info information about the template argument deduction itself
+///
+/// \param Deduced the deduced template arguments
+///
+/// \param TDF bitwise OR of the TemplateDeductionFlags bits that describe
+/// how template argument deduction is performed.
+///
+/// \param PartialOrdering If true, we are performing template argument
+/// deduction for during partial ordering for a call
+/// (C++0x [temp.deduct.partial]).
+///
+/// \param HasDeducedAnyParam If set, the object pointed at will indicate
+/// whether any template parameter was deduced.
+///
+/// \param HasDeducedParam If set, the bit vector will be used to represent
+/// which template parameters were deduced, in order.
+///
+/// \returns the result of template argument deduction so far. Note that a
+/// "success" result means that template argument deduction has not yet failed,
+/// but it may still fail, later, for other reasons.
+static TemplateDeductionResult DeduceTemplateArguments(
+ Sema &S, TemplateParameterList *TemplateParams, const QualType *Params,
+ unsigned NumParams, const QualType *Args, unsigned NumArgs,
+ TemplateDeductionInfo &Info,
+ SmallVectorImpl<DeducedTemplateArgument> &Deduced, unsigned TDF,
+ bool PartialOrdering, bool *HasDeducedAnyParam,
+ llvm::SmallBitVector *HasDeducedParam) {
+ return ::DeduceForEachType(
+ S, TemplateParams, Params, NumParams, Args, NumArgs, Info, Deduced,
+ PartialOrdering, /*FinishingDeduction=*/false,
+ [&](Sema &S, TemplateParameterList *TemplateParams, int ParamIdx,
+ int ArgIdx, QualType P, QualType A, TemplateDeductionInfo &Info,
+ SmallVectorImpl<DeducedTemplateArgument> &Deduced,
+ bool PartialOrdering) {
+ bool HasDeducedAnyParamCopy = false;
+ TemplateDeductionResult TDR = DeduceTemplateArgumentsByTypeMatch(
+ S, TemplateParams, P, A, Info, Deduced, TDF, PartialOrdering,
+ /*DeducedFromArrayBound=*/false, &HasDeducedAnyParamCopy);
+ if (HasDeducedAnyParam && HasDeducedAnyParamCopy)
+ *HasDeducedAnyParam = true;
+ if (HasDeducedParam && HasDeducedAnyParamCopy)
+ (*HasDeducedParam)[ParamIdx] = true;
+ return TDR;
+ });
+}
+
/// Determine whether the parameter has qualifiers that the argument
/// lacks. Put another way, determine whether there is no way to add
/// a deduced set of qualifiers to the ParamType that would result in
@@ -1402,7 +1461,8 @@ static TemplateDeductionResult
DeduceTemplateBases(Sema &S, const CXXRecordDecl *RD,
TemplateParameterList *TemplateParams, QualType P,
TemplateDeductionInfo &Info,
- SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
+ SmallVectorImpl<DeducedTemplateArgument> &Deduced,
+ bool *HasDeducedAnyParam) {
// C++14 [temp.deduct.call] p4b3:
// If P is a class and P has the form simple-template-id, then the
// transformed A can be a derived class of the deduced A. Likewise if
@@ -1426,9 +1486,11 @@ DeduceTemplateBases(Sema &S, const CXXRecordDecl *RD,
SmallVector<QualType, 8> ToVisit;
// We iterate over this later, so we have to use MapVector to ensure
// determinism.
- llvm::MapVector<const CXXRecordDecl *,
- SmallVector<DeducedTemplateArgument, 8>>
- Matches;
+ struct MatchValue {
+ SmallVector<DeducedTemplateArgument, 8> Deduced;
+ bool HasDeducedAnyParam;
+ };
+ llvm::MapVector<const CXXRecordDecl *, MatchValue> Matches;
auto AddBases = [&Visited, &ToVisit](const CXXRecordDecl *RD) {
for (const auto &Base : RD->bases()) {
@@ -1450,14 +1512,16 @@ DeduceTemplateBases(Sema &S, const CXXRecordDecl *RD,
SmallVector<DeducedTemplateArgument, 8> DeducedCopy(Deduced.begin(),
Deduced.end());
TemplateDeductionInfo BaseInfo(TemplateDeductionInfo::ForBase, Info);
- TemplateDeductionResult BaseResult = DeduceTemplateSpecArguments(
- S, TemplateParams, P, NextT, BaseInfo, DeducedCopy);
+ bool HasDeducedAnyParamCopy = false;
+ TemplateDeductionResult BaseResult =
+ DeduceTemplateSpecArguments(S, TemplateParams, P, NextT, BaseInfo,
+ DeducedCopy, &HasDeducedAnyParamCopy);
// If this was a successful deduction, add it to the list of matches,
// otherwise we need to continue searching its bases.
const CXXRecordDecl *RD = NextT->getAsCXXRecordDecl();
if (BaseResult == TemplateDeductionResult::Success)
- Matches.insert({RD, DeducedCopy});
+ Matches.insert({RD, {DeducedCopy, HasDeducedAnyParamCopy}});
else
AddBases(RD);
}
@@ -1490,7 +1554,10 @@ DeduceTemplateBases(Sema &S, const CXXRecordDecl *RD,
if (Matches.size() > 1)
return TemplateDeductionResult::MiscellaneousDeductionFailure;
- std::swap(Matches.front().second, Deduced);
+ std::swap(Matches.front().second.Deduced, Deduced);
+ if (bool HasDeducedAnyParamCopy = Matches.front().second.HasDeducedAnyParam;
+ HasDeducedAnyParamCopy && HasDeducedAnyParam)
+ *HasDeducedAnyParam = HasDeducedAnyParamCopy;
return TemplateDeductionResult::Success;
}
@@ -1522,7 +1589,8 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
Sema &S, TemplateParameterList *TemplateParams, QualType P, QualType A,
TemplateDeductionInfo &Info,
SmallVectorImpl<DeducedTemplateArgument> &Deduced, unsigned TDF,
- bool PartialOrdering, bool DeducedFromArrayBound) {
+ bool PartialOrdering, bool DeducedFromArrayBound,
+ bool *HasDeducedAnyParam) {
// If the argument type is a pack expansion, look at its pattern.
// This isn't explicitly called out
@@ -1704,6 +1772,8 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
}
Deduced[Index] = Result;
+ if (HasDeducedAnyParam)
+ *HasDeducedAnyParam = true;
return TemplateDeductionResult::Success;
}
@@ -1802,7 +1872,8 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
return TemplateDeductionResult::NonDeducedMismatch;
return DeduceTemplateArgumentsByTypeMatch(
S, TemplateParams, CP->getElementType(), CA->getElementType(), Info,
- Deduced, TDF);
+ Deduced, TDF, /*PartialOrdering=*/false,
+ /*DeducedFromArrayBound=*/false, HasDeducedAnyParam);
}
// _Atomic T [extension]
@@ -1812,7 +1883,8 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
return TemplateDeductionResult::NonDeducedMismatch;
return DeduceTemplateArgumentsByTypeMatch(
S, TemplateParams, PA->getValueType(), AA->getValueType(), Info,
- Deduced, TDF);
+ Deduced, TDF, /*PartialOrdering=*/false,
+ /*DeducedFromArrayBound=*/false, HasDeducedAnyParam);
}
// T *
@@ -1828,7 +1900,9 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
return DeduceTemplateArgumentsByTypeMatch(
S, TemplateParams, P->castAs<PointerType>()->getPointeeType(),
PointeeType, Info, Deduced,
- TDF & (TDF_IgnoreQualifiers | TDF_DerivedClass));
+ TDF & (TDF_IgnoreQualifiers | TDF_DerivedClass),
+ /*PartialOrdering=*/false, /*DeducedFromArrayBound=*/false,
+ HasDeducedAnyParam);
}
// T &
@@ -1840,7 +1914,8 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
return DeduceTemplateArgumentsByTypeMatch(
S, TemplateParams, RP->getPointeeType(), RA->getPointeeType(), Info,
- Deduced, 0);
+ Deduced, 0, /*PartialOrdering=*/false,
+ /*DeducedFromArrayBound=*/false, HasDeducedAnyParam);
}
// T && [C++0x]
@@ -1852,7 +1927,8 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
return DeduceTemplateArgumentsByTypeMatch(
S, TemplateParams, RP->getPointeeType(), RA->getPointeeType(), Info,
- Deduced, 0);
+ Deduced, 0, /*PartialOrdering=*/false,
+ /*DeducedFromArrayBound=*/false, HasDeducedAnyParam);
}
// T [] (implied, but not stated explicitly)
@@ -1866,7 +1942,8 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
return DeduceTemplateArgumentsByTypeMatch(
S, TemplateParams, IAP->getElementType(), IAA->getElementType(), Info,
- Deduced, TDF & TDF_IgnoreQualifiers);
+ Deduced, TDF & TDF_IgnoreQualifiers, /*PartialOrdering=*/false,
+ /*DeducedFromArrayBound=*/false, HasDeducedAnyParam);
}
// T [integer-constant]
@@ -1879,7 +1956,8 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
return DeduceTemplateArgumentsByTypeMatch(
S, TemplateParams, CAP->getElementType(), CAA->getElementType(), Info,
- Deduced, TDF & TDF_IgnoreQualifiers);
+ Deduced, TDF & TDF_IgnoreQualifiers, /*PartialOrdering=*/false,
+ /*DeducedFromArrayBound=*/false, HasDeducedAnyParam);
}
// type [i]
@@ -1893,7 +1971,9 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
assert(DAP);
if (auto Result = DeduceTemplateArgumentsByTypeMatch(
S, TemplateParams, DAP->getElementType(), AA->getElementType(),
- Info, Deduced, TDF & TDF_IgnoreQualifiers);
+ Info, Deduced, TDF & TDF_IgnoreQualifiers,
+ /*PartialOrdering=*/false,
+ /*DeducedFromArrayBound=*/false, HasDeducedAnyParam);
Result != TemplateDeductionResult::Success)
return Result;
@@ -1911,12 +1991,13 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
llvm::APSInt Size(CAA->getSize());
return DeduceNonTypeTemplateArgument(
S, TemplateParams, NTTP, Size, S.Context.getSizeType(),
- /*ArrayBound=*/true, Info, Deduced);
+ /*ArrayBound=*/true, Info, Deduced, HasDeducedAnyParam);
}
if (const auto *DAA = dyn_cast<DependentSizedArrayType>(AA))
if (DAA->getSizeExpr())
- return DeduceNonTypeTemplateArgument(
- S, TemplateParams, NTTP, DAA->getSizeExpr(), Info, Deduced);
+ return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP,
+ DAA->getSizeExpr(), Info,
+ Deduced, HasDeducedAnyParam);
// Incomplete type does not match a dependently-sized array type
return TemplateDeductionResult::NonDeducedMismatch;
@@ -1941,7 +2022,7 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
S, TemplateParams, FPP->getReturnType(), FPA->getReturnType(),
Info, Deduced, 0,
/*PartialOrdering=*/false,
- /*DeducedFromArrayBound=*/false);
+ /*DeducedFromArrayBound=*/false, HasDeducedAnyParam);
Result != TemplateDeductionResult::Success)
return Result;
@@ -1949,7 +2030,8 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
if (auto Result = DeduceTemplateArguments(
S, TemplateParams, FPP->param_type_begin(), FPP->getNumParams(),
FPA->param_type_begin(), FPA->getNumParams(), Info, Deduced,
- TDF & TDF_TopLevelParameterTypeList, PartialOrdering);
+ TDF & TDF_TopLevelParameterTypeList, PartialOrdering,
+ HasDeducedAnyParam, /*HasDeducedParam=*/nullptr);
Result != TemplateDeductionResult::Success)
return Result;
@@ -1977,12 +2059,14 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
// FIXME: Should we?
return DeduceNonTypeTemplateArgument(
S, TemplateParams, NTTP, Noexcept, S.Context.BoolTy,
- /*DeducedFromArrayBound=*/true, Info, Deduced);
+ /*DeducedFromArrayBound=*/true, Info, Deduced,
+ HasDeducedAnyParam);
case CT_Dependent:
if (Expr *ArgNoexceptExpr = FPA->getNoexceptExpr())
- return DeduceNonTypeTemplateArgument(
- S, TemplateParams, NTTP, ArgNoexceptExpr, Info, Deduced);
+ return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP,
+ ArgNoexceptExpr, Info, Deduced,
+ HasDeducedAnyParam);
// Can't deduce anything from throw(T...).
break;
}
@@ -2009,13 +2093,13 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
// arguments from the template-id.
if (!(TDF & TDF_DerivedClass) || !A->isRecordType())
return DeduceTemplateSpecArguments(S, TemplateParams, P, A, Info,
- Deduced);
+ Deduced, HasDeducedAnyParam);
SmallVector<DeducedTemplateArgument, 8> DeducedOrig(Deduced.begin(),
Deduced.end());
- auto Result =
- DeduceTemplateSpecArguments(S, TemplateParams, P, A, Info, Deduced);
+ auto Result = DeduceTemplateSpecArguments(S, TemplateParams, P, A, Info,
+ Deduced, HasDeducedAnyParam);
if (Result == TemplateDeductionResult::Success)
return Result;
@@ -2033,8 +2117,8 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
Deduced = DeducedOrig;
// Check bases according to C++14 [temp.deduct.call] p4b3:
- auto BaseResult =
- DeduceTemplateBases(S, RD, TemplateParams, P, Info, Deduced);
+ auto BaseResult = DeduceTemplateBases(S, RD, TemplateParams, P, Info,
+ Deduced, HasDeducedAnyParam);
return BaseResult != TemplateDeductionResult::Invalid ? BaseResult
: Result;
}
@@ -2065,12 +2149,16 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
unsigned SubTDF = TDF & TDF_IgnoreQualifiers;
if (auto Result = DeduceTemplateArgumentsByTypeMatch(
- S, TemplateParams, PPT, APT, Info, Deduced, SubTDF);
+ S, TemplateParams, PPT, APT, Info, Deduced, SubTDF,
+ /*PartialOrdering=*/false, /*DeducedFromArrayBound=*/false,
+ HasDeducedAnyParam);
Result != TemplateDeductionResult::Success)
return Result;
return DeduceTemplateArgumentsByTypeMatch(
S, TemplateParams, QualType(MPP->getClass(), 0),
- QualType(MPA->getClass(), 0), Info, Deduced, SubTDF);
+ QualType(MPA->getClass(), 0), Info, Deduced, SubTDF,
+ /*PartialOrdering=*/false, /*DeducedFromArrayBound=*/false,
+ HasDeducedAnyParam);
}
// (clang extension)
@@ -2085,7 +2173,8 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
return TemplateDeductionResult::NonDeducedMismatch;
return DeduceTemplateArgumentsByTypeMatch(
S, TemplateParams, BPP->getPointeeType(), BPA->getPointeeType(), Info,
- Deduced, 0);
+ Deduced, 0, /*PartialOrdering=*/false,
+ /*DeducedFromArrayBound=*/false, HasDeducedAnyParam);
}
// (clang extension)
@@ -2110,7 +2199,8 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
// Perform deduction on the element types.
return DeduceTemplateArgumentsByTypeMatch(
S, TemplateParams, VP->getElementType(), ElementType, Info, Deduced,
- TDF);
+ TDF, /*PartialOrdering=*/false, /*DeducedFromArrayBound=*/false,
+ HasDeducedAnyParam);
}
case Type::DependentVector: {
@@ -2120,7 +2210,8 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
// Perform deduction on the element types.
if (auto Result = DeduceTemplateArgumentsByTypeMatch(
S, TemplateParams, VP->getElementType(), VA->getElementType(),
- Info, Deduced, TDF);
+ Info, Deduced, TDF, /*PartialOrdering=*/false,
+ /*DeducedFromArrayBound=*/false, HasDeducedAnyParam);
Result != TemplateDeductionResult::Success)
return Result;
@@ -2137,14 +2228,15 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
// we can provide one if necessary.
return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP, ArgSize,
S.Context.UnsignedIntTy, true,
- Info, Deduced);
+ Info, Deduced, HasDeducedAnyParam);
}
if (const auto *VA = A->getAs<DependentVectorType>()) {
// Perform deduction on the element types.
if (auto Result = DeduceTemplateArgumentsByTypeMatch(
S, TemplateParams, VP->getElementType(), VA->getElementType(),
- Info, Deduced, TDF);
+ Info, Deduced, TDF, /*PartialOrdering=*/false,
+ /*DeducedFromArrayBound=*/false, HasDeducedAnyParam);
Result != TemplateDeductionResult::Success)
return Result;
@@ -2155,7 +2247,8 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
return TemplateDeductionResult::Success;
return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP,
- VA->getSizeExpr(), Info, Deduced);
+ VA->getSizeExpr(), Info, Deduced,
+ HasDeducedAnyParam);
}
return TemplateDeductionResult::NonDeducedMismatch;
@@ -2171,7 +2264,8 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
// Perform deduction on the element types.
if (auto Result = DeduceTemplateArgumentsByTypeMatch(
S, TemplateParams, VP->getElementType(), VA->getElementType(),
- Info, Deduced, TDF);
+ Info, Deduced, TDF, /*PartialOrdering=*/false,
+ /*DeducedFromArrayBound=*/false, HasDeducedAnyParam);
Result != TemplateDeductionResult::Success)
return Result;
@@ -2188,14 +2282,15 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
// we can provide one if necessary.
return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP, ArgSize,
S.Context.IntTy, true, Info,
- Deduced);
+ Deduced, HasDeducedAnyParam);
}
if (const auto *VA = A->getAs<DependentSizedExtVectorType>()) {
// Perform deduction on the element types.
if (auto Result = DeduceTemplateArgumentsByTypeMatch(
S, TemplateParams, VP->getElementType(), VA->getElementType(),
- Info, Deduced, TDF);
+ Info, Deduced, TDF, /*PartialOrdering=*/false,
+ /*DeducedFromArrayBound=*/false, HasDeducedAnyParam);
Result != TemplateDeductionResult::Success)
return Result;
@@ -2206,7 +2301,8 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
return TemplateDeductionResult::Success;
return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP,
- VA->getSizeExpr(), Info, Deduced);
+ VA->getSizeExpr(), Info, Deduced,
+ HasDeducedAnyParam);
}
return TemplateDeductionResult::NonDeducedMismatch;
@@ -2230,7 +2326,8 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
// Perform deduction on element types.
return DeduceTemplateArgumentsByTypeMatch(
S, TemplateParams, MP->getElementType(), MA->getElementType(), Info,
- Deduced, TDF);
+ Deduced, TDF, /*PartialOrdering=*/false,
+ /*DeducedFromArrayBound=*/false, HasDeducedAnyParam);
}
case Type::DependentSizedMatrix: {
@@ -2242,13 +2339,14 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
// Check the element type of the matrixes.
if (auto Result = DeduceTemplateArgumentsByTypeMatch(
S, TemplateParams, MP->getElementType(), MA->getElementType(),
- Info, Deduced, TDF);
+ Info, Deduced, TDF, /*PartialOrdering=*/false,
+ /*DeducedFromArrayBound=*/false, HasDeducedAnyParam);
Result != TemplateDeductionResult::Success)
return Result;
// Try to deduce a matrix dimension.
auto DeduceMatrixArg =
- [&S, &Info, &Deduced, &TemplateParams](
+ [&S, &Info, &Deduced, &TemplateParams, &HasDeducedAnyParam](
Expr *ParamExpr, const MatrixType *A,
unsigned (ConstantMatrixType::*GetArgDimension)() const,
Expr *(DependentSizedMatrixType::*GetArgDimensionExpr)() const) {
@@ -2285,12 +2383,12 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
ArgConst = (ACM->*GetArgDimension)();
return DeduceNonTypeTemplateArgument(
S, TemplateParams, NTTP, ArgConst, S.Context.getSizeType(),
- /*ArrayBound=*/true, Info, Deduced);
+ /*ArrayBound=*/true, Info, Deduced, HasDeducedAnyParam);
}
- return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP,
- (ADM->*GetArgDimensionExpr)(),
- Info, Deduced);
+ return DeduceNonTypeTemplateArgument(
+ S, TemplateParams, NTTP, (ADM->*GetArgDimensionExpr)(), Info,
+ Deduced, HasDeducedAnyParam);
};
if (auto Result = DeduceMatrixArg(MP->getRowExpr(), MA,
@@ -2314,7 +2412,8 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
// Perform deduction on the pointer type.
if (auto Result = DeduceTemplateArgumentsByTypeMatch(
S, TemplateParams, ASP->getPointeeType(), ASA->getPointeeType(),
- Info, Deduced, TDF);
+ Info, Deduced, TDF, /*PartialOrdering=*/false,
+ /*DeducedFromArrayBound=*/false, HasDeducedAnyParam);
Result != TemplateDeductionResult::Success)
return Result;
@@ -2324,8 +2423,9 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
if (!NTTP)
return TemplateDeductionResult::Success;
- return DeduceNonTypeTemplateArgument(
- S, TemplateParams, NTTP, ASA->getAddrSpaceExpr(), Info, Deduced);
+ return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP,
+ ASA->getAddrSpaceExpr(), Info,
+ Deduced, HasDeducedAnyParam);
}
if (isTargetAddressSpace(A.getAddressSpace())) {
@@ -2336,7 +2436,9 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
// Perform deduction on the pointer types.
if (auto Result = DeduceTemplateArgumentsByTypeMatch(
S, TemplateParams, ASP->getPointeeType(),
- S.Context.removeAddrSpaceQualType(A), Info, Deduced, TDF);
+ S.Context.removeAddrSpaceQualType(A), Info, Deduced, TDF,
+ /*PartialOrdering=*/false, /*DeducedFromArrayBound=*/false,
+ HasDeducedAnyParam);
Result != TemplateDeductionResult::Success)
return Result;
@@ -2346,9 +2448,9 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
if (!NTTP)
return TemplateDeductionResult::Success;
- return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP,
- ArgAddressSpace, S.Context.IntTy,
- true, Info, Deduced);
+ return DeduceNonTypeTemplateArgument(
+ S, TemplateParams, NTTP, ArgAddressSpace, S.Context.IntTy, true,
+ Info, Deduced, HasDeducedAnyParam);
}
return TemplateDeductionResult::NonDeducedMismatch;
@@ -2370,7 +2472,7 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP, ArgSize,
S.Context.IntTy, true, Info,
- Deduced);
+ Deduced, HasDeducedAnyParam);
}
if (const auto *IA = A->getAs<DependentBitIntType>()) {
@@ -2400,7 +2502,9 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
const PackIndexingType *PIT = P->getAs<PackIndexingType>();
if (PIT->hasSelectedType()) {
return DeduceTemplateArgumentsByTypeMatch(
- S, TemplateParams, PIT->getSelectedType(), A, Info, Deduced, TDF);
+ S, TemplateParams, PIT->getSelectedType(), A, Info, Deduced, TDF,
+ /*PartialOrdering=*/false, /*DeducedFromArrayBound=*/false,
+ HasDeducedAnyParam);
}
return TemplateDeductionResult::IncompletePack;
}
@@ -2413,7 +2517,8 @@ static TemplateDeductionResult
DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams,
const TemplateArgument &P, TemplateArgument A,
TemplateDeductionInfo &Info,
- SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
+ SmallVectorImpl<DeducedTemplateArgument> &Deduced,
+ bool *HasDeducedAnyParam) {
// If the template argument is a pack expansion, perform template argument
// deduction against the pattern of that expansion. This only occurs during
// partial ordering.
@@ -2427,16 +2532,18 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams,
case TemplateArgument::Type:
if (A.getKind() == TemplateArgument::Type)
return DeduceTemplateArgumentsByTypeMatch(
- S, TemplateParams, P.getAsType(), A.getAsType(), Info, Deduced, 0);
+ S, TemplateParams, P.getAsType(), A.getAsType(), Info, Deduced, 0,
+ /*PartialOrdering=*/false, /*DeducedFromArrayBound=*/false,
+ HasDeducedAnyParam);
Info.FirstArg = P;
Info.SecondArg = A;
return TemplateDeductionResult::NonDeducedMismatch;
case TemplateArgument::Template:
if (A.getKind() == TemplateArgument::Template)
- return DeduceTemplateArguments(S, TemplateParams, P.getAsTemplate(),
- A.getAsTemplate(), Info,
- /*DefaultArguments=*/{}, Deduced);
+ return DeduceTemplateArguments(
+ S, TemplateParams, P.getAsTemplate(), A.getAsTemplate(), Info,
+ /*DefaultArguments=*/{}, Deduced, HasDeducedAnyParam);
Info.FirstArg = P;
Info.SecondArg = A;
return TemplateDeductionResult::NonDeducedMismatch;
@@ -2487,18 +2594,20 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams,
case TemplateArgument::Integral:
case TemplateArgument::Expression:
case TemplateArgument::StructuralValue:
- return DeduceNonTypeTemplateArgument(
- S, TemplateParams, NTTP, DeducedTemplateArgument(A),
- A.getNonTypeTemplateArgumentType(), Info, Deduced);
+ return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP,
+ DeducedTemplateArgument(A),
+ A.getNonTypeTemplateArgumentType(),
+ Info, Deduced, HasDeducedAnyParam);
case TemplateArgument::NullPtr:
return DeduceNullPtrTemplateArgument(S, TemplateParams, NTTP,
- A.getNullPtrType(), Info, Deduced);
+ A.getNullPtrType(), Info, Deduced,
+ HasDeducedAnyParam);
case TemplateArgument::Declaration:
return DeduceNonTypeTemplateArgument(
S, TemplateParams, NTTP, A.getAsDecl(), A.getParamTypeForDecl(),
- Info, Deduced);
+ Info, Deduced, HasDeducedAnyParam);
case TemplateArgument::Null:
case TemplateArgument::Type:
@@ -2570,7 +2679,8 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams,
ArrayRef<TemplateArgument> As,
TemplateDeductionInfo &Info,
SmallVectorImpl<DeducedTemplateArgument> &Deduced,
- bool NumberOfArgumentsMustMatch, PackFold PackFold) {
+ bool NumberOfArgumentsMustMatch, PackFold PackFold,
+ bool *HasDeducedAnyParam) {
if (PackFold == PackFold::ArgumentToParameter)
std::swap(Ps, As);
// C++0x [temp.deduct.type]p9:
@@ -2606,8 +2716,8 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams,
TemplateArgument Pi = P, Ai = As[ArgIdx];
if (PackFold == PackFold::ArgumentToParameter)
std::swap(Pi, Ai);
- if (auto Result =
- DeduceTemplateArguments(S, TemplateParams, Pi, Ai, Info, Deduced);
+ if (auto Result = DeduceTemplateArguments(S, TemplateParams, Pi, Ai, Info,
+ Deduced, HasDeducedAnyParam);
Result != TemplateDeductionResult::Success)
return Result;
@@ -2638,8 +2748,8 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams,
if (PackFold == PackFold::ArgumentToParameter)
std::swap(Pi, Ai);
// Deduce template arguments from the pattern.
- if (auto Result =
- DeduceTemplateArguments(S, TemplateParams, Pi, Ai, Info, Deduced);
+ if (auto Result = DeduceTemplateArguments(S, TemplateParams, Pi, Ai, Info,
+ Deduced, HasDeducedAnyParam);
Result != TemplateDeductionResult::Success)
return Result;
@@ -2661,8 +2771,9 @@ TemplateDeductionResult Sema::DeduceTemplateArguments(
ArrayRef<TemplateArgument> As, sema::TemplateDeductionInfo &Info,
SmallVectorImpl<DeducedTemplateArgument> &Deduced,
bool NumberOfArgumentsMustMatch) {
- return ::DeduceTemplateArguments(*this, TemplateParams, Ps, As, Info, Deduced,
- NumberOfArgumentsMustMatch);
+ return ::DeduceTemplateArguments(
+ *this, TemplateParams, Ps, As, Info, Deduced, NumberOfArgumentsMustMatch,
+ PackFold::ParameterToArgument, /*HasDeducedAnyParam=*/nullptr);
}
/// Determine whether two template arguments are the same.
@@ -2912,6 +3023,10 @@ static bool ConvertDeducedTemplateArgument(
// FIXME: This should not be a template, but
// ClassTemplatePartialSpecializationDecl sadly does not derive from
// TemplateDecl.
+/// \param IsIncomplete When used, we only consider template parameters that
+/// were deduced, disregarding any default arguments. After the function
+/// finishes, the object pointed at will contain a value indicating if the
+/// conversion was actually incomplete.
template <typename TemplateDeclT>
static TemplateDeductionResult ConvertDeducedTemplateArguments(
Sema &S, TemplateDeclT *Template, bool IsDeduced,
@@ -2920,7 +3035,7 @@ static TemplateDeductionResult ConvertDeducedTemplateArguments(
SmallVectorImpl<TemplateArgument> &SugaredBuilder,
SmallVectorImpl<TemplateArgument> &CanonicalBuilder,
LocalInstantiationScope *CurrentInstantiationScope = nullptr,
- unsigned NumAlreadyConverted = 0, bool PartialOverloading = false) {
+ unsigned NumAlreadyConverted = 0, bool *IsIncomplete = nullptr) {
TemplateParameterList *TemplateParams = Template->getTemplateParameters();
for (unsigned I = 0, N = TemplateParams->size(); I != N; ++I) {
@@ -2976,6 +3091,17 @@ static TemplateDeductionResult ConvertDeducedTemplateArguments(
continue;
}
+ // [temp.deduct.partial]p12 - When partial ordering, it's ok for template
+ // parameters to remain not deduced. As a provisional fix for a core issue
+ // that does not exist yet, only consider template parameters that were
+ // deduced, disregarding any default arguments.
+ if (IsIncomplete) {
+ *IsIncomplete = true;
+ SugaredBuilder.push_back({});
+ CanonicalBuilder.push_back({});
+ continue;
+ }
+
// Substitute into the default template argument, if available.
bool HasDefaultArg = false;
TemplateDecl *TD = dyn_cast<TemplateDecl>(Template);
@@ -3010,7 +3136,6 @@ static TemplateDeductionResult ConvertDeducedTemplateArguments(
const_cast<NamedDecl *>(TemplateParams->getParam(I)));
Info.reset(TemplateArgumentList::CreateCopy(S.Context, SugaredBuilder),
TemplateArgumentList::CreateCopy(S.Context, CanonicalBuilder));
- if (PartialOverloading) break;
return HasDefaultArg ? TemplateDeductionResult::SubstitutionFailure
: TemplateDeductionResult::Incomplete;
@@ -3225,7 +3350,7 @@ static TemplateDeductionResult FinishTemplateArgumentDeduction(
S, Template, /*IsDeduced*/ PartialOrdering, Deduced, Info,
SugaredBuilder, CanonicalBuilder,
/*CurrentInstantiationScope=*/nullptr,
- /*NumAlreadyConverted=*/0U, /*PartialOverloading=*/false);
+ /*NumAlreadyConverted=*/0U);
Result != TemplateDeductionResult::Success)
return Result;
@@ -3319,7 +3444,8 @@ DeduceTemplateArguments(Sema &S, T *Partial,
if (TemplateDeductionResult Result = ::DeduceTemplateArguments(
S, Partial->getTemplateParameters(),
Partial->getTemplateArgs().asArray(), TemplateArgs, Info, Deduced,
- /*NumberOfArgumentsMustMatch=*/false);
+ /*NumberOfArgumentsMustMatch=*/false, PackFold::ParameterToArgument,
+ /*HasDeducedAnyParam=*/nullptr);
Result != TemplateDeductionResult::Success)
return Result;
@@ -3827,11 +3953,12 @@ TemplateDeductionResult Sema::FinishTemplateArgumentDeduction(
// C++ [temp.deduct.type]p2:
// [...] or if any template argument remains neither deduced nor
// explicitly specified, template argument deduction fails.
+ bool IsIncomplete = false;
SmallVector<TemplateArgument, 4> SugaredBuilder, CanonicalBuilder;
if (auto Result = ConvertDeducedTemplateArguments(
*this, FunctionTemplate, /*IsDeduced*/ true, Deduced, Info,
SugaredBuilder, CanonicalBuilder, CurrentInstantiationScope,
- NumExplicitlySpecified, PartialOverloading);
+ NumExplicitlySpecified, PartialOverloading ? &IsIncomplete : nullptr);
Result != TemplateDeductionResult::Success)
return Result;
@@ -3910,9 +4037,7 @@ TemplateDeductionResult Sema::FinishTemplateArgumentDeduction(
// ([temp.constr.decl]), those constraints are checked for satisfaction
// ([temp.constr.constr]). If the constraints are not satisfied, type
// deduction fails.
- if (!PartialOverloading ||
- (CanonicalBuilder.size() ==
- FunctionTemplate->getTemplateParameters()->size())) {
+ if (!IsIncomplete) {
if (CheckInstantiatedFunctionTemplateConstraints(
Info.getLocation(), Specialization, CanonicalBuilder,
Info.AssociatedConstraintsSatisfaction))
@@ -4122,7 +4247,9 @@ ResolveOverloadForDeduction(Sema &S, TemplateParameterList *TemplateParams,
Deduced(TemplateParams->size());
TemplateDeductionInfo Info(Ovl->getNameLoc());
TemplateDeductionResult Result = DeduceTemplateArgumentsByTypeMatch(
- S, TemplateParams, ParamType, ArgType, Info, Deduced, TDF);
+ S, TemplateParams, ParamType, ArgType, Info, Deduced, TDF,
+ /*PartialOrdering=*/false, /*DeducedFromArrayBound=*/false,
+ /*HasDeducedAnyParam=*/nullptr);
if (Result != TemplateDeductionResult::Success)
continue;
if (!Match.isNull())
@@ -4308,7 +4435,8 @@ static TemplateDeductionResult DeduceFromInitializerList(
llvm::APInt Size(S.Context.getIntWidth(T), ILE->getNumInits());
if (auto Result = DeduceNonTypeTemplateArgument(
S, TemplateParams, NTTP, llvm::APSInt(Size), T,
- /*ArrayBound=*/true, Info, Deduced);
+ /*ArrayBound=*/true, Info, Deduced,
+ /*HasDeducedAnyParam=*/nullptr);
Result != TemplateDeductionResult::Success)
return Result;
}
@@ -4351,8 +4479,10 @@ static TemplateDeductionResult DeduceTemplateArgumentsFromCallArgument(
if (Arg)
OriginalCallArgs.push_back(
Sema::OriginalCallArg(OrigParamType, DecomposedParam, ArgIdx, ArgType));
- return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, ParamType,
- ArgType, Info, Deduced, TDF);
+ return DeduceTemplateArgumentsByTypeMatch(
+ S, TemplateParams, ParamType, ArgType, Info, Deduced, TDF,
+ /*PartialOrdering=*/false, /*DeducedFromArrayBound=*/false,
+ /*HasDeducedAnyParam=*/nullptr);
}
TemplateDeductionResult Sema::DeduceTemplateArguments(
@@ -4679,7 +4809,8 @@ TemplateDeductionResult Sema::DeduceTemplateArguments(
// Deduce template arguments from the function type.
if (TemplateDeductionResult Result = DeduceTemplateArgumentsByTypeMatch(
*this, TemplateParams, FunctionType, ArgFunctionType, Info, Deduced,
- TDF);
+ TDF, /*PartialOrdering=*/false, /*DeducedFromArrayBound=*/false,
+ /*HasDeducedAnyParam=*/nullptr);
Result != TemplateDeductionResult::Success)
return Result;
}
@@ -4856,7 +4987,9 @@ TemplateDeductionResult Sema::DeduceTemplateArguments(
}
if (TemplateDeductionResult Result = DeduceTemplateArgumentsByTypeMatch(
- *this, TemplateParams, P, A, Info, Deduced, TDF);
+ *this, TemplateParams, P, A, Info, Deduced, TDF,
+ /*PartialOrdering=*/false, /*DeducedFromArrayBound=*/false,
+ /*HasDeducedAnyParam=*/nullptr);
Result != TemplateDeductionResult::Success)
return Result;
@@ -5395,11 +5528,99 @@ static QualType GetImplicitObjectParameterType(ASTContext &Context,
return Context.getLValueReferenceType(RawType);
}
+static TemplateDeductionResult CheckDeductionConsistency(
+ Sema &S, FunctionTemplateDecl *FTD, int ArgIdx, QualType P, QualType A,
+ ArrayRef<TemplateArgument> DeducedArgs, bool CheckConsistency) {
+ MultiLevelTemplateArgumentList MLTAL(FTD, DeducedArgs,
+ /*Final=*/true);
+ if (ArgIdx != -1)
+ if (auto *MD = dyn_cast<CXXMethodDecl>(FTD->getTemplatedDecl());
+ MD && MD->isImplicitObjectMemberFunction())
+ ArgIdx -= 1;
+ Sema::ArgumentPackSubstitutionIndexRAII PackIndex(
+ S, ArgIdx != -1 ? ::getPackIndexForParam(S, FTD, MLTAL, ArgIdx) : -1);
+ bool IsIncompleteSubstitution = false;
+ QualType InstP = S.SubstType(P, MLTAL, FTD->getLocation(), FTD->getDeclName(),
+ &IsIncompleteSubstitution);
+ if (InstP.isNull())
+ return TemplateDeductionResult::SubstitutionFailure;
+ if (!CheckConsistency)
+ return TemplateDeductionResult::Success;
+ if (IsIncompleteSubstitution)
+ return TemplateDeductionResult::Incomplete;
+
+ // [temp.deduct.call]/4 - Check we produced a consistent deduction.
+ // This handles just the cases that can appear when partial ordering.
+ if (auto *PA = dyn_cast<PackExpansionType>(A);
+ PA && !isa<PackExpansionType>(InstP))
+ A = PA->getPattern();
+ if (!S.Context.hasSameType(
+ S.Context.getUnqualifiedArrayType(InstP.getNonReferenceType()),
+ S.Context.getUnqualifiedArrayType(A.getNonReferenceType())))
+ return TemplateDeductionResult::NonDeducedMismatch;
+ return TemplateDeductionResult::Success;
+}
+
+template <class T>
+static TemplateDeductionResult FinishTemplateArgumentDeduction(
+ Sema &S, FunctionTemplateDecl *FTD,
+ SmallVectorImpl<DeducedTemplateArgument> &Deduced,
+ TemplateDeductionInfo &Info, T &&CheckDeductionConsistency) {
+ EnterExpressionEvaluationContext Unevaluated(
+ S, Sema::ExpressionEvaluationContext::Unevaluated);
+ Sema::SFINAETrap Trap(S);
+
+ Sema::ContextRAII SavedContext(S, getAsDeclContextOrEnclosing(FTD));
+
+ // C++26 [temp.deduct.type]p2:
+ // [...] or if any template argument remains neither deduced nor
+ // explicitly specified, template argument deduction fails.
+ bool IsIncomplete = false;
+ SmallVector<TemplateArgument, 4> SugaredBuilder, CanonicalBuilder;
+ if (auto Result = ConvertDeducedTemplateArguments(
+ S, FTD, /*IsDeduced=*/true, Deduced, Info, SugaredBuilder,
+ CanonicalBuilder, /*CurrentInstantiationScope=*/nullptr,
+ /*NumAlreadyConverted=*/0, &IsIncomplete);
+ Result != TemplateDeductionResult::Success)
+ return Result;
+
+ // Form the template argument list from the deduced template arguments.
+ TemplateArgumentList *SugaredDeducedArgumentList =
+ TemplateArgumentList::CreateCopy(S.Context, SugaredBuilder);
+ TemplateArgumentList *CanonicalDeducedArgumentList =
+ TemplateArgumentList::CreateCopy(S.Context, CanonicalBuilder);
+
+ Info.reset(SugaredDeducedArgumentList, CanonicalDeducedArgumentList);
+
+ // Substitute the deduced template arguments into the argument
+ // and verify that the instantiated argument is both valid
+ // and equivalent to the parameter.
+ LocalInstantiationScope InstScope(S);
+
+ if (auto TDR = CheckDeductionConsistency(S, FTD, SugaredBuilder);
+ TDR != TemplateDeductionResult::Success)
+ return TDR;
+
+ // C++20 [temp.deduct]p5 - Only check constraints when all parameters have
+ // been deduced.
+ if (!IsIncomplete) {
+ if (auto Result = CheckDeducedArgumentConstraints(S, FTD, SugaredBuilder,
+ CanonicalBuilder, Info);
+ Result != TemplateDeductionResult::Success)
+ return Result;
+ }
+
+ if (Trap.hasErrorOccurred())
+ return TemplateDeductionResult::SubstitutionFailure;
+
+ return TemplateDeductionResult::Success;
+}
+
/// Determine whether the function template \p FT1 is at least as
/// specialized as \p FT2.
static bool isAtLeastAsSpecializedAs(Sema &S, SourceLocation Loc,
- const FunctionTemplateDecl *FT1,
- const FunctionTemplateDecl *FT2,
+ FunctionTemplateDecl *FT1,
+ FunctionTemplateDecl *FT2,
TemplatePartialOrderingContext TPOC,
bool Reversed,
const SmallVector<QualType> &Args1,
@@ -5421,34 +5642,114 @@ static bool isAtLeastAsSpecializedAs(Sema &S, SourceLocation Loc,
// the partial ordering is done:
TemplateDeductionInfo Info(Loc);
switch (TPOC) {
- case TPOC_Call:
- if (DeduceTemplateArguments(S, TemplateParams, Args2.data(), Args2.size(),
- Args1.data(), Args1.size(), Info, Deduced,
- TDF_None, /*PartialOrdering=*/true) !=
- TemplateDeductionResult::Success)
+ case TPOC_Call: {
+ llvm::SmallBitVector HasDeducedParam(Args2.size());
+ if (DeduceTemplateArguments(
+ S, TemplateParams, Args2.data(), Args2.size(), Args1.data(),
+ Args1.size(), Info, Deduced, TDF_None, /*PartialOrdering=*/true,
+ /*HasDeducedAnyParam=*/nullptr,
+ &HasDeducedParam) != TemplateDeductionResult::Success)
return false;
- break;
+ SmallVector<TemplateArgument, 4> DeducedArgs(Deduced.begin(),
+ Deduced.end());
+ Sema::InstantiatingTemplate Inst(
+ S, Info.getLocation(), FT2, DeducedArgs,
+ Sema::CodeSynthesisContext::DeducedTemplateArgumentSubstitution, Info);
+ if (Inst.isInvalid())
+ return false;
+ bool AtLeastAsSpecialized = true;
+ S.runWithSufficientStackSpace(Info.getLocation(), [&] {
+ AtLeastAsSpecialized =
+ ::FinishTemplateArgumentDeduction(
+ S, FT2, Deduced, Info,
+ [&](Sema &S, FunctionTemplateDecl *FTD,
+ ArrayRef<TemplateArgument> DeducedArgs) {
+ return ::DeduceForEachType(
+ S, TemplateParams, Args2.data(), Args2.size(), Args1.data(),
+ Args1.size(), Info, Deduced,
+ /*PartialOrdering=*/true, /*FinishingDeduction=*/true,
+ [&](Sema &S, TemplateParameterList *, int ParamIdx,
+ int ArgIdx, QualType P, QualType A,
+ TemplateDeductionInfo &Info,
+ SmallVectorImpl<DeducedTemplateArgument> &Deduced,
+ bool) {
+ // As a provisional fix for a core issue that does not
+ // exist yet, only check the consistency of parameters
+ // which participated in deduction. We still try to
+ // substitute them though.
+ return ::CheckDeductionConsistency(
+ S, FTD, ArgIdx, P, A, DeducedArgs,
+ HasDeducedParam[ParamIdx]);
+ });
+ }) == TemplateDeductionResult::Success;
+ });
+ if (!AtLeastAsSpecialized)
+ return false;
+ } break;
case TPOC_Conversion:
+ case TPOC_Other: {
// - In the context of a call to a conversion operator, the return types
// of the conversion function templates are used.
- if (DeduceTemplateArgumentsByTypeMatch(
- S, TemplateParams, Proto2->getReturnType(), Proto1->getReturnType(),
- Info, Deduced, TDF_None,
- /*PartialOrdering=*/true) != TemplateDeductionResult::Success)
- return false;
- break;
-
- case TPOC_Other:
// - In other contexts (14.6.6.2) the function template's function type
// is used.
+ auto [A, P, TDF] = TPOC == TPOC_Other
+ ? std::make_tuple(FD1->getType(), FD2->getType(),
+ TDF_AllowCompatibleFunctionType)
+ : std::make_tuple(Proto1->getReturnType(),
+ Proto2->getReturnType(), TDF_None);
if (DeduceTemplateArgumentsByTypeMatch(
- S, TemplateParams, FD2->getType(), FD1->getType(), Info, Deduced,
- TDF_AllowCompatibleFunctionType,
- /*PartialOrdering=*/true) != TemplateDeductionResult::Success)
+ S, TemplateParams, P, A, Info, Deduced, TDF,
+ /*PartialOrdering=*/true, /*DeducedFromArrayBound=*/false,
+ /*HasDeducedAnyParam=*/nullptr) != TemplateDeductionResult::Success)
return false;
- break;
+
+ SmallVector<TemplateArgument, 4> DeducedArgs(Deduced.begin(),
+ Deduced.end());
+ Sema::InstantiatingTemplate Inst(
+ S, Info.getLocation(), FT2, DeducedArgs,
+ Sema::CodeSynthesisContext::DeducedTemplateArgumentSubstitution, Info);
+ if (Inst.isInvalid())
+ return false;
+
+ bool AtLeastAsSpecialized;
+ S.runWithSufficientStackSpace(Info.getLocation(), [&] {
+ AtLeastAsSpecialized =
+ ::FinishTemplateArgumentDeduction(
+ S, FT2, Deduced, Info,
+ [&](Sema &S, FunctionTemplateDecl *FTD,
+ ArrayRef<TemplateArgument> DeducedArgs) {
+ if (auto TDR = ::CheckDeductionConsistency(
+ S, FTD, /*ArgIdx=*/-1, Proto2->getReturnType(),
+ Proto1->getReturnType(), DeducedArgs,
+ /*CheckConsistency=*/true);
+ TDR != TemplateDeductionResult::Success)
+ return TDR;
+
+ if (TPOC != TPOC_Conversion)
+ return TemplateDeductionResult::Success;
+
+ return ::DeduceForEachType(
+ S, TemplateParams, Proto2->getParamTypes().data(),
+ Proto2->getParamTypes().size(),
+ Proto1->getParamTypes().data(),
+ Proto1->getParamTypes().size(), Info, Deduced,
+ /*PartialOrdering=*/true, /*FinishingDeduction=*/true,
+ [&](Sema &S, TemplateParameterList *, int ParamIdx,
+ int ArgIdx, QualType P, QualType A,
+ TemplateDeductionInfo &Info,
+ SmallVectorImpl<DeducedTemplateArgument> &Deduced,
+ bool) {
+ return ::CheckDeductionConsistency(
+ S, FTD, ArgIdx, P, A, DeducedArgs,
+ /*CheckConsistency=*/true);
+ });
+ }) == TemplateDeductionResult::Success;
+ });
+ if (!AtLeastAsSpecialized)
+ return false;
+ } break;
}
// C++0x [temp.deduct.partial]p11:
@@ -5462,10 +5763,6 @@ static bool isAtLeastAsSpecializedAs(Sema &S, SourceLocation Loc,
if (Deduced[ArgIdx].isNull())
break;
- // FIXME: We fail to implement [temp.deduct.type]p1 along this path. We need
- // to substitute the deduced arguments back into the template and check that
- // we get the right type.
-
if (ArgIdx == NumArgs) {
// All template arguments were deduced. FT1 is at least as specialized
// as FT2.
@@ -5554,38 +5851,52 @@ FunctionTemplateDecl *Sema::getMoreSpecializedTemplate(
// "that is a member function with no expicit object argument".
// Otherwise the ordering rules for methods with expicit objet arguments
// against anything else make no sense.
- ShouldConvert1 = Method1 && !Method1->isExplicitObjectMemberFunction();
- ShouldConvert2 = Method2 && !Method2->isExplicitObjectMemberFunction();
- if (ShouldConvert1) {
- bool IsRValRef2 =
- ShouldConvert2
- ? Method2->getRefQualifier() == RQ_RValue
- : Proto2->param_type_begin()[0]->isRValueReferenceType();
- // Compare 'this' from Method1 against first parameter from Method2.
- Obj1Ty = GetImplicitObjectParameterType(this->Context, Method1, RawObj1Ty,
- IsRValRef2);
- Args1.push_back(Obj1Ty);
- }
- if (ShouldConvert2) {
- bool IsRValRef1 =
- ShouldConvert1
- ? Method1->getRefQualifier() == RQ_RValue
- : Proto1->param_type_begin()[0]->isRValueReferenceType();
- // Compare 'this' from Method2 against first parameter from Method1.
- Obj2Ty = GetImplicitObjectParameterType(this->Context, Method2, RawObj2Ty,
- IsRValRef1);
- Args2.push_back(Obj2Ty);
- }
+
+ bool NonStaticMethod1 = Method1 && !Method1->isStatic(),
+ NonStaticMethod2 = Method2 && !Method2->isStatic();
+
+ auto Params1Begin = Proto1->param_type_begin(),
+ Params2Begin = Proto2->param_type_begin();
+
size_t NumComparedArguments = NumCallArguments1;
- // Either added an argument above or the prototype includes an explicit
- // object argument we need to count
- if (Method1)
- ++NumComparedArguments;
- Args1.insert(Args1.end(), Proto1->param_type_begin(),
- Proto1->param_type_end());
- Args2.insert(Args2.end(), Proto2->param_type_begin(),
- Proto2->param_type_end());
+ if (auto OO = FD1->getOverloadedOperator();
+ (NonStaticMethod1 && NonStaticMethod2) ||
+ (OO != OO_None && OO != OO_Call && OO != OO_Subscript)) {
+ ShouldConvert1 =
+ NonStaticMethod1 && !Method1->hasCXXExplicitFunctionObjectParameter();
+ ShouldConvert2 =
+ NonStaticMethod2 && !Method2->hasCXXExplicitFunctionObjectParameter();
+ NumComparedArguments += 1;
+
+ if (ShouldConvert1) {
+ bool IsRValRef2 =
+ ShouldConvert2
+ ? Method2->getRefQualifier() == RQ_RValue
+ : Proto2->param_type_begin()[0]->isRValueReferenceType();
+ // Compare 'this' from Method1 against first parameter from Method2.
+ Obj1Ty = GetImplicitObjectParameterType(this->Context, Method1,
+ RawObj1Ty, IsRValRef2);
+ Args1.push_back(Obj1Ty);
+ }
+ if (ShouldConvert2) {
+ bool IsRValRef1 =
+ ShouldConvert1
+ ? Method1->getRefQualifier() == RQ_RValue
+ : Proto1->param_type_begin()[0]->isRValueReferenceType();
+ // Compare 'this' from Method2 against first parameter from Method1.
+ Obj2Ty = GetImplicitObjectParameterType(this->Context, Method2,
+ RawObj2Ty, IsRValRef1);
+ Args2.push_back(Obj2Ty);
+ }
+ } else {
+ if (NonStaticMethod1 && Method1->hasCXXExplicitFunctionObjectParameter())
+ Params1Begin += 1;
+ if (NonStaticMethod2 && Method2->hasCXXExplicitFunctionObjectParameter())
+ Params2Begin += 1;
+ }
+ Args1.insert(Args1.end(), Params1Begin, Proto1->param_type_end());
+ Args2.insert(Args2.end(), Params2Begin, Proto2->param_type_end());
// C++ [temp.func.order]p5:
// The presence of unused ellipsis and default arguments has no effect on
@@ -5876,7 +6187,8 @@ static bool isAtLeastAsSpecializedAs(Sema &S, QualType T1, QualType T2,
Deduced.resize(P2->getTemplateParameters()->size());
if (DeduceTemplateArgumentsByTypeMatch(
S, P2->getTemplateParameters(), T2, T1, Info, Deduced, TDF_None,
- /*PartialOrdering=*/true) != TemplateDeductionResult::Success)
+ /*PartialOrdering=*/true, /*DeducedFromArrayBound=*/false,
+ /*HasDeducedAnyParam=*/nullptr) != TemplateDeductionResult::Success)
return false;
SmallVector<TemplateArgument, 4> DeducedArgs(Deduced.begin(),
@@ -6208,7 +6520,8 @@ bool Sema::isTemplateTemplateParameterAtLeastAsSpecializedAs(
if (::DeduceTemplateArguments(*this, A, AArgs, PArgs, Info, Deduced,
/*NumberOfArgumentsMustMatch=*/false,
IsDeduced ? PackFold::ArgumentToParameter
- : PackFold::ParameterToArgument) !=
+ : PackFold::ParameterToArgument,
+ /*HasDeducedAnyParam=*/nullptr) !=
TemplateDeductionResult::Success)
return false;
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index 9a6cd2cd0ab751..6b6f0e8ce42969 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -1343,6 +1343,9 @@ namespace {
DeclarationName Entity;
// Whether to evaluate the C++20 constraints or simply substitute into them.
bool EvaluateConstraints = true;
+ // Whether Substitution was Incomplete, that is, we tried to substitute in
+ // any user provided template arguments which were null.
+ bool IsIncomplete = false;
public:
typedef TreeTransform<TemplateInstantiator> inherited;
@@ -1373,6 +1376,9 @@ namespace {
/// Returns the name of the entity being instantiated, if any.
DeclarationName getBaseEntity() { return Entity; }
+ /// Returns whether any substitution so far was incomplete.
+ bool getIsIncomplete() const { return IsIncomplete; }
+
/// Sets the "base" location and entity when that
/// information is known based on another transformation.
void setBase(SourceLocation Loc, DeclarationName Entity) {
@@ -1419,6 +1425,8 @@ namespace {
if (TemplateArgs.hasTemplateArgument(Depth, Index)) {
Result = TemplateArgs(Depth, Index);
TemplateArgs.setArgument(Depth, Index, TemplateArgument());
+ } else {
+ IsIncomplete = true;
}
}
@@ -1814,8 +1822,10 @@ Decl *TemplateInstantiator::TransformDecl(SourceLocation Loc, Decl *D) {
// template arguments in a function template, but there were some
// arguments left unspecified.
if (!TemplateArgs.hasTemplateArgument(TTP->getDepth(),
- TTP->getPosition()))
+ TTP->getPosition())) {
+ IsIncomplete = true;
return D;
+ }
TemplateArgument Arg = TemplateArgs(TTP->getDepth(), TTP->getPosition());
@@ -1961,8 +1971,10 @@ TemplateName TemplateInstantiator::TransformTemplateName(
// template arguments in a function template, but there were some
// arguments left unspecified.
if (!TemplateArgs.hasTemplateArgument(TTP->getDepth(),
- TTP->getPosition()))
+ TTP->getPosition())) {
+ IsIncomplete = true;
return Name;
+ }
TemplateArgument Arg = TemplateArgs(TTP->getDepth(), TTP->getPosition());
@@ -2044,8 +2056,10 @@ TemplateInstantiator::TransformTemplateParmRefExpr(DeclRefExpr *E,
// template arguments in a function template, but there were some
// arguments left unspecified.
if (!TemplateArgs.hasTemplateArgument(NTTP->getDepth(),
- NTTP->getPosition()))
+ NTTP->getPosition())) {
+ IsIncomplete = true;
return E;
+ }
TemplateArgument Arg = TemplateArgs(NTTP->getDepth(), NTTP->getPosition());
@@ -2464,6 +2478,7 @@ TemplateInstantiator::TransformTemplateTypeParmType(TypeLocBuilder &TLB,
// template arguments in a function template class, but there were some
// arguments left unspecified.
if (!TemplateArgs.hasTemplateArgument(T->getDepth(), T->getIndex())) {
+ IsIncomplete = true;
TemplateTypeParmTypeLoc NewTL
= TLB.push<TemplateTypeParmTypeLoc>(TL.getType());
NewTL.setNameLoc(TL.getNameLoc());
@@ -2835,7 +2850,8 @@ TypeSourceInfo *Sema::SubstType(TypeLoc TL,
/// Deprecated form of the above.
QualType Sema::SubstType(QualType T,
const MultiLevelTemplateArgumentList &TemplateArgs,
- SourceLocation Loc, DeclarationName Entity) {
+ SourceLocation Loc, DeclarationName Entity,
+ bool *IsIncompleteSubstitution) {
assert(!CodeSynthesisContexts.empty() &&
"Cannot perform an instantiation without some context on the "
"instantiation stack");
@@ -2846,7 +2862,10 @@ QualType Sema::SubstType(QualType T,
return T;
TemplateInstantiator Instantiator(*this, TemplateArgs, Loc, Entity);
- return Instantiator.TransformType(T);
+ QualType QT = Instantiator.TransformType(T);
+ if (IsIncompleteSubstitution && Instantiator.getIsIncomplete())
+ *IsIncompleteSubstitution = true;
+ return QT;
}
static bool NeedsInstantiationAsFunctionType(TypeSourceInfo *T) {
diff --git a/clang/test/CodeCompletion/variadic-template.cpp b/clang/test/CodeCompletion/variadic-template.cpp
index 31fc55ee154f67..370cf5e8461d68 100644
--- a/clang/test/CodeCompletion/variadic-template.cpp
+++ b/clang/test/CodeCompletion/variadic-template.cpp
@@ -8,7 +8,7 @@ void f() {
// The important thing is that we provide OVERLOAD signature in all those cases.
//
// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:%(line-5):7 %s -o - | FileCheck --check-prefix=CHECK-1 %s
- // CHECK-1: OVERLOAD: [#void#]fun(<#T x#>, Args args...)
+ // CHECK-1: OVERLOAD: [#void#]fun(<#T x#>)
// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:%(line-7):10 %s -o - | FileCheck --check-prefix=CHECK-2 %s
// CHECK-2: OVERLOAD: [#void#]fun(int x)
// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:%(line-9):13 %s -o - | FileCheck --check-prefix=CHECK-3 %s
diff --git a/clang/test/Index/complete-call.cpp b/clang/test/Index/complete-call.cpp
index 95bc8d49b2b907..f86c85a9983c72 100644
--- a/clang/test/Index/complete-call.cpp
+++ b/clang/test/Index/complete-call.cpp
@@ -409,7 +409,8 @@ struct Bar2Template : public BarTemplates {
// CHECK-CC22-NEXT: Objective-C interface
// RUN: c-index-test -code-completion-at=%s:64:10 %s | FileCheck -check-prefix=CHECK-CC23 %s
-// CHECK-CC23: OverloadCandidate:{ResultType void}{Text foo_12}{LeftParen (}{CurrentParameter int}{Comma , }{Placeholder int}{RightParen )} (1)
+
+// CHECK-CC23: OverloadCandidate:{ResultType void}{Text foo_12}{LeftParen (}{CurrentParameter T}{Comma , }{Placeholder T}{RightParen )} (1)
// CHECK-CC23: Completion contexts:
// CHECK-CC23-NEXT: Any type
// CHECK-CC23-NEXT: Any value
@@ -702,7 +703,7 @@ struct Bar2Template : public BarTemplates {
// CHECK-CC46-NEXT: Objective-C interface
// RUN: c-index-test -code-completion-at=%s:84:12 %s | FileCheck -check-prefix=CHECK-CC47 %s
-// CHECK-CC47: OverloadCandidate:{ResultType void}{Text foo_12}{LeftParen (}{CurrentParameter int}{Comma , }{Placeholder int}{RightParen )} (1)
+// CHECK-CC47: OverloadCandidate:{ResultType void}{Text foo_12}{LeftParen (}{CurrentParameter T}{Comma , }{Placeholder T}{RightParen )} (1)
// CHECK-CC47: Completion contexts:
// CHECK-CC47-NEXT: Any type
// CHECK-CC47-NEXT: Any value
diff --git a/clang/test/SemaCXX/cxx2b-deducing-this.cpp b/clang/test/SemaCXX/cxx2b-deducing-this.cpp
index bfcc5991cee5ac..63bf92e8d5edd3 100644
--- a/clang/test/SemaCXX/cxx2b-deducing-this.cpp
+++ b/clang/test/SemaCXX/cxx2b-deducing-this.cpp
@@ -1012,6 +1012,49 @@ static_assert(__is_same(X<B{0}>, X<B{0}>));
static_assert(!__is_same(X<B{0}>, X<B{1}>));
} // namespace defaulted_compare
+namespace static_overloaded_operator {
+struct A {
+ template<auto N>
+ static void operator()(const char (&)[N]);
+ void operator()(this auto &&, auto &&);
+
+ void implicit_this() {
+ operator()("123");
+ }
+};
+
+struct B {
+ template<auto N>
+ void operator()(this auto &&, const char (&)[N]);
+ static void operator()(auto &&);
+
+ void implicit_this() {
+ operator()("123");
+ }
+};
+
+struct C {
+ template<auto N>
+ static void operator[](const char (&)[N]);
+ void operator[](this auto &&, auto &&);
+
+ void implicit_this() {
+ operator[]("123");
+ }
+};
+
+struct D {
+ template<auto N>
+ void operator[](this auto &&, const char (&)[N]);
+ static void operator[](auto &&);
+
+ void implicit_this() {
+ operator[]("123");
+ }
+};
+
+} // namespace static_overloaded_operator
+
namespace GH102025 {
struct Foo {
template <class T>
diff --git a/clang/test/SemaTemplate/GH18291.cpp b/clang/test/SemaTemplate/GH18291.cpp
new file mode 100644
index 00000000000000..e77a29c8e2c244
--- /dev/null
+++ b/clang/test/SemaTemplate/GH18291.cpp
@@ -0,0 +1,32 @@
+// RUN: %clang_cc1 -std=c++23 -verify %s
+
+namespace t1 {
+template<bool> struct enable_if { typedef void type; };
+template <class T> class Foo {};
+template <class X> constexpr bool check() { return true; }
+template <class X, class Enable = void> struct Bar {};
+
+template<class X> void func(Bar<X, typename enable_if<check<X>()>::type>) {}
+// expected-note at -1 {{candidate function}}
+
+template<class T> void func(Bar<Foo<T>>) {}
+// expected-note at -1 {{candidate function}}
+
+void g() {
+ func(Bar<Foo<int>>()); // expected-error {{call to 'func' is ambiguous}}
+}
+} // namespace t1
+
+namespace t2 {
+template <bool> struct enable_if;
+template <> struct enable_if<true> {
+ typedef int type;
+};
+struct pair {
+ template <int = 0> pair(int);
+ template <class _U2, enable_if<__is_constructible(int &, _U2)>::type = 0>
+ pair(_U2 &&);
+};
+int test_test_i;
+void test() { pair{test_test_i}; }
+} // namespace t2
diff --git a/clang/test/SemaTemplate/cwg2398.cpp b/clang/test/SemaTemplate/cwg2398.cpp
index 7675d4287cb88a..6fe1bd3d4f1659 100644
--- a/clang/test/SemaTemplate/cwg2398.cpp
+++ b/clang/test/SemaTemplate/cwg2398.cpp
@@ -74,6 +74,20 @@ namespace class_template {
// new-error at -1 {{ambiguous partial specialization}}
} // namespace class_template
+namespace class_template_func {
+ template <class T1, class T2 = float> struct A {};
+
+ template <template <class T4> class TT1, class T5> void f(TT1<T5>);
+ // new-note at -1 {{candidate function}}
+
+ template <class T6, class T7> void f(A<T6, T7>) {};
+ // new-note at -1 {{candidate function}}
+
+ void g() {
+ f(A<int>()); // new-error {{call to 'f' is ambiguous}}
+ }
+} // namespace class_template_func
+
namespace type_pack1 {
template<class T2> struct A;
template<template<class ...T3s> class TT1, class T4> struct A<TT1<T4>> ;
diff --git a/clang/test/SemaTemplate/temp_arg_nontype.cpp b/clang/test/SemaTemplate/temp_arg_nontype.cpp
index 518122cca77b51..da42f85fb910c8 100644
--- a/clang/test/SemaTemplate/temp_arg_nontype.cpp
+++ b/clang/test/SemaTemplate/temp_arg_nontype.cpp
@@ -458,17 +458,13 @@ namespace dependent_nested_partial_specialization {
namespace nondependent_default_arg_ordering {
int n, m;
template<typename A, A B = &n> struct X {};
- template<typename A> void f(X<A>); // expected-note {{candidate}}
- template<typename A> void f(X<A, &m>); // expected-note {{candidate}}
- template<typename A, A B> void f(X<A, B>); // expected-note 2{{candidate}}
+ template<typename A> void f(X<A>);
+ template<typename A> void f(X<A, &m>);
+ template<typename A, A B> void f(X<A, B>);
template<template<typename U, U> class T, typename A, int *B> void f(T<A, B>);
void g() {
- // FIXME: The first and second function templates above should be
- // considered more specialized than the third, but during partial
- // ordering we fail to check that we actually deduced template arguments
- // that make the deduced A identical to A.
- X<int *, &n> x; f(x); // expected-error {{ambiguous}}
- X<int *, &m> y; f(y); // expected-error {{ambiguous}}
+ X<int *, &n> x; f(x);
+ X<int *, &m> y; f(y);
}
}
diff --git a/clang/test/SemaTemplate/temp_arg_type.cpp b/clang/test/SemaTemplate/temp_arg_type.cpp
index cdbcf281125efd..392d2573d3d0e9 100644
--- a/clang/test/SemaTemplate/temp_arg_type.cpp
+++ b/clang/test/SemaTemplate/temp_arg_type.cpp
@@ -69,11 +69,10 @@ namespace deduce_noexcept {
void noexcept_function() noexcept;
void throwing_function();
- template<typename T, bool B> float &deduce_function(T(*)() noexcept(B)); // expected-note {{candidate}}
- template<typename T> int &deduce_function(T(*)() noexcept); // expected-note {{candidate}}
+ template<typename T, bool B> float &deduce_function(T(*)() noexcept(B));
+ template<typename T> int &deduce_function(T(*)() noexcept);
void test_function_deduction() {
- // FIXME: This should probably unambiguously select the second overload.
- int &r = deduce_function(noexcept_function); // expected-error {{ambiguous}}
+ int &r = deduce_function(noexcept_function);
float &s = deduce_function(throwing_function);
}
diff --git a/clang/test/Templight/templight-empty-entries-fix.cpp b/clang/test/Templight/templight-empty-entries-fix.cpp
index ad029d30707563..e17be9012e59cc 100644
--- a/clang/test/Templight/templight-empty-entries-fix.cpp
+++ b/clang/test/Templight/templight-empty-entries-fix.cpp
@@ -170,6 +170,30 @@ template <bool d = true, class = typename b<d>::c> void a() { a(); }
template <bool = true> void d(int = 0) { d(); }
+// CHECK-LABEL: {{^---$}}
+// CHECK: {{^name:[ ]+a$}}
+// CHECK: {{^kind:[ ]+DeducedTemplateArgumentSubstitution$}}
+// CHECK: {{^event:[ ]+Begin$}}
+// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:60:57'$}}
+// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:60:63'$}}
+// CHECK-LABEL: {{^---$}}
+// CHECK: {{^name:[ ]+a$}}
+// CHECK: {{^kind:[ ]+DeducedTemplateArgumentSubstitution$}}
+// CHECK: {{^event:[ ]+End$}}
+// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:60:57'$}}
+// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:60:63'$}}
+// CHECK-LABEL: {{^---$}}
+// CHECK: {{^name:[ ]+a$}}
+// CHECK: {{^kind:[ ]+DeducedTemplateArgumentSubstitution$}}
+// CHECK: {{^event:[ ]+Begin$}}
+// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:20:25'$}}
+// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:60:63'$}}
+// CHECK-LABEL: {{^---$}}
+// CHECK: {{^name:[ ]+a$}}
+// CHECK: {{^kind:[ ]+DeducedTemplateArgumentSubstitution$}}
+// CHECK: {{^event:[ ]+End$}}
+// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:20:25'$}}
+// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:60:63'$}}
// CHECK-LABEL: {{^---$}}
// CHECK: {{^name:[ ]+d$}}
// CHECK: {{^kind:[ ]+DeducedTemplateArgumentSubstitution$}}
@@ -225,41 +249,41 @@ void e() {
}
// CHECK-LABEL: {{^---$}}
-// CHECK: {{^name:[ ]+'\(unnamed struct at .*templight-empty-entries-fix.cpp:223:3\)'$}}
+// CHECK: {{^name:[ ]+'\(unnamed struct at .*templight-empty-entries-fix.cpp:247:3\)'$}}
// CHECK: {{^kind:[ ]+Memoization$}}
// CHECK: {{^event:[ ]+Begin$}}
-// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:223:3'$}}
-// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:224:5'$}}
+// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:247:3'$}}
+// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:248:5'$}}
// CHECK-LABEL: {{^---$}}
-// CHECK: {{^name:[ ]+'\(unnamed struct at .*templight-empty-entries-fix.cpp:223:3\)'$}}
+// CHECK: {{^name:[ ]+'\(unnamed struct at .*templight-empty-entries-fix.cpp:247:3\)'$}}
// CHECK: {{^kind:[ ]+Memoization$}}
// CHECK: {{^event:[ ]+End$}}
-// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:223:3'$}}
-// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:224:5'$}}
+// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:247:3'$}}
+// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:248:5'$}}
// CHECK-LABEL: {{^---$}}
-// CHECK: {{^name:[ ]+'\(unnamed struct at .*templight-empty-entries-fix.cpp:223:3\)'$}}
+// CHECK: {{^name:[ ]+'\(unnamed struct at .*templight-empty-entries-fix.cpp:247:3\)'$}}
// CHECK: {{^kind:[ ]+Memoization$}}
// CHECK: {{^event:[ ]+Begin$}}
-// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:223:3'$}}
-// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:224:5'$}}
+// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:247:3'$}}
+// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:248:5'$}}
// CHECK-LABEL: {{^---$}}
-// CHECK: {{^name:[ ]+'\(unnamed struct at .*templight-empty-entries-fix.cpp:223:3\)'$}}
+// CHECK: {{^name:[ ]+'\(unnamed struct at .*templight-empty-entries-fix.cpp:247:3\)'$}}
// CHECK: {{^kind:[ ]+Memoization$}}
// CHECK: {{^event:[ ]+End$}}
-// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:223:3'$}}
-// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:224:5'$}}
+// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:247:3'$}}
+// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:248:5'$}}
// CHECK-LABEL: {{^---$}}
-// CHECK: {{^name:[ ]+'\(unnamed struct at .*templight-empty-entries-fix.cpp:223:3\)'$}}
+// CHECK: {{^name:[ ]+'\(unnamed struct at .*templight-empty-entries-fix.cpp:247:3\)'$}}
// CHECK: {{^kind:[ ]+Memoization$}}
// CHECK: {{^event:[ ]+Begin$}}
-// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:223:3'$}}
-// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:223:3'$}}
+// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:247:3'$}}
+// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:247:3'$}}
// CHECK-LABEL: {{^---$}}
-// CHECK: {{^name:[ ]+'\(unnamed struct at .*templight-empty-entries-fix.cpp:223:3\)'$}}
+// CHECK: {{^name:[ ]+'\(unnamed struct at .*templight-empty-entries-fix.cpp:247:3\)'$}}
// CHECK: {{^kind:[ ]+Memoization$}}
// CHECK: {{^event:[ ]+End$}}
-// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:223:3'$}}
-// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:223:3'$}}
+// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:247:3'$}}
+// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:247:3'$}}
template <template<typename> class>
@@ -275,59 +299,59 @@ void foo() {
// CHECK: {{^name:[ ]+d$}}
// CHECK: {{^kind:[ ]+ExplicitTemplateArgumentSubstitution$}}
// CHECK: {{^event:[ ]+Begin$}}
-// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:266:6'$}}
-// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:271:3'$}}
+// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:290:6'$}}
+// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:295:3'$}}
// CHECK-LABEL: {{^---$}}
// CHECK: {{^name:[ ]+unnamed template template parameter 0 of d$}}
// CHECK: {{^kind:[ ]+PriorTemplateArgumentSubstitution$}}
// CHECK: {{^event:[ ]+Begin$}}
-// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:265:35'$}}
+// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:289:35'$}}
// CHECK: {{^poi:[ ]+''$}}
// CHECK-LABEL: {{^---$}}
// CHECK: {{^name:[ ]+unnamed template template parameter 0 of d$}}
// CHECK: {{^kind:[ ]+PriorTemplateArgumentSubstitution$}}
// CHECK: {{^event:[ ]+End$}}
-// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:265:35'$}}
+// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:289:35'$}}
// CHECK: {{^poi:[ ]+''$}}
// CHECK-LABEL: {{^---$}}
// CHECK: {{^name:[ ]+d$}}
// CHECK: {{^kind:[ ]+ExplicitTemplateArgumentSubstitution$}}
// CHECK: {{^event:[ ]+End$}}
-// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:266:6'$}}
-// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:271:3'$}}
+// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:290:6'$}}
+// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:295:3'$}}
// CHECK-LABEL: {{^---$}}
// CHECK: {{^name:[ ]+d$}}
// CHECK: {{^kind:[ ]+DeducedTemplateArgumentSubstitution$}}
// CHECK: {{^event:[ ]+Begin$}}
-// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:266:6'$}}
-// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:271:3'$}}
+// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:290:6'$}}
+// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:295:3'$}}
// CHECK-LABEL: {{^---$}}
// CHECK: {{^name:[ ]+d$}}
// CHECK: {{^kind:[ ]+DeducedTemplateArgumentSubstitution$}}
// CHECK: {{^event:[ ]+End$}}
-// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:266:6'$}}
-// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:271:3'$}}
+// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:290:6'$}}
+// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:295:3'$}}
// CHECK-LABEL: {{^---$}}
// CHECK: {{^name:[ ]+'d<C>'$}}
// CHECK: {{^kind:[ ]+TemplateInstantiation$}}
// CHECK: {{^event:[ ]+Begin$}}
-// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:266:6'$}}
-// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:271:3'$}}
+// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:290:6'$}}
+// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:295:3'$}}
// CHECK-LABEL: {{^---$}}
// CHECK: {{^name:[ ]+'d<C>'$}}
// CHECK: {{^kind:[ ]+TemplateInstantiation$}}
// CHECK: {{^event:[ ]+End$}}
-// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:266:6'$}}
-// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:271:3'$}}
+// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:290:6'$}}
+// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:295:3'$}}
// CHECK-LABEL: {{^---$}}
// CHECK: {{^name:[ ]+d$}}
// CHECK: {{^kind:[ ]+ExplicitTemplateArgumentSubstitution$}}
// CHECK: {{^event:[ ]+Begin$}}
// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:171:29'$}}
-// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:271:3'$}}
+// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:295:3'$}}
// CHECK-LABEL: {{^---$}}
// CHECK: {{^name:[ ]+d$}}
// CHECK: {{^kind:[ ]+ExplicitTemplateArgumentSubstitution$}}
// CHECK: {{^event:[ ]+End$}}
// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:171:29'$}}
-// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:271:3'$}}
+// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:295:3'$}}
>From 1c6ea6e86fd32693ba065d8fd0dd8dd50945b9f5 Mon Sep 17 00:00:00 2001
From: Matheus Izvekov <mizvekov at gmail.com>
Date: Tue, 27 Aug 2024 00:35:05 -0300
Subject: [PATCH 2/4] fixup! [clang] check deduction consistency when partial
ordering function templates
---
clang/lib/AST/ExprConstant.cpp | 1 +
clang/lib/Sema/SemaTemplateDeduction.cpp | 2 +-
clang/lib/Sema/SemaTemplateInstantiate.cpp | 22 ++++++++++++++++------
3 files changed, 18 insertions(+), 7 deletions(-)
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 91c1883e7ab24e..5540f58b526705 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -5399,6 +5399,7 @@ static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info,
const Expr *RetExpr = cast<ReturnStmt>(S)->getRetValue();
FullExpressionRAII Scope(Info);
if (RetExpr && RetExpr->isValueDependent()) {
+ EvaluateDependentExpr(RetExpr, Info);
// We know we returned, but we don't know what the value is.
return ESR_Failed;
}
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp
index 8ddc7a4df62444..5d9d57a5c0a6d1 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -5542,7 +5542,7 @@ static TemplateDeductionResult CheckDeductionConsistency(
bool IsIncompleteSubstitution = false;
QualType InstP = S.SubstType(P, MLTAL, FTD->getLocation(), FTD->getDeclName(),
&IsIncompleteSubstitution);
- if (InstP.isNull())
+ if (InstP.isNull() && !IsIncompleteSubstitution)
return TemplateDeductionResult::SubstitutionFailure;
if (!CheckConsistency)
return TemplateDeductionResult::Success;
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index 6b6f0e8ce42969..90248f2b1e163e 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -1346,15 +1346,18 @@ namespace {
// Whether Substitution was Incomplete, that is, we tried to substitute in
// any user provided template arguments which were null.
bool IsIncomplete = false;
+ // Whether an incomplete substituion should be treated as an error.
+ bool BailOutOnIncomplete;
public:
typedef TreeTransform<TemplateInstantiator> inherited;
TemplateInstantiator(Sema &SemaRef,
const MultiLevelTemplateArgumentList &TemplateArgs,
- SourceLocation Loc, DeclarationName Entity)
+ SourceLocation Loc, DeclarationName Entity,
+ bool BailOutOnIncomplete = false)
: inherited(SemaRef), TemplateArgs(TemplateArgs), Loc(Loc),
- Entity(Entity) {}
+ Entity(Entity), BailOutOnIncomplete(BailOutOnIncomplete) {}
void setEvaluateConstraints(bool B) {
EvaluateConstraints = B;
@@ -1427,6 +1430,8 @@ namespace {
TemplateArgs.setArgument(Depth, Index, TemplateArgument());
} else {
IsIncomplete = true;
+ if (BailOutOnIncomplete)
+ return TemplateArgument();
}
}
@@ -1824,7 +1829,7 @@ Decl *TemplateInstantiator::TransformDecl(SourceLocation Loc, Decl *D) {
if (!TemplateArgs.hasTemplateArgument(TTP->getDepth(),
TTP->getPosition())) {
IsIncomplete = true;
- return D;
+ return BailOutOnIncomplete ? nullptr : D;
}
TemplateArgument Arg = TemplateArgs(TTP->getDepth(), TTP->getPosition());
@@ -1973,7 +1978,7 @@ TemplateName TemplateInstantiator::TransformTemplateName(
if (!TemplateArgs.hasTemplateArgument(TTP->getDepth(),
TTP->getPosition())) {
IsIncomplete = true;
- return Name;
+ return BailOutOnIncomplete ? TemplateName() : Name;
}
TemplateArgument Arg = TemplateArgs(TTP->getDepth(), TTP->getPosition());
@@ -2058,7 +2063,7 @@ TemplateInstantiator::TransformTemplateParmRefExpr(DeclRefExpr *E,
if (!TemplateArgs.hasTemplateArgument(NTTP->getDepth(),
NTTP->getPosition())) {
IsIncomplete = true;
- return E;
+ return BailOutOnIncomplete ? ExprError() : E;
}
TemplateArgument Arg = TemplateArgs(NTTP->getDepth(), NTTP->getPosition());
@@ -2479,6 +2484,9 @@ TemplateInstantiator::TransformTemplateTypeParmType(TypeLocBuilder &TLB,
// arguments left unspecified.
if (!TemplateArgs.hasTemplateArgument(T->getDepth(), T->getIndex())) {
IsIncomplete = true;
+ if (BailOutOnIncomplete)
+ return QualType();
+
TemplateTypeParmTypeLoc NewTL
= TLB.push<TemplateTypeParmTypeLoc>(TL.getType());
NewTL.setNameLoc(TL.getNameLoc());
@@ -2861,7 +2869,9 @@ QualType Sema::SubstType(QualType T,
if (!T->isInstantiationDependentType() && !T->isVariablyModifiedType())
return T;
- TemplateInstantiator Instantiator(*this, TemplateArgs, Loc, Entity);
+ TemplateInstantiator Instantiator(
+ *this, TemplateArgs, Loc, Entity,
+ /*BailOutOnIncomplete=*/IsIncompleteSubstitution != nullptr);
QualType QT = Instantiator.TransformType(T);
if (IsIncompleteSubstitution && Instantiator.getIsIncomplete())
*IsIncompleteSubstitution = true;
>From 5b8099e542f526fe10f4c54f56c3ac52dd7a8715 Mon Sep 17 00:00:00 2001
From: Matheus Izvekov <mizvekov at gmail.com>
Date: Tue, 27 Aug 2024 01:20:17 -0300
Subject: [PATCH 3/4] fixup! [clang] check deduction consistency when partial
ordering function templates
---
clang/lib/Sema/SemaTemplateDeduction.cpp | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp
index 5d9d57a5c0a6d1..adcb81f816d666 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -3093,8 +3093,9 @@ static TemplateDeductionResult ConvertDeducedTemplateArguments(
// [temp.deduct.partial]p12 - When partial ordering, it's ok for template
// parameters to remain not deduced. As a provisional fix for a core issue
- // that does not exist yet, only consider template parameters that were
- // deduced, disregarding any default arguments.
+ // that does not exist yet, which may be related to CWG2160, only consider
+ // template parameters that were deduced, disregarding any default
+ // arguments.
if (IsIncomplete) {
*IsIncomplete = true;
SugaredBuilder.push_back({});
>From 9497c1d1f336cd418a55acfe44d3f9e4a247b331 Mon Sep 17 00:00:00 2001
From: Matheus Izvekov <mizvekov at gmail.com>
Date: Tue, 27 Aug 2024 16:41:20 -0300
Subject: [PATCH 4/4] fixup! [clang] check deduction consistency when partial
ordering function templates
---
clang/lib/Sema/SemaTemplateDeduction.cpp | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp
index adcb81f816d666..78c22a7dae7725 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -3091,10 +3091,10 @@ static TemplateDeductionResult ConvertDeducedTemplateArguments(
continue;
}
- // [temp.deduct.partial]p12 - When partial ordering, it's ok for template
- // parameters to remain not deduced. As a provisional fix for a core issue
- // that does not exist yet, which may be related to CWG2160, only consider
- // template parameters that were deduced, disregarding any default
+ // [C++26][temp.deduct.partial]p12 - When partial ordering, it's ok for
+ // template parameters to remain not deduced. As a provisional fix for a
+ // core issue that does not exist yet, which may be related to CWG2160, only
+ // consider template parameters that were deduced, disregarding any default
// arguments.
if (IsIncomplete) {
*IsIncomplete = true;
More information about the cfe-commits
mailing list