Skip to content

Commit

Permalink
[clang] NFCI: use TemplateArgumentLoc for NTTP DefaultArgument
Browse files Browse the repository at this point in the history
This is an enabler for a future patch.
  • Loading branch information
mizvekov committed May 21, 2024
1 parent 219ea26 commit 984ac61
Show file tree
Hide file tree
Showing 25 changed files with 99 additions and 74 deletions.
3 changes: 2 additions & 1 deletion clang-tools-extra/clangd/Hover.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,8 @@ fetchTemplateParameters(const TemplateParameterList *Params,
if (NTTP->hasDefaultArgument()) {
P.Default.emplace();
llvm::raw_string_ostream Out(*P.Default);
NTTP->getDefaultArgument()->printPretty(Out, nullptr, PP);
NTTP->getDefaultArgument().getArgument().print(PP, Out,
/*IncludeType=*/false);
}
} else if (const auto *TTPD = dyn_cast<TemplateTemplateParmDecl>(Param)) {
P.Type = printType(TTPD, PP);
Expand Down
6 changes: 3 additions & 3 deletions clang/include/clang/AST/ASTNodeTraverser.h
Original file line number Diff line number Diff line change
Expand Up @@ -704,9 +704,9 @@ class ASTNodeTraverser
if (const auto *E = D->getPlaceholderTypeConstraint())
Visit(E);
if (D->hasDefaultArgument())
Visit(D->getDefaultArgument(), SourceRange(),
D->getDefaultArgStorage().getInheritedFrom(),
D->defaultArgumentWasInherited() ? "inherited from" : "previous");
dumpTemplateArgumentLoc(
D->getDefaultArgument(), D->getDefaultArgStorage().getInheritedFrom(),
D->defaultArgumentWasInherited() ? "inherited from" : "previous");
}

void VisitTemplateTemplateParmDecl(const TemplateTemplateParmDecl *D) {
Expand Down
11 changes: 8 additions & 3 deletions clang/include/clang/AST/DeclTemplate.h
Original file line number Diff line number Diff line change
Expand Up @@ -1360,7 +1360,8 @@ class NonTypeTemplateParmDecl final

/// The default template argument, if any, and whether or not
/// it was inherited.
using DefArgStorage = DefaultArgStorage<NonTypeTemplateParmDecl, Expr *>;
using DefArgStorage =
DefaultArgStorage<NonTypeTemplateParmDecl, TemplateArgumentLoc *>;
DefArgStorage DefaultArgument;

// FIXME: Collapse this into TemplateParamPosition; or, just move depth/index
Expand Down Expand Up @@ -1430,7 +1431,10 @@ class NonTypeTemplateParmDecl final
bool hasDefaultArgument() const { return DefaultArgument.isSet(); }

/// Retrieve the default argument, if any.
Expr *getDefaultArgument() const { return DefaultArgument.get(); }
const TemplateArgumentLoc &getDefaultArgument() const {
static const TemplateArgumentLoc NoneLoc;
return DefaultArgument.isSet() ? *DefaultArgument.get() : NoneLoc;
}

/// Retrieve the location of the default argument, if any.
SourceLocation getDefaultArgumentLoc() const;
Expand All @@ -1444,7 +1448,8 @@ class NonTypeTemplateParmDecl final
/// Set the default argument for this template parameter, and
/// whether that default argument was inherited from another
/// declaration.
void setDefaultArgument(Expr *DefArg) { DefaultArgument.set(DefArg); }
void setDefaultArgument(const ASTContext &C,
const TemplateArgumentLoc &DefArg);
void setInheritedDefaultArgument(const ASTContext &C,
NonTypeTemplateParmDecl *Parm) {
DefaultArgument.setInherited(C, Parm);
Expand Down
2 changes: 1 addition & 1 deletion clang/include/clang/AST/RecursiveASTVisitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -2320,7 +2320,7 @@ DEF_TRAVERSE_DECL(NonTypeTemplateParmDecl, {
// A non-type template parameter, e.g. "S" in template<int S> class Foo ...
TRY_TO(TraverseDeclaratorHelper(D));
if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited())
TRY_TO(TraverseStmt(D->getDefaultArgument()));
TRY_TO(TraverseTemplateArgumentLoc(D->getDefaultArgument()));
})

DEF_TRAVERSE_DECL(ParmVarDecl, {
Expand Down
6 changes: 4 additions & 2 deletions clang/lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6503,8 +6503,10 @@ bool ASTContext::isSameDefaultTemplateArgument(const NamedDecl *X,
if (!NTTPX->hasDefaultArgument() || !NTTPY->hasDefaultArgument())
return false;

Expr *DefaultArgumentX = NTTPX->getDefaultArgument()->IgnoreImpCasts();
Expr *DefaultArgumentY = NTTPY->getDefaultArgument()->IgnoreImpCasts();
Expr *DefaultArgumentX =
NTTPX->getDefaultArgument().getArgument().getAsExpr()->IgnoreImpCasts();
Expr *DefaultArgumentY =
NTTPY->getDefaultArgument().getArgument().getAsExpr()->IgnoreImpCasts();
llvm::FoldingSetNodeID XID, YID;
DefaultArgumentX->Profile(XID, *this, /*Canonical=*/true);
DefaultArgumentY->Profile(YID, *this, /*Canonical=*/true);
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/AST/ASTDiagnostic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1238,7 +1238,7 @@ class TemplateDiff {
E = Iter->getAsExpr();
}
} else if (!Default->isParameterPack()) {
E = Default->getDefaultArgument();
E = Default->getDefaultArgument().getArgument().getAsExpr();
}

if (!Iter.hasDesugaredTA()) return;
Expand Down
5 changes: 3 additions & 2 deletions clang/lib/AST/ASTImporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5949,10 +5949,11 @@ ASTNodeImporter::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) {
return ToD;

if (D->hasDefaultArgument()) {
ExpectedExpr ToDefaultArgOrErr = import(D->getDefaultArgument());
Expected<TemplateArgumentLoc> ToDefaultArgOrErr =
import(D->getDefaultArgument());
if (!ToDefaultArgOrErr)
return ToDefaultArgOrErr.takeError();
ToD->setDefaultArgument(*ToDefaultArgOrErr);
ToD->setDefaultArgument(Importer.getToContext(), *ToDefaultArgOrErr);
}

return ToD;
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/AST/DeclPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1898,7 +1898,7 @@ void DeclPrinter::VisitNonTypeTemplateParmDecl(

if (NTTP->hasDefaultArgument()) {
Out << " = ";
NTTP->getDefaultArgument()->printPretty(Out, nullptr, Policy, Indentation,
"\n", &Context);
NTTP->getDefaultArgument().getArgument().print(Policy, Out,
/*IncludeType=*/false);
}
}
15 changes: 11 additions & 4 deletions clang/lib/AST/DeclTemplate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -795,14 +795,21 @@ NonTypeTemplateParmDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID,
SourceRange NonTypeTemplateParmDecl::getSourceRange() const {
if (hasDefaultArgument() && !defaultArgumentWasInherited())
return SourceRange(getOuterLocStart(),
getDefaultArgument()->getSourceRange().getEnd());
getDefaultArgument().getSourceRange().getEnd());
return DeclaratorDecl::getSourceRange();
}

SourceLocation NonTypeTemplateParmDecl::getDefaultArgumentLoc() const {
return hasDefaultArgument()
? getDefaultArgument()->getSourceRange().getBegin()
: SourceLocation();
return hasDefaultArgument() ? getDefaultArgument().getSourceRange().getBegin()
: SourceLocation();
}

void NonTypeTemplateParmDecl::setDefaultArgument(
const ASTContext &C, const TemplateArgumentLoc &DefArg) {
if (DefArg.getArgument().isNull())
DefaultArgument.set(nullptr);
else
DefaultArgument.set(new (C) TemplateArgumentLoc(DefArg));
}

//===----------------------------------------------------------------------===//
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/AST/JSONNodeDumper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1044,7 +1044,7 @@ void JSONNodeDumper::VisitNonTypeTemplateParmDecl(

if (D->hasDefaultArgument())
JOS.attributeObject("defaultArg", [=] {
Visit(D->getDefaultArgument(), SourceRange(),
Visit(D->getDefaultArgument().getArgument(), SourceRange(),
D->getDefaultArgStorage().getInheritedFrom(),
D->defaultArgumentWasInherited() ? "inherited from" : "previous");
});
Expand Down
7 changes: 5 additions & 2 deletions clang/lib/AST/ODRDiagsEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1523,8 +1523,11 @@ bool ODRDiagsEmitter::diagnoseMismatch(
}

if (HasFirstDefaultArgument && HasSecondDefaultArgument) {
Expr *FirstDefaultArgument = FirstNTTPD->getDefaultArgument();
Expr *SecondDefaultArgument = SecondNTTPD->getDefaultArgument();
TemplateArgument FirstDefaultArgument =
FirstNTTPD->getDefaultArgument().getArgument();
TemplateArgument SecondDefaultArgument =
SecondNTTPD->getDefaultArgument().getArgument();

if (computeODRHash(FirstDefaultArgument) !=
computeODRHash(SecondDefaultArgument)) {
DiagTemplateError(FunctionTemplateParameterDifferentDefaultArgument)
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/AST/ODRHash.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -480,7 +480,7 @@ class ODRDeclVisitor : public ConstDeclVisitor<ODRDeclVisitor> {
D->hasDefaultArgument() && !D->defaultArgumentWasInherited();
Hash.AddBoolean(hasDefaultArgument);
if (hasDefaultArgument) {
AddStmt(D->getDefaultArgument());
AddTemplateArgument(D->getDefaultArgument().getArgument());
}
Hash.AddBoolean(D->isParameterPack());

Expand Down
5 changes: 3 additions & 2 deletions clang/lib/AST/TypePrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2281,8 +2281,9 @@ bool clang::isSubstitutedDefaultArgument(ASTContext &Ctx, TemplateArgument Arg,
Ctx, Arg, TTPD->getDefaultArgument().getArgument(), Args, Depth);
} else if (auto *NTTPD = dyn_cast<NonTypeTemplateParmDecl>(Param)) {
return NTTPD->hasDefaultArgument() &&
isSubstitutedTemplateArgument(Ctx, Arg, NTTPD->getDefaultArgument(),
Args, Depth);
isSubstitutedTemplateArgument(
Ctx, Arg, NTTPD->getDefaultArgument().getArgument(), Args,
Depth);
}
return false;
}
Expand Down
5 changes: 3 additions & 2 deletions clang/lib/ExtractAPI/DeclarationFragments.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1023,8 +1023,9 @@ DeclarationFragmentsBuilder::getFragmentsForTemplateParameters(
if (NTP->hasDefaultArgument()) {
SmallString<8> ExprStr;
raw_svector_ostream Output(ExprStr);
NTP->getDefaultArgument()->printPretty(
Output, nullptr, NTP->getASTContext().getPrintingPolicy());
NTP->getDefaultArgument().getArgument().print(
NTP->getASTContext().getPrintingPolicy(), Output,
/*IncludeType=*/false);
Fragments.append(" = ", DeclarationFragments::FragmentKind::Text)
.append(ExprStr, DeclarationFragments::FragmentKind::Text);
}
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/Index/IndexDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -711,7 +711,8 @@ class IndexingDeclVisitor : public ConstDeclVisitor<IndexingDeclVisitor, bool> {
} else if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(TP)) {
IndexCtx.indexTypeSourceInfo(NTTP->getTypeSourceInfo(), Parent);
if (NTTP->hasDefaultArgument())
IndexCtx.indexBody(NTTP->getDefaultArgument(), Parent);
handleTemplateArgumentLoc(NTTP->getDefaultArgument(), Parent,
TP->getLexicalDeclContext());
} else if (const auto *TTPD = dyn_cast<TemplateTemplateParmDecl>(TP)) {
if (TTPD->hasDefaultArgument())
handleTemplateArgumentLoc(TTPD->getDefaultArgument(), Parent,
Expand Down
10 changes: 6 additions & 4 deletions clang/lib/Sema/HLSLExternalSemaSource.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -442,10 +442,12 @@ void HLSLExternalSemaSource::defineHLSLVectorAlias() {
AST, HLSLNamespace, SourceLocation(), SourceLocation(), 0, 1,
&AST.Idents.get("element_count", tok::TokenKind::identifier), AST.IntTy,
false, AST.getTrivialTypeSourceInfo(AST.IntTy));
Expr *LiteralExpr =
IntegerLiteral::Create(AST, llvm::APInt(AST.getIntWidth(AST.IntTy), 4),
AST.IntTy, SourceLocation());
SizeParam->setDefaultArgument(LiteralExpr);
llvm::APInt Val(AST.getIntWidth(AST.IntTy), 4);
TemplateArgument Default(AST, llvm::APSInt(std::move(Val)), AST.IntTy,
/*IsDefaulted=*/true);
SizeParam->setDefaultArgument(
AST, SemaPtr->getTrivialTemplateArgumentLoc(Default, AST.IntTy,
SourceLocation(), SizeParam));
TemplateParams.emplace_back(SizeParam);

auto *ParamList =
Expand Down
46 changes: 22 additions & 24 deletions clang/lib/Sema/SemaTemplate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1599,7 +1599,9 @@ NamedDecl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D,
if (DiagnoseUnexpandedParameterPack(Default, UPPC_DefaultArgument))
return Param;

Param->setDefaultArgument(Default);
Param->setDefaultArgument(
Context, getTrivialTemplateArgumentLoc(TemplateArgument(Default),
QualType(), SourceLocation()));
}

return Param;
Expand Down Expand Up @@ -3630,9 +3632,9 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,

// Check the presence of a default argument here.
if (NewNonTypeParm->hasDefaultArgument() &&
DiagnoseDefaultTemplateArgument(*this, TPC,
NewNonTypeParm->getLocation(),
NewNonTypeParm->getDefaultArgument()->getSourceRange())) {
DiagnoseDefaultTemplateArgument(
*this, TPC, NewNonTypeParm->getLocation(),
NewNonTypeParm->getDefaultArgument().getSourceRange())) {
NewNonTypeParm->removeDefaultArgument();
}

Expand Down Expand Up @@ -6107,16 +6109,17 @@ static bool SubstDefaultTemplateArgument(
/// parameters that precede \p Param in the template parameter list.
///
/// \returns the substituted template argument, or NULL if an error occurred.
static ExprResult SubstDefaultTemplateArgument(
static bool SubstDefaultTemplateArgument(
Sema &SemaRef, TemplateDecl *Template, SourceLocation TemplateLoc,
SourceLocation RAngleLoc, NonTypeTemplateParmDecl *Param,
ArrayRef<TemplateArgument> SugaredConverted,
ArrayRef<TemplateArgument> CanonicalConverted) {
ArrayRef<TemplateArgument> CanonicalConverted,
TemplateArgumentLoc &Output) {
Sema::InstantiatingTemplate Inst(SemaRef, TemplateLoc, Param, Template,
SugaredConverted,
SourceRange(TemplateLoc, RAngleLoc));
if (Inst.isInvalid())
return ExprError();
return true;

// Only substitute for the innermost template argument list.
MultiLevelTemplateArgumentList TemplateArgLists(Template, SugaredConverted,
Expand All @@ -6127,7 +6130,8 @@ static ExprResult SubstDefaultTemplateArgument(
Sema::ContextRAII SavedContext(SemaRef, Template->getDeclContext());
EnterExpressionEvaluationContext ConstantEvaluated(
SemaRef, Sema::ExpressionEvaluationContext::ConstantEvaluated);
return SemaRef.SubstExpr(Param->getDefaultArgument(), TemplateArgLists);
return SemaRef.SubstTemplateArgument(Param->getDefaultArgument(),
TemplateArgLists, Output);
}

/// Substitute template arguments into the default template argument for
Expand Down Expand Up @@ -6219,14 +6223,12 @@ TemplateArgumentLoc Sema::SubstDefaultTemplateArgumentIfAvailable(
return TemplateArgumentLoc();

HasDefaultArg = true;
ExprResult Arg = SubstDefaultTemplateArgument(
*this, Template, TemplateLoc, RAngleLoc, NonTypeParm, SugaredConverted,
CanonicalConverted);
if (Arg.isInvalid())
TemplateArgumentLoc Output;
if (SubstDefaultTemplateArgument(*this, Template, TemplateLoc, RAngleLoc,
NonTypeParm, SugaredConverted,
CanonicalConverted, Output))
return TemplateArgumentLoc();

Expr *ArgE = Arg.getAs<Expr>();
return TemplateArgumentLoc(TemplateArgument(ArgE), ArgE);
return Output;
}

TemplateTemplateParmDecl *TempTempParm
Expand Down Expand Up @@ -6803,14 +6805,10 @@ bool Sema::CheckTemplateArgumentList(
return diagnoseMissingArgument(*this, TemplateLoc, Template, NTTP,
NewArgs);

ExprResult E = SubstDefaultTemplateArgument(
*this, Template, TemplateLoc, RAngleLoc, NTTP, SugaredConverted,
CanonicalConverted);
if (E.isInvalid())
if (SubstDefaultTemplateArgument(*this, Template, TemplateLoc, RAngleLoc,
NTTP, SugaredConverted,
CanonicalConverted, Arg))
return true;

Expr *Ex = E.getAs<Expr>();
Arg = TemplateArgumentLoc(TemplateArgument(Ex), Ex);
} else {
TemplateTemplateParmDecl *TempParm
= cast<TemplateTemplateParmDecl>(*Param);
Expand Down Expand Up @@ -9523,10 +9521,10 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
}
} else if (NonTypeTemplateParmDecl *NTTP
= dyn_cast<NonTypeTemplateParmDecl>(Param)) {
if (Expr *DefArg = NTTP->getDefaultArgument()) {
if (NTTP->hasDefaultArgument()) {
Diag(NTTP->getDefaultArgumentLoc(),
diag::err_default_arg_in_partial_spec)
<< DefArg->getSourceRange();
<< NTTP->getDefaultArgument().getSourceRange();
NTTP->removeDefaultArgument();
}
} else {
Expand Down
10 changes: 5 additions & 5 deletions clang/lib/Sema/SemaTemplateDeduction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -536,14 +536,14 @@ static NamedDecl *getTemplateParameterWithDefault(Sema &S, NamedDecl *A,
}
case Decl::NonTypeTemplateParm: {
auto *T = cast<NonTypeTemplateParmDecl>(A);
// FIXME: Ditto, as above for TemplateTypeParm case.
if (T->isParameterPack())
return A;
auto *R = NonTypeTemplateParmDecl::Create(
S.Context, A->getDeclContext(), SourceLocation(), SourceLocation(),
T->getDepth(), T->getIndex(), T->getIdentifier(), T->getType(),
/*ParameterPack=*/false, T->getTypeSourceInfo());
R->setDefaultArgument(Default.getAsExpr());
T->isParameterPack(), T->getTypeSourceInfo());
R->setDefaultArgument(S.Context,
S.getTrivialTemplateArgumentLoc(
Default, Default.getNonTypeTemplateArgumentType(),
SourceLocation()));
if (auto *PTC = T->getPlaceholderTypeConstraint())
R->setPlaceholderTypeConstraint(PTC);
return R;
Expand Down
7 changes: 4 additions & 3 deletions clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3123,9 +3123,10 @@ Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl(
if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited()) {
EnterExpressionEvaluationContext ConstantEvaluated(
SemaRef, Sema::ExpressionEvaluationContext::ConstantEvaluated);
ExprResult Value = SemaRef.SubstExpr(D->getDefaultArgument(), TemplateArgs);
if (!Value.isInvalid())
Param->setDefaultArgument(Value.get());
TemplateArgumentLoc Result;
if (!SemaRef.SubstTemplateArgument(D->getDefaultArgument(), TemplateArgs,
Result))
Param->setDefaultArgument(SemaRef.Context, Result);
}

// Introduce this template parameter's instantiation into the instantiation
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/Serialization/ASTReaderDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2717,7 +2717,8 @@ void ASTDeclReader::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) {
// Rest of NonTypeTemplateParmDecl.
D->ParameterPack = Record.readInt();
if (Record.readInt())
D->setDefaultArgument(Record.readExpr());
D->setDefaultArgument(Reader.getContext(),
Record.readTemplateArgumentLoc());
}
}

Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Serialization/ASTWriterDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1941,7 +1941,7 @@ void ASTDeclWriter::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) {
!D->defaultArgumentWasInherited();
Record.push_back(OwnsDefaultArg);
if (OwnsDefaultArg)
Record.AddStmt(D->getDefaultArgument());
Record.AddTemplateArgumentLoc(D->getDefaultArgument());
Code = serialization::DECL_NON_TYPE_TEMPLATE_PARM;
}
}
Expand Down
4 changes: 2 additions & 2 deletions clang/test/AST/ast-dump-decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -459,7 +459,7 @@ namespace testClassTemplateDecl {

// CHECK: ClassTemplateDecl 0x{{.+}} <{{.+}}:[[@LINE-148]]:3, col:31> col:31 TestTemplateDefaultNonType{{$}}
// CHECK-NEXT: |-NonTypeTemplateParmDecl 0x{{.+}} <col:12, col:20> col:16 'int' depth 0 index 0 I{{$}}
// CHECK-NEXT: | `-TemplateArgument expr{{$}}
// CHECK-NEXT: | `-TemplateArgument <col:20> expr{{$}}
// CHECK-NEXT: | `-IntegerLiteral 0x{{.+}} <col:20> 'int' 42{{$}}
// CHECK-NEXT: `-CXXRecordDecl 0x{{.+}} <col:24, col:31> col:31 struct TestTemplateDefaultNonType{{$}}

Expand Down Expand Up @@ -671,7 +671,7 @@ namespace TestNonTypeTemplateParmDecl {
// CHECK: NamespaceDecl{{.*}} TestNonTypeTemplateParmDecl
// CHECK-NEXT: FunctionTemplateDecl
// CHECK-NEXT: NonTypeTemplateParmDecl{{.*}} 'int' depth 0 index 0 I
// CHECK-NEXT: TemplateArgument expr
// CHECK-NEXT: TemplateArgument {{.*}} expr
// CHECK-NEXT: IntegerLiteral{{.*}} 'int' 1
// CHECK-NEXT: NonTypeTemplateParmDecl{{.*}} 'int' depth 0 index 1 ... J

Expand Down
Loading

0 comments on commit 984ac61

Please sign in to comment.