[clang] [Clang] Defer the instantiation of explicit-specifier until constraint checking completes (PR #70548)
via cfe-commits
cfe-commits at lists.llvm.org
Tue Oct 31 09:24:00 PDT 2023
https://github.com/LYP951018 updated https://github.com/llvm/llvm-project/pull/70548
>From b62beb7553f098488e64c81995558c19cd36d785 Mon Sep 17 00:00:00 2001
From: letrec <liuyupei951018 at hotmail.com>
Date: Sat, 28 Oct 2023 18:05:36 +0800
Subject: [PATCH 1/4] Defer the instantiation of explicit-specifier after
constraint checking
---
clang/docs/ReleaseNotes.rst | 4 ++
clang/include/clang/Sema/Sema.h | 3 +
clang/lib/Sema/SemaTemplateDeduction.cpp | 59 +++++++++++++++++++
.../lib/Sema/SemaTemplateInstantiateDecl.cpp | 40 ++++++++-----
.../SemaCXX/cxx2a-explicit-bool-deferred.cpp | 31 ++++++++++
5 files changed, 123 insertions(+), 14 deletions(-)
create mode 100644 clang/test/SemaCXX/cxx2a-explicit-bool-deferred.cpp
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index bc28bb567f6932a..d9980694de40f6f 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -670,6 +670,10 @@ Bug Fixes to C++ Support
default initializing a base class in a constant expression context. Fixes:
(`#69890 <https://github.com/llvm/llvm-project/issues/69890>`_)
+- Clang now defers the instantiation of explicit specifier until constraint checking
+ completes (except deduction guides). Fixes:
+ (`#59827 <https://github.com/llvm/llvm-project/issues/59827>`_)
+
Bug Fixes to AST Handling
^^^^^^^^^^^^^^^^^^^^^^^^^
- Fixed an import failure of recursive friend class template.
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 91a4211a5cf5cce..daed24be0a86d11 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -10430,6 +10430,9 @@ class Sema final {
const CXXConstructorDecl *Tmpl,
const MultiLevelTemplateArgumentList &TemplateArgs);
+ ExplicitSpecifier instantiateExplicitSpecifier(
+ const MultiLevelTemplateArgumentList &TemplateArgs, ExplicitSpecifier ES);
+
NamedDecl *FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
const MultiLevelTemplateArgumentList &TemplateArgs,
bool FindingInstantiatedContext = false);
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp
index 0b3f0247ea3bee3..f06332770f51d1f 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -3553,6 +3553,56 @@ static unsigned getPackIndexForParam(Sema &S,
llvm_unreachable("parameter index would not be produced from template");
}
+// if `Specialization` is a `CXXConstructorDecl` or `CXXConversionDecl`
+// we try to instantiate and update its explicit specifier after constraint
+// checking.
+static Sema::TemplateDeductionResult
+tryInstantiateExplicitSpecifier(Sema &S, FunctionDecl *Specialization,
+ const MultiLevelTemplateArgumentList &SubstArgs,
+ TemplateDeductionInfo &Info,
+ FunctionTemplateDecl *FunctionTemplate,
+ ArrayRef<TemplateArgument> DeducedArgs) {
+
+ const auto TryInstantiateExplicitSpecifierForSingleDecl =
+ [&](auto *ExplicitDecl) {
+ ExplicitSpecifier ExplicitSpecifier =
+ ExplicitDecl->getExplicitSpecifier();
+ Expr *const Expr = ExplicitSpecifier.getExpr();
+ if (!Expr) {
+ return Sema::TDK_Success;
+ }
+ if (!Expr->isValueDependent()) {
+ return Sema::TDK_Success;
+ }
+ // TemplateDeclInstantiator::InitFunctionInstantiation set the
+ // ActiveInstType to TemplateInstantiation, but we need
+ // to enable SFINAE when instantiating explicit specifier.
+ Sema::InstantiatingTemplate Inst(
+ S, Info.getLocation(), FunctionTemplate, DeducedArgs,
+ Sema::CodeSynthesisContext::DeducedTemplateArgumentSubstitution,
+ Info);
+ const auto Instantiated =
+ S.instantiateExplicitSpecifier(SubstArgs, ExplicitSpecifier);
+ if (Instantiated.isInvalid()) {
+ ExplicitDecl->setInvalidDecl(true);
+ return clang::Sema::TDK_SubstitutionFailure;
+ }
+ ExplicitDecl->setExplicitSpecifier(Instantiated);
+ return clang::Sema::TDK_Success;
+ };
+ Sema::TemplateDeductionResult DeductionResult = clang::Sema::TDK_Success;
+ if (CXXConstructorDecl *ConstructorDecl =
+ dyn_cast_or_null<CXXConstructorDecl>(Specialization)) {
+ DeductionResult =
+ TryInstantiateExplicitSpecifierForSingleDecl(ConstructorDecl);
+ } else if (CXXConversionDecl *ConversionDecl =
+ dyn_cast_or_null<CXXConversionDecl>(Specialization)) {
+ DeductionResult =
+ TryInstantiateExplicitSpecifierForSingleDecl(ConversionDecl);
+ }
+ return DeductionResult;
+}
+
/// Finish template argument deduction for a function template,
/// checking the deduced template arguments for completeness and forming
/// the function template specialization.
@@ -3682,6 +3732,15 @@ Sema::TemplateDeductionResult Sema::FinishTemplateArgumentDeduction(
}
}
+ // We skipped the instantiation of the explicit-specifier during subst the
+ // decl before. Now, we try to instantiate it back if the Specialization is a
+ // constructor or a conversion.
+ if (TDK_Success !=
+ tryInstantiateExplicitSpecifier(*this, Specialization, SubstArgs, Info,
+ FunctionTemplate, DeducedArgs)) {
+ return TDK_SubstitutionFailure;
+ }
+
if (OriginalCallArgs) {
// C++ [temp.deduct.call]p4:
// In general, the deduction process attempts to find template argument
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 78a7892a35a320b..163dbef03e80a4d 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -563,18 +563,16 @@ static void instantiateDependentAMDGPUFlatWorkGroupSizeAttr(
S.addAMDGPUFlatWorkGroupSizeAttr(New, Attr, MinExpr, MaxExpr);
}
-static ExplicitSpecifier
-instantiateExplicitSpecifier(Sema &S,
- const MultiLevelTemplateArgumentList &TemplateArgs,
- ExplicitSpecifier ES, FunctionDecl *New) {
+ExplicitSpecifier Sema::instantiateExplicitSpecifier(
+ const MultiLevelTemplateArgumentList &TemplateArgs, ExplicitSpecifier ES) {
if (!ES.getExpr())
return ES;
Expr *OldCond = ES.getExpr();
Expr *Cond = nullptr;
{
EnterExpressionEvaluationContext Unevaluated(
- S, Sema::ExpressionEvaluationContext::ConstantEvaluated);
- ExprResult SubstResult = S.SubstExpr(OldCond, TemplateArgs);
+ *this, Sema::ExpressionEvaluationContext::ConstantEvaluated);
+ ExprResult SubstResult = SubstExpr(OldCond, TemplateArgs);
if (SubstResult.isInvalid()) {
return ExplicitSpecifier::Invalid();
}
@@ -582,7 +580,7 @@ instantiateExplicitSpecifier(Sema &S,
}
ExplicitSpecifier Result(Cond, ES.getKind());
if (!Cond->isTypeDependent())
- S.tryResolveExplicitSpecifier(Result);
+ tryResolveExplicitSpecifier(Result);
return Result;
}
@@ -2073,8 +2071,8 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(
ExplicitSpecifier InstantiatedExplicitSpecifier;
if (auto *DGuide = dyn_cast<CXXDeductionGuideDecl>(D)) {
- InstantiatedExplicitSpecifier = instantiateExplicitSpecifier(
- SemaRef, TemplateArgs, DGuide->getExplicitSpecifier(), DGuide);
+ InstantiatedExplicitSpecifier = SemaRef.instantiateExplicitSpecifier(
+ TemplateArgs, DGuide->getExplicitSpecifier());
if (InstantiatedExplicitSpecifier.isInvalid())
return nullptr;
}
@@ -2453,11 +2451,25 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
}
}
- ExplicitSpecifier InstantiatedExplicitSpecifier =
- instantiateExplicitSpecifier(SemaRef, TemplateArgs,
- ExplicitSpecifier::getFromDecl(D), D);
- if (InstantiatedExplicitSpecifier.isInvalid())
- return nullptr;
+ auto InstantiatedExplicitSpecifier = ExplicitSpecifier::getFromDecl(D);
+ // deduction guides need this
+ const bool CouldInstantiate =
+ InstantiatedExplicitSpecifier.getExpr() == nullptr ||
+ !InstantiatedExplicitSpecifier.getExpr()->isValueDependent();
+
+ // Delay the instantiation of the explicit-specifier until after the
+ // constraints are checked during template argument deduction.
+ if (CouldInstantiate ||
+ SemaRef.CodeSynthesisContexts.back().Kind !=
+ Sema::CodeSynthesisContext::DeducedTemplateArgumentSubstitution) {
+ InstantiatedExplicitSpecifier = SemaRef.instantiateExplicitSpecifier(
+ TemplateArgs, InstantiatedExplicitSpecifier);
+
+ if (InstantiatedExplicitSpecifier.isInvalid())
+ return nullptr;
+ } else {
+ InstantiatedExplicitSpecifier.setKind(ExplicitSpecKind::Unresolved);
+ }
// Implicit destructors/constructors created for local classes in
// DeclareImplicit* (see SemaDeclCXX.cpp) might not have an associated TSI.
diff --git a/clang/test/SemaCXX/cxx2a-explicit-bool-deferred.cpp b/clang/test/SemaCXX/cxx2a-explicit-bool-deferred.cpp
new file mode 100644
index 000000000000000..4d667008f2e2763
--- /dev/null
+++ b/clang/test/SemaCXX/cxx2a-explicit-bool-deferred.cpp
@@ -0,0 +1,31 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++2a %s
+
+template <typename T1, typename T2> struct is_same {
+ static constexpr bool value = false;
+};
+
+template <typename T> struct is_same<T, T> {
+ static constexpr bool value = true;
+};
+
+template <class T, class U>
+concept SameHelper = is_same<T, U>::value;
+template <class T, class U>
+concept same_as = SameHelper<T, U> && SameHelper<U, T>;
+
+namespace deferred_instantiation {
+template <class X> constexpr X do_not_instantiate() { return nullptr; }
+
+struct T {
+ template <same_as<float> X> explicit(do_not_instantiate<X>()) T(X) {}
+
+ T(int) {}
+};
+
+T t(5);
+// expected-error at 17{{cannot initialize}}
+// expected-note at 20{{in instantiation of function template specialization}}
+// expected-note at 30{{while substituting deduced template arguments}}
+// expected-note at 30{{in instantiation of function template specialization}}
+T t2(5.0f);
+} // namespace deferred_instantiation
>From c1e2d504ac22e16fb59f7390b29065c2e7879d27 Mon Sep 17 00:00:00 2001
From: letrec <liuyupei951018 at hotmail.com>
Date: Tue, 31 Oct 2023 00:47:39 +0800
Subject: [PATCH 2/4] fix CR comments
---
clang/lib/Sema/SemaTemplateDeduction.cpp | 94 ++++++++++++------------
1 file changed, 45 insertions(+), 49 deletions(-)
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp
index f06332770f51d1f..0218c4319ad01a0 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -3557,50 +3557,44 @@ static unsigned getPackIndexForParam(Sema &S,
// we try to instantiate and update its explicit specifier after constraint
// checking.
static Sema::TemplateDeductionResult
-tryInstantiateExplicitSpecifier(Sema &S, FunctionDecl *Specialization,
- const MultiLevelTemplateArgumentList &SubstArgs,
- TemplateDeductionInfo &Info,
- FunctionTemplateDecl *FunctionTemplate,
- ArrayRef<TemplateArgument> DeducedArgs) {
-
- const auto TryInstantiateExplicitSpecifierForSingleDecl =
- [&](auto *ExplicitDecl) {
- ExplicitSpecifier ExplicitSpecifier =
- ExplicitDecl->getExplicitSpecifier();
- Expr *const Expr = ExplicitSpecifier.getExpr();
- if (!Expr) {
- return Sema::TDK_Success;
- }
- if (!Expr->isValueDependent()) {
- return Sema::TDK_Success;
- }
- // TemplateDeclInstantiator::InitFunctionInstantiation set the
- // ActiveInstType to TemplateInstantiation, but we need
- // to enable SFINAE when instantiating explicit specifier.
- Sema::InstantiatingTemplate Inst(
- S, Info.getLocation(), FunctionTemplate, DeducedArgs,
- Sema::CodeSynthesisContext::DeducedTemplateArgumentSubstitution,
- Info);
- const auto Instantiated =
- S.instantiateExplicitSpecifier(SubstArgs, ExplicitSpecifier);
- if (Instantiated.isInvalid()) {
- ExplicitDecl->setInvalidDecl(true);
- return clang::Sema::TDK_SubstitutionFailure;
- }
- ExplicitDecl->setExplicitSpecifier(Instantiated);
- return clang::Sema::TDK_Success;
- };
- Sema::TemplateDeductionResult DeductionResult = clang::Sema::TDK_Success;
- if (CXXConstructorDecl *ConstructorDecl =
- dyn_cast_or_null<CXXConstructorDecl>(Specialization)) {
- DeductionResult =
- TryInstantiateExplicitSpecifierForSingleDecl(ConstructorDecl);
- } else if (CXXConversionDecl *ConversionDecl =
- dyn_cast_or_null<CXXConversionDecl>(Specialization)) {
- DeductionResult =
- TryInstantiateExplicitSpecifierForSingleDecl(ConversionDecl);
- }
- return DeductionResult;
+resolveExplicitSpecifier(Sema &S, FunctionDecl *Specialization,
+ const MultiLevelTemplateArgumentList &SubstArgs,
+ TemplateDeductionInfo &Info,
+ FunctionTemplateDecl *FunctionTemplate,
+ ArrayRef<TemplateArgument> DeducedArgs) {
+ auto GetExplicitSpecifier = [](FunctionDecl *D) {
+ return isa<CXXConstructorDecl>(D)
+ ? cast<CXXConstructorDecl>(D)->getExplicitSpecifier()
+ : cast<CXXConversionDecl>(D)->getExplicitSpecifier();
+ };
+ auto SetExplicitSpecifier = [](FunctionDecl *D, ExplicitSpecifier ES) {
+ isa<CXXConstructorDecl>(D)
+ ? cast<CXXConstructorDecl>(D)->setExplicitSpecifier(ES)
+ : cast<CXXConversionDecl>(D)->setExplicitSpecifier(ES);
+ };
+
+ ExplicitSpecifier ExplicitSpecifier = GetExplicitSpecifier(Specialization);
+ Expr *const Expr = ExplicitSpecifier.getExpr();
+ if (!Expr) {
+ return Sema::TDK_Success;
+ }
+ if (!Expr->isValueDependent()) {
+ return Sema::TDK_Success;
+ }
+ // TemplateDeclInstantiator::InitFunctionInstantiation set the
+ // ActiveInstType to TemplateInstantiation, but we need
+ // to enable SFINAE when instantiating an explicit specifier.
+ Sema::InstantiatingTemplate Inst(
+ S, Info.getLocation(), FunctionTemplate, DeducedArgs,
+ Sema::CodeSynthesisContext::DeducedTemplateArgumentSubstitution, Info);
+ const auto Instantiated =
+ S.instantiateExplicitSpecifier(SubstArgs, ExplicitSpecifier);
+ if (Instantiated.isInvalid()) {
+ Specialization->setInvalidDecl(true);
+ return clang::Sema::TDK_SubstitutionFailure;
+ }
+ SetExplicitSpecifier(Specialization, Instantiated);
+ return clang::Sema::TDK_Success;
}
/// Finish template argument deduction for a function template,
@@ -3733,12 +3727,14 @@ Sema::TemplateDeductionResult Sema::FinishTemplateArgumentDeduction(
}
// We skipped the instantiation of the explicit-specifier during subst the
- // decl before. Now, we try to instantiate it back if the Specialization is a
+ // FD before. So we try to instantiate it back if the `Specialization` is a
// constructor or a conversion.
- if (TDK_Success !=
- tryInstantiateExplicitSpecifier(*this, Specialization, SubstArgs, Info,
- FunctionTemplate, DeducedArgs)) {
- return TDK_SubstitutionFailure;
+ if (isa<CXXConstructorDecl, CXXConversionDecl>(Specialization)) {
+ if (TDK_Success !=
+ resolveExplicitSpecifier(*this, Specialization, SubstArgs, Info,
+ FunctionTemplate, DeducedArgs)) {
+ return TDK_SubstitutionFailure;
+ }
}
if (OriginalCallArgs) {
>From 1159e3774dc1a0c56bbacb26384f1eb17b5f6b02 Mon Sep 17 00:00:00 2001
From: letrec <liuyupei951018 at hotmail.com>
Date: Tue, 31 Oct 2023 01:05:57 +0800
Subject: [PATCH 3/4] unify ES identifier
---
clang/lib/Sema/SemaTemplateDeduction.cpp | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp
index 0218c4319ad01a0..f905391279c02dc 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -3573,8 +3573,8 @@ resolveExplicitSpecifier(Sema &S, FunctionDecl *Specialization,
: cast<CXXConversionDecl>(D)->setExplicitSpecifier(ES);
};
- ExplicitSpecifier ExplicitSpecifier = GetExplicitSpecifier(Specialization);
- Expr *const Expr = ExplicitSpecifier.getExpr();
+ ExplicitSpecifier ES = GetExplicitSpecifier(Specialization);
+ Expr *const Expr = ES.getExpr();
if (!Expr) {
return Sema::TDK_Success;
}
@@ -3587,8 +3587,7 @@ resolveExplicitSpecifier(Sema &S, FunctionDecl *Specialization,
Sema::InstantiatingTemplate Inst(
S, Info.getLocation(), FunctionTemplate, DeducedArgs,
Sema::CodeSynthesisContext::DeducedTemplateArgumentSubstitution, Info);
- const auto Instantiated =
- S.instantiateExplicitSpecifier(SubstArgs, ExplicitSpecifier);
+ const auto Instantiated = S.instantiateExplicitSpecifier(SubstArgs, ES);
if (Instantiated.isInvalid()) {
Specialization->setInvalidDecl(true);
return clang::Sema::TDK_SubstitutionFailure;
>From e6ed716bbd07e3d6705ed4b23aca89b20202bdc6 Mon Sep 17 00:00:00 2001
From: letrec <liuyupei951018 at hotmail.com>
Date: Tue, 31 Oct 2023 23:56:34 +0800
Subject: [PATCH 4/4] add hasErrorOccurred check
---
clang/lib/Sema/SemaTemplateDeduction.cpp | 44 +++++++++++++-----------
1 file changed, 24 insertions(+), 20 deletions(-)
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp
index f905391279c02dc..c2bfa58b2288241 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -3553,15 +3553,14 @@ static unsigned getPackIndexForParam(Sema &S,
llvm_unreachable("parameter index would not be produced from template");
}
-// if `Specialization` is a `CXXConstructorDecl` or `CXXConversionDecl`
-// we try to instantiate and update its explicit specifier after constraint
+// if `Specialization` is a `CXXConstructorDecl` or `CXXConversionDecl`,
+// we'll try to instantiate and update its explicit specifier after constraint
// checking.
-static Sema::TemplateDeductionResult
-resolveExplicitSpecifier(Sema &S, FunctionDecl *Specialization,
- const MultiLevelTemplateArgumentList &SubstArgs,
- TemplateDeductionInfo &Info,
- FunctionTemplateDecl *FunctionTemplate,
- ArrayRef<TemplateArgument> DeducedArgs) {
+static Sema::TemplateDeductionResult instantiateExplicitSpecifierDeferred(
+ Sema &S, FunctionDecl *Specialization,
+ const MultiLevelTemplateArgumentList &SubstArgs,
+ TemplateDeductionInfo &Info, FunctionTemplateDecl *FunctionTemplate,
+ ArrayRef<TemplateArgument> DeducedArgs) {
auto GetExplicitSpecifier = [](FunctionDecl *D) {
return isa<CXXConstructorDecl>(D)
? cast<CXXConstructorDecl>(D)->getExplicitSpecifier()
@@ -3581,19 +3580,24 @@ resolveExplicitSpecifier(Sema &S, FunctionDecl *Specialization,
if (!Expr->isValueDependent()) {
return Sema::TDK_Success;
}
- // TemplateDeclInstantiator::InitFunctionInstantiation set the
- // ActiveInstType to TemplateInstantiation, but we need
- // to enable SFINAE when instantiating an explicit specifier.
+ // The `InstantiatingTemplate` here is used to restore `ActiveInstType` to
+ // `DeducedTemplateArgumentSubstitution` because ActiveInstType was set to
+ // `TemplateInstantiation` in
+ // `TemplateDeclInstantiator::InitFunctionInstantiation`. The real depth of
+ // instantiation should be the same as the depth in
+ // `FinishTemplateArgumentDeduction`.
+ // So we don't check `InstantiatingTemplate::IsValid` here.
Sema::InstantiatingTemplate Inst(
S, Info.getLocation(), FunctionTemplate, DeducedArgs,
Sema::CodeSynthesisContext::DeducedTemplateArgumentSubstitution, Info);
+ Sema::SFINAETrap Trap(S);
const auto Instantiated = S.instantiateExplicitSpecifier(SubstArgs, ES);
- if (Instantiated.isInvalid()) {
+ if (Instantiated.isInvalid() || Trap.hasErrorOccurred()) {
Specialization->setInvalidDecl(true);
- return clang::Sema::TDK_SubstitutionFailure;
+ return Sema::TDK_SubstitutionFailure;
}
SetExplicitSpecifier(Specialization, Instantiated);
- return clang::Sema::TDK_Success;
+ return Sema::TDK_Success;
}
/// Finish template argument deduction for a function template,
@@ -3725,13 +3729,13 @@ Sema::TemplateDeductionResult Sema::FinishTemplateArgumentDeduction(
}
}
- // We skipped the instantiation of the explicit-specifier during subst the
- // FD before. So we try to instantiate it back if the `Specialization` is a
- // constructor or a conversion.
+ // We skipped the instantiation of the explicit-specifier during the
+ // substitution of `FD` before. So, we try to instantiate it back if
+ // `Specialization` is either a constructor or a conversion function.
if (isa<CXXConstructorDecl, CXXConversionDecl>(Specialization)) {
- if (TDK_Success !=
- resolveExplicitSpecifier(*this, Specialization, SubstArgs, Info,
- FunctionTemplate, DeducedArgs)) {
+ if (TDK_Success != instantiateExplicitSpecifierDeferred(
+ *this, Specialization, SubstArgs, Info,
+ FunctionTemplate, DeducedArgs)) {
return TDK_SubstitutionFailure;
}
}
More information about the cfe-commits
mailing list