[clang] [clang-tools-extra] [clang] check deduction consistency when partial ordering function templates (PR #100692)
Matheus Izvekov via cfe-commits
cfe-commits at lists.llvm.org
Thu Jul 25 23:25:25 PDT 2024
https://github.com/mizvekov updated https://github.com/llvm/llvm-project/pull/100692
>From c7ef00e6b9b2c798ef002696be6ebe65195d2fab 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] [clang] check deduction consistency when partial ordering
function templates
This makes partial ordering of function templates consistent with
other entities.
Fixes #18291
---
.../checkers/bugprone/stringview-nullptr.cpp | 85 +---
clang/docs/ReleaseNotes.rst | 2 +
clang/lib/AST/ExprConstant.cpp | 1 -
clang/lib/Sema/SemaTemplateDeduction.cpp | 425 +++++++++++++-----
.../test/CodeCompletion/variadic-template.cpp | 2 +-
clang/test/SemaTemplate/GH18291.cpp | 16 +
clang/test/SemaTemplate/cwg2398.cpp | 14 +
clang/test/SemaTemplate/deduction.cpp | 4 +-
clang/test/SemaTemplate/temp_arg_nontype.cpp | 14 +-
clang/test/SemaTemplate/temp_arg_type.cpp | 7 +-
.../Templight/templight-empty-entries-fix.cpp | 92 ++--
11 files changed, 419 insertions(+), 243 deletions(-)
create mode 100644 clang/test/SemaTemplate/GH18291.cpp
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/stringview-nullptr.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/stringview-nullptr.cpp
index 02fcab31dcf3e..19c4da437c85f 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/stringview-nullptr.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/stringview-nullptr.cpp
@@ -30,98 +30,27 @@ class basic_string_view {
constexpr basic_string_view &operator=(const basic_string_view &) {}
};
-template <typename CharT>
-constexpr bool operator<(basic_string_view<CharT>, basic_string_view<CharT>) {
- return {};
-}
-template <typename CharT>
-constexpr bool operator<(type_identity_t<basic_string_view<CharT>>,
- basic_string_view<CharT>) {
- return {};
-}
-template <typename CharT>
-constexpr bool operator<(basic_string_view<CharT>,
- type_identity_t<basic_string_view<CharT>>) {
- return {};
-}
-
-template <typename CharT>
-constexpr bool operator<=(basic_string_view<CharT>, basic_string_view<CharT>) {
- return {};
-}
-template <typename CharT>
-constexpr bool operator<=(type_identity_t<basic_string_view<CharT>>,
- basic_string_view<CharT>) {
- return {};
-}
-template <typename CharT>
-constexpr bool operator<=(basic_string_view<CharT>,
- type_identity_t<basic_string_view<CharT>>) {
- return {};
-}
-
-template <typename CharT>
-constexpr bool operator>(basic_string_view<CharT>, basic_string_view<CharT>) {
- return {};
-}
-template <typename CharT>
-constexpr bool operator>(type_identity_t<basic_string_view<CharT>>,
- basic_string_view<CharT>) {
- return {};
-}
-template <typename CharT>
-constexpr bool operator>(basic_string_view<CharT>,
- type_identity_t<basic_string_view<CharT>>) {
- return {};
-}
-
-template <typename CharT>
-constexpr bool operator>=(basic_string_view<CharT>, basic_string_view<CharT>) {
- return {};
-}
-template <typename CharT>
-constexpr bool operator>=(type_identity_t<basic_string_view<CharT>>,
- basic_string_view<CharT>) {
- return {};
-}
-template <typename CharT>
-constexpr bool operator>=(basic_string_view<CharT>,
- type_identity_t<basic_string_view<CharT>>) {
- return {};
-}
+using string_view = basic_string_view<char>;
-template <typename CharT>
-constexpr bool operator==(basic_string_view<CharT>, basic_string_view<CharT>) {
+constexpr bool operator<(string_view, string_view) {
return {};
}
-template <typename CharT>
-constexpr bool operator==(type_identity_t<basic_string_view<CharT>>,
- basic_string_view<CharT>) {
+constexpr bool operator<=(string_view, string_view) {
return {};
}
-template <typename CharT>
-constexpr bool operator==(basic_string_view<CharT>,
- type_identity_t<basic_string_view<CharT>>) {
+constexpr bool operator>(string_view, string_view) {
return {};
}
-
-template <typename CharT>
-constexpr bool operator!=(basic_string_view<CharT>, basic_string_view<CharT>) {
+constexpr bool operator>=(string_view, string_view) {
return {};
}
-template <typename CharT>
-constexpr bool operator!=(type_identity_t<basic_string_view<CharT>>,
- basic_string_view<CharT>) {
+constexpr bool operator==(string_view, string_view) {
return {};
}
-template <typename CharT>
-constexpr bool operator!=(basic_string_view<CharT>,
- type_identity_t<basic_string_view<CharT>>) {
+constexpr bool operator!=(string_view, string_view) {
return {};
}
-using string_view = basic_string_view<char>;
-
} // namespace std
using SV = std::string_view; // Used in some places for shorter line length
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 5dddd8f1c5af5..6098101a73a62 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -153,6 +153,8 @@ Bug Fixes to C++ Support
- Fixed a crash when an expression with a dependent ``__typeof__`` type is used as the operand of a unary operator. (#GH97646)
- Fixed a failed assertion when checking invalid delete operator declaration. (#GH96191)
+- 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/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 558e20ed3e423..2512cd575fbdd 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -5346,7 +5346,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 b7b857ebf804b..4e5aeab125a01 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -837,9 +837,11 @@ class PackDeductionScope {
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 +861,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
@@ -1024,18 +1028,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;
@@ -1045,11 +1051,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.
@@ -1149,6 +1158,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;
@@ -1157,43 +1167,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
@@ -1219,11 +1199,10 @@ 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, ArgIdx, Params[ParamIdx].getUnqualifiedType(),
+ Args[ArgIdx].getUnqualifiedType(), Info, Deduced,
+ PartialOrdering);
Result != TemplateDeductionResult::Success)
return Result;
@@ -1239,20 +1218,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, ArgIdx, Pattern.getUnqualifiedType(),
+ Args[ArgIdx].getUnqualifiedType(), Info, Deduced,
+ PartialOrdering);
Result != TemplateDeductionResult::Success)
return Result;
-
PackScope.nextPackElement();
}
} else {
@@ -1305,6 +1285,56 @@ 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]).
+///
+/// \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) {
+ return ::DeduceForEachType(
+ S, TemplateParams, Params, NumParams, Args, NumArgs, Info, Deduced,
+ PartialOrdering, /*FinishingDeduction=*/false,
+ [TDF](Sema &S, TemplateParameterList *TemplateParams, int, QualType P,
+ QualType A, TemplateDeductionInfo &Info,
+ SmallVectorImpl<DeducedTemplateArgument> &Deduced,
+ bool PartialOrdering) {
+ return DeduceTemplateArgumentsByTypeMatch(
+ S, TemplateParams, P, A, Info, Deduced, TDF, PartialOrdering,
+ /*DeducedFromArrayBound=*/false);
+ });
+}
+
/// 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
@@ -2922,7 +2952,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) {
@@ -3008,11 +3038,17 @@ static TemplateDeductionResult ConvertDeducedTemplateArguments(
// If there was no default argument, deduction is incomplete.
if (DefArg.getArgument().isNull()) {
+ if (IsIncomplete) {
+ *IsIncomplete = true;
+ SugaredBuilder.push_back({});
+ CanonicalBuilder.push_back({});
+ continue;
+ }
+
Info.Param = makeTemplateParameter(
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;
@@ -3227,7 +3263,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;
@@ -3831,11 +3867,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;
@@ -3914,9 +3951,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))
@@ -5399,11 +5434,85 @@ static QualType GetImplicitObjectParameterType(ASTContext &Context,
return Context.getLValueReferenceType(RawType);
}
+static TemplateDeductionResult FinishTemplateArgumentDeduction(
+ Sema &S, FunctionTemplateDecl *FTD, int ArgIdx, QualType P, QualType A,
+ SmallVectorImpl<DeducedTemplateArgument> &Deduced,
+ TemplateDeductionInfo &Info) {
+ // Unevaluated SFINAE context.
+ EnterExpressionEvaluationContext Unevaluated(
+ S, Sema::ExpressionEvaluationContext::Unevaluated);
+ Sema::SFINAETrap Trap(S);
+
+ Sema::ContextRAII SavedContext(S, getAsDeclContextOrEnclosing(FTD));
+
+ // 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(
+ 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);
+
+ QualType InstP;
+ {
+ MultiLevelTemplateArgumentList MLTAL(FTD, SugaredBuilder,
+ /*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);
+ InstP = S.SubstType(P, MLTAL, FTD->getLocation(), FTD->getDeclName());
+ if (InstP.isNull())
+ return TemplateDeductionResult::SubstitutionFailure;
+ }
+
+ 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;
+
+ // 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,
@@ -5425,16 +5534,41 @@ static bool isAtLeastAsSpecializedAs(Sema &S, SourceLocation Loc,
// the partial ordering is done:
TemplateDeductionInfo Info(Loc);
switch (TPOC) {
- case TPOC_Call:
+ case TPOC_Call: {
if (DeduceTemplateArguments(S, TemplateParams, Args2.data(), Args2.size(),
Args1.data(), Args1.size(), Info, Deduced,
TDF_None, /*PartialOrdering=*/true) !=
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;
- case TPOC_Conversion:
+ bool AtLeastAsSpecialized = true;
+ S.runWithSufficientStackSpace(Info.getLocation(), [&] {
+ AtLeastAsSpecialized =
+ ::DeduceForEachType(
+ S, TemplateParams, Args2.data(), Args2.size(), Args1.data(),
+ Args1.size(), Info, Deduced,
+ /*PartialOrdering=*/true, /*FinishingDeduction=*/true,
+ [&FT2](Sema &S, TemplateParameterList *, int ArgIdx, QualType P,
+ QualType A, TemplateDeductionInfo &Info,
+ SmallVectorImpl<DeducedTemplateArgument> &Deduced,
+ bool PartialOrdering) {
+ return ::FinishTemplateArgumentDeduction(S, FT2, ArgIdx, P, A,
+ Deduced, Info);
+ }) == TemplateDeductionResult::Success;
+ });
+ if (!AtLeastAsSpecialized)
+ return false;
+ } break;
+
+ case TPOC_Conversion: {
// - In the context of a call to a conversion operator, the return types
// of the conversion function templates are used.
if (DeduceTemplateArgumentsByTypeMatch(
@@ -5442,9 +5576,27 @@ static bool isAtLeastAsSpecializedAs(Sema &S, SourceLocation Loc,
Info, Deduced, TDF_None,
/*PartialOrdering=*/true) != TemplateDeductionResult::Success)
return false;
- break;
- case TPOC_Other:
+ 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, /*ArgIdx=*/-1, Proto2->getReturnType(),
+ Proto1->getReturnType(), Deduced,
+ Info) == TemplateDeductionResult::Success;
+ });
+ if (!AtLeastAsSpecialized)
+ return false;
+ } break;
+
+ case TPOC_Other: {
// - In other contexts (14.6.6.2) the function template's function type
// is used.
if (DeduceTemplateArgumentsByTypeMatch(
@@ -5452,7 +5604,42 @@ static bool isAtLeastAsSpecializedAs(Sema &S, SourceLocation Loc,
TDF_AllowCompatibleFunctionType,
/*PartialOrdering=*/true) != 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, /*ArgIdx=*/-1, Proto2->getReturnType(),
+ Proto1->getReturnType(), Deduced,
+ Info) == TemplateDeductionResult::Success;
+ if (!AtLeastAsSpecialized)
+ return;
+ S.runWithSufficientStackSpace(Info.getLocation(), [&] {
+ AtLeastAsSpecialized =
+ ::DeduceForEachType(
+ S, TemplateParams, Proto2->getParamTypes().data(),
+ Proto2->getParamTypes().size(), Proto1->getParamTypes().data(),
+ Proto1->getParamTypes().size(), Info, Deduced,
+ /*PartialOrdering=*/true, /*FinishingDeduction=*/true,
+ [&FT2](Sema &S, TemplateParameterList *, int ArgIdx, QualType P,
+ QualType A, TemplateDeductionInfo &Info,
+ SmallVectorImpl<DeducedTemplateArgument> &Deduced,
+ bool PartialOrdering) {
+ return ::FinishTemplateArgumentDeduction(S, FT2, ArgIdx, P, A,
+ Deduced, Info);
+ }) == TemplateDeductionResult::Success;
+ });
+ });
+ if (!AtLeastAsSpecialized)
+ return false;
+ } break;
}
// C++0x [temp.deduct.partial]p11:
@@ -5466,10 +5653,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.
@@ -5558,38 +5741,50 @@ 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 ((NonStaticMethod1 && NonStaticMethod2) || FD1->isOverloadedOperator()) {
+ 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
diff --git a/clang/test/CodeCompletion/variadic-template.cpp b/clang/test/CodeCompletion/variadic-template.cpp
index 31fc55ee154f6..370cf5e8461d6 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/SemaTemplate/GH18291.cpp b/clang/test/SemaTemplate/GH18291.cpp
new file mode 100644
index 0000000000000..2dc7328edad52
--- /dev/null
+++ b/clang/test/SemaTemplate/GH18291.cpp
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -std=c++23 -verify %s
+
+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}}
+}
diff --git a/clang/test/SemaTemplate/cwg2398.cpp b/clang/test/SemaTemplate/cwg2398.cpp
index 7675d4287cb88..6fe1bd3d4f165 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/deduction.cpp b/clang/test/SemaTemplate/deduction.cpp
index a209615c36479..088977249e47d 100644
--- a/clang/test/SemaTemplate/deduction.cpp
+++ b/clang/test/SemaTemplate/deduction.cpp
@@ -140,11 +140,13 @@ namespace test2 {
template<typename T> struct Const { typedef void const type; };
template<typename T> void f(T, typename Const<T>::type*);
+ // expected-note at -1 {{candidate function}}
template<typename T> void f(T, void const *);
+ // expected-note at -1 {{candidate function}}
void test() {
void *p = 0;
- f(0, p);
+ f(0, p); // expected-error {{call to 'f' is ambiguous}}
}
}
diff --git a/clang/test/SemaTemplate/temp_arg_nontype.cpp b/clang/test/SemaTemplate/temp_arg_nontype.cpp
index e091de669fab4..cbcfb2a5b8674 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 cdbcf281125ef..392d2573d3d0e 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 ad029d3070756..e17be9012e59c 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'$}}
More information about the cfe-commits
mailing list