Skip to content

Commit a1fe052

Browse files
committed
[clang] Preserve Qualifiers and type sugar in TemplateNames
This patch improves the preservation of qualifiers and loss of type sugar in TemplateNames. This problem is analogous to https://reviews.llvm.org/D112374 and this patch takes a very similar approach to that patch, except the impact here is much lesser. When a TemplateName was written bare, without qualifications, we wouldn't produce a QualifiedTemplate which could be used to disambiguate it from a Canonical TemplateName. This had effects in the TemplateName printer, which had workarounds to deal with this, and wouldn't print the TemplateName as-written in most situations. There are also some related fixes to help preserve this type sugar along the way into diagnostics, so that this patch can be properly tested. - Fix dropping the template keyword. - Fix type deduction to preserve sugar in TST TemplateNames.
1 parent 031e7c2 commit a1fe052

36 files changed

+222
-147
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -802,6 +802,8 @@ Bug Fixes to AST Handling
802802
- Clang now properly preserves ``FoundDecls`` within a ``ConceptReference``. (#GH82628)
803803
- The presence of the ``typename`` keyword is now stored in ``TemplateTemplateParmDecl``.
804804
- Fixed malformed AST generated for anonymous union access in templates. (#GH90842)
805+
- Improved preservation of qualifiers and sugar in TemplateNames, including
806+
template keyword.
805807

806808
Miscellaneous Bug Fixes
807809
^^^^^^^^^^^^^^^^^^^^^^^

clang/include/clang/AST/TemplateName.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -332,7 +332,7 @@ class TemplateName {
332332
/// unexpanded parameter pack (for C++0x variadic templates).
333333
bool containsUnexpandedParameterPack() const;
334334

335-
enum class Qualified { None, AsWritten, Fully };
335+
enum class Qualified { None, AsWritten };
336336
/// Print the template name.
337337
///
338338
/// \param OS the output stream to which the template name will be

clang/include/clang/Sema/Sema.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8988,6 +8988,9 @@ class Sema final : public SemaBase {
89888988
const TemplateArgumentListInfo *TemplateArgs);
89898989

89908990
void diagnoseMissingTemplateArguments(TemplateName Name, SourceLocation Loc);
8991+
void diagnoseMissingTemplateArguments(const CXXScopeSpec &SS,
8992+
bool TemplateKeyword, TemplateDecl *TD,
8993+
SourceLocation Loc);
89918994

89928995
ExprResult BuildTemplateIdExpr(const CXXScopeSpec &SS,
89938996
SourceLocation TemplateKWLoc, LookupResult &R,

clang/lib/AST/ASTContext.cpp

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5006,9 +5006,6 @@ ASTContext::getTemplateSpecializationType(TemplateName Template,
50065006
QualType Underlying) const {
50075007
assert(!Template.getAsDependentTemplateName() &&
50085008
"No dependent template names here!");
5009-
// Look through qualified template names.
5010-
if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName())
5011-
Template = QTN->getUnderlyingTemplate();
50125009

50135010
const auto *TD = Template.getAsTemplateDecl();
50145011
bool IsTypeAlias = TD && TD->isTypeAlias();
@@ -5044,10 +5041,6 @@ QualType ASTContext::getCanonicalTemplateSpecializationType(
50445041
assert(!Template.getAsDependentTemplateName() &&
50455042
"No dependent template names here!");
50465043

5047-
// Look through qualified template names.
5048-
if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName())
5049-
Template = TemplateName(QTN->getUnderlyingTemplate());
5050-
50515044
// Build the canonical template specialization type.
50525045
TemplateName CanonTemplate = getCanonicalTemplateName(Template);
50535046
bool AnyNonCanonArgs = false;
@@ -5262,10 +5255,12 @@ TemplateArgument ASTContext::getInjectedTemplateArg(NamedDecl *Param) {
52625255
Arg = TemplateArgument(E);
52635256
} else {
52645257
auto *TTP = cast<TemplateTemplateParmDecl>(Param);
5258+
TemplateName Name = getQualifiedTemplateName(
5259+
nullptr, /*TemplateKeyword=*/false, TemplateName(TTP));
52655260
if (TTP->isParameterPack())
5266-
Arg = TemplateArgument(TemplateName(TTP), std::optional<unsigned>());
5261+
Arg = TemplateArgument(Name, std::optional<unsigned>());
52675262
else
5268-
Arg = TemplateArgument(TemplateName(TTP));
5263+
Arg = TemplateArgument(Name);
52695264
}
52705265

52715266
if (Param->isTemplateParameterPack())
@@ -9304,7 +9299,8 @@ TemplateName ASTContext::getAssumedTemplateName(DeclarationName Name) const {
93049299
TemplateName ASTContext::getQualifiedTemplateName(NestedNameSpecifier *NNS,
93059300
bool TemplateKeyword,
93069301
TemplateName Template) const {
9307-
assert(NNS && "Missing nested-name-specifier in qualified template name");
9302+
assert(Template.getKind() == TemplateName::Template ||
9303+
Template.getKind() == TemplateName::UsingTemplate);
93089304

93099305
// FIXME: Canonicalization?
93109306
llvm::FoldingSetNodeID ID;

clang/lib/AST/DeclTemplate.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -627,9 +627,10 @@ ClassTemplateDecl::getInjectedClassNameSpecialization() {
627627
TemplateParameterList *Params = getTemplateParameters();
628628
SmallVector<TemplateArgument, 16> TemplateArgs;
629629
Context.getInjectedTemplateArgs(Params, TemplateArgs);
630-
CommonPtr->InjectedClassNameType
631-
= Context.getTemplateSpecializationType(TemplateName(this),
632-
TemplateArgs);
630+
TemplateName Name = Context.getQualifiedTemplateName(
631+
/*NNS=*/nullptr, /*TemplateKeyword=*/false, TemplateName(this));
632+
CommonPtr->InjectedClassNameType =
633+
Context.getTemplateSpecializationType(Name, TemplateArgs);
633634
return CommonPtr->InjectedClassNameType;
634635
}
635636

clang/lib/AST/ODRHash.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,10 +146,17 @@ void ODRHash::AddTemplateName(TemplateName Name) {
146146
case TemplateName::Template:
147147
AddDecl(Name.getAsTemplateDecl());
148148
break;
149+
case TemplateName::QualifiedTemplate: {
150+
QualifiedTemplateName *QTN = Name.getAsQualifiedTemplateName();
151+
if (NestedNameSpecifier *NNS = QTN->getQualifier())
152+
AddNestedNameSpecifier(NNS);
153+
AddBoolean(QTN->hasTemplateKeyword());
154+
AddTemplateName(QTN->getUnderlyingTemplate());
155+
break;
156+
}
149157
// TODO: Support these cases.
150158
case TemplateName::OverloadedTemplate:
151159
case TemplateName::AssumedTemplate:
152-
case TemplateName::QualifiedTemplate:
153160
case TemplateName::DependentTemplate:
154161
case TemplateName::SubstTemplateTemplateParm:
155162
case TemplateName::SubstTemplateTemplateParmPack:

clang/lib/AST/TemplateBase.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -547,7 +547,7 @@ void TemplateArgument::print(const PrintingPolicy &Policy, raw_ostream &Out,
547547
const auto *TTP = cast<TemplateTemplateParmDecl>(TD);
548548
Out << "template-parameter-" << TTP->getDepth() << "-" << TTP->getIndex();
549549
} else {
550-
TN.print(Out, Policy, TemplateName::Qualified::Fully);
550+
TN.print(Out, Policy);
551551
}
552552
break;
553553
}

clang/lib/AST/TemplateName.cpp

Lines changed: 30 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -235,8 +235,8 @@ TemplateNameDependence TemplateName::getDependence() const {
235235
auto D = TemplateNameDependence::None;
236236
switch (getKind()) {
237237
case TemplateName::NameKind::QualifiedTemplate:
238-
D |= toTemplateNameDependence(
239-
getAsQualifiedTemplateName()->getQualifier()->getDependence());
238+
if (NestedNameSpecifier *NNS = getAsQualifiedTemplateName()->getQualifier())
239+
D |= toTemplateNameDependence(NNS->getDependence());
240240
break;
241241
case TemplateName::NameKind::DependentTemplate:
242242
D |= toTemplateNameDependence(
@@ -292,9 +292,8 @@ void TemplateName::Profile(llvm::FoldingSetNodeID &ID) {
292292

293293
void TemplateName::print(raw_ostream &OS, const PrintingPolicy &Policy,
294294
Qualified Qual) const {
295-
auto Kind = getKind();
296-
TemplateDecl *Template = nullptr;
297-
if (Kind == TemplateName::Template || Kind == TemplateName::UsingTemplate) {
295+
if (NameKind Kind = getKind();
296+
Kind == TemplateName::Template || Kind == TemplateName::UsingTemplate) {
298297
// After `namespace ns { using std::vector }`, what is the fully-qualified
299298
// name of the UsingTemplateName `vector` within ns?
300299
//
@@ -304,46 +303,43 @@ void TemplateName::print(raw_ostream &OS, const PrintingPolicy &Policy,
304303
// Similar to the UsingType behavior, using declarations are used to import
305304
// names more often than to export them, thus using the original name is
306305
// most useful in this case.
307-
Template = getAsTemplateDecl();
308-
}
309-
310-
if (Template)
311-
if (Policy.CleanUglifiedParameters &&
312-
isa<TemplateTemplateParmDecl>(Template) && Template->getIdentifier())
313-
OS << Template->getIdentifier()->deuglifiedName();
314-
else if (Qual == Qualified::Fully &&
315-
getDependence() !=
316-
TemplateNameDependenceScope::DependentInstantiation)
317-
Template->printQualifiedName(OS, Policy);
318-
else
306+
TemplateDecl *Template = getAsTemplateDecl();
307+
if (Qual == Qualified::None)
319308
OS << *Template;
320-
else if (QualifiedTemplateName *QTN = getAsQualifiedTemplateName()) {
321-
if (Qual == Qualified::Fully &&
322-
getDependence() !=
323-
TemplateNameDependenceScope::DependentInstantiation) {
324-
QTN->getUnderlyingTemplate().getAsTemplateDecl()->printQualifiedName(
325-
OS, Policy);
326-
return;
327-
}
328-
if (Qual == Qualified::AsWritten)
329-
QTN->getQualifier()->print(OS, Policy);
309+
else
310+
Template->printQualifiedName(OS, Policy);
311+
} else if (QualifiedTemplateName *QTN = getAsQualifiedTemplateName()) {
312+
if (NestedNameSpecifier *NNS = QTN->getQualifier();
313+
Qual != Qualified::None && NNS)
314+
NNS->print(OS, Policy);
330315
if (QTN->hasTemplateKeyword())
331316
OS << "template ";
332-
OS << *QTN->getUnderlyingTemplate().getAsTemplateDecl();
317+
318+
TemplateName Underlying = QTN->getUnderlyingTemplate();
319+
assert(Underlying.getKind() == TemplateName::Template ||
320+
Underlying.getKind() == TemplateName::UsingTemplate);
321+
322+
TemplateDecl *UTD = Underlying.getAsTemplateDecl();
323+
if (IdentifierInfo *II = UTD->getIdentifier();
324+
Policy.CleanUglifiedParameters && II &&
325+
isa<TemplateTemplateParmDecl>(UTD))
326+
OS << II->deuglifiedName();
327+
else
328+
OS << *UTD;
333329
} else if (DependentTemplateName *DTN = getAsDependentTemplateName()) {
334-
if (Qual == Qualified::AsWritten && DTN->getQualifier())
335-
DTN->getQualifier()->print(OS, Policy);
330+
if (NestedNameSpecifier *NNS = DTN->getQualifier())
331+
NNS->print(OS, Policy);
336332
OS << "template ";
337333

338334
if (DTN->isIdentifier())
339335
OS << DTN->getIdentifier()->getName();
340336
else
341337
OS << "operator " << getOperatorSpelling(DTN->getOperator());
342-
} else if (SubstTemplateTemplateParmStorage *subst
343-
= getAsSubstTemplateTemplateParm()) {
338+
} else if (SubstTemplateTemplateParmStorage *subst =
339+
getAsSubstTemplateTemplateParm()) {
344340
subst->getReplacement().print(OS, Policy, Qual);
345-
} else if (SubstTemplateTemplateParmPackStorage *SubstPack
346-
= getAsSubstTemplateTemplateParmPack())
341+
} else if (SubstTemplateTemplateParmPackStorage *SubstPack =
342+
getAsSubstTemplateTemplateParmPack())
347343
OS << *SubstPack->getParameterPack();
348344
else if (AssumedTemplateStorage *Assumed = getAsAssumedTemplateName()) {
349345
Assumed->getDeclName().print(OS, Policy);

clang/lib/AST/TextNodeDumper.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1988,15 +1988,15 @@ void TextNodeDumper::VisitAutoType(const AutoType *T) {
19881988

19891989
void TextNodeDumper::VisitDeducedTemplateSpecializationType(
19901990
const DeducedTemplateSpecializationType *T) {
1991-
if (T->getTemplateName().getKind() == TemplateName::UsingTemplate)
1991+
if (T->getTemplateName().getAsUsingShadowDecl())
19921992
OS << " using";
19931993
}
19941994

19951995
void TextNodeDumper::VisitTemplateSpecializationType(
19961996
const TemplateSpecializationType *T) {
19971997
if (T->isTypeAlias())
19981998
OS << " alias";
1999-
if (T->getTemplateName().getKind() == TemplateName::UsingTemplate)
1999+
if (T->getTemplateName().getAsUsingShadowDecl())
20002000
OS << " using";
20012001
OS << " ";
20022002
T->getTemplateName().dump(OS);

clang/lib/AST/Type.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4251,7 +4251,8 @@ TemplateSpecializationType::TemplateSpecializationType(
42514251
assert((T.getKind() == TemplateName::Template ||
42524252
T.getKind() == TemplateName::SubstTemplateTemplateParm ||
42534253
T.getKind() == TemplateName::SubstTemplateTemplateParmPack ||
4254-
T.getKind() == TemplateName::UsingTemplate) &&
4254+
T.getKind() == TemplateName::UsingTemplate ||
4255+
T.getKind() == TemplateName::QualifiedTemplate) &&
42554256
"Unexpected template name for TemplateSpecializationType");
42564257

42574258
auto *TemplateArgs = reinterpret_cast<TemplateArgument *>(this + 1);

clang/lib/AST/TypePrinter.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1586,14 +1586,14 @@ void TypePrinter::printTemplateId(const TemplateSpecializationType *T,
15861586
IncludeStrongLifetimeRAII Strong(Policy);
15871587

15881588
TemplateDecl *TD = T->getTemplateName().getAsTemplateDecl();
1589-
// FIXME: Null TD never excercised in test suite.
1589+
// FIXME: Null TD never exercised in test suite.
15901590
if (FullyQualify && TD) {
15911591
if (!Policy.SuppressScope)
15921592
AppendScope(TD->getDeclContext(), OS, TD->getDeclName());
15931593

15941594
OS << TD->getName();
15951595
} else {
1596-
T->getTemplateName().print(OS, Policy);
1596+
T->getTemplateName().print(OS, Policy, TemplateName::Qualified::None);
15971597
}
15981598

15991599
DefaultTemplateArgsPolicyRAII TemplateArgs(Policy);

clang/lib/Sema/SemaDecl.cpp

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -538,8 +538,9 @@ ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc,
538538
} else if (AllowDeducedTemplate) {
539539
if (auto *TD = getAsTypeTemplateDecl(IIDecl)) {
540540
assert(!FoundUsingShadow || FoundUsingShadow->getTargetDecl() == TD);
541-
TemplateName Template =
542-
FoundUsingShadow ? TemplateName(FoundUsingShadow) : TemplateName(TD);
541+
TemplateName Template = Context.getQualifiedTemplateName(
542+
SS ? SS->getScopeRep() : nullptr, /*TemplateKeyword=*/false,
543+
FoundUsingShadow ? TemplateName(FoundUsingShadow) : TemplateName(TD));
543544
T = Context.getDeducedTemplateSpecializationType(Template, QualType(),
544545
false);
545546
// Don't wrap in a further UsingType.
@@ -1137,12 +1138,10 @@ Sema::NameClassification Sema::ClassifyName(Scope *S, CXXScopeSpec &SS,
11371138
dyn_cast<UsingShadowDecl>(*Result.begin());
11381139
assert(!FoundUsingShadow ||
11391140
TD == cast<TemplateDecl>(FoundUsingShadow->getTargetDecl()));
1140-
Template =
1141-
FoundUsingShadow ? TemplateName(FoundUsingShadow) : TemplateName(TD);
1142-
if (SS.isNotEmpty())
1143-
Template = Context.getQualifiedTemplateName(SS.getScopeRep(),
1144-
/*TemplateKeyword=*/false,
1145-
Template);
1141+
Template = Context.getQualifiedTemplateName(
1142+
SS.getScopeRep(),
1143+
/*TemplateKeyword=*/false,
1144+
FoundUsingShadow ? TemplateName(FoundUsingShadow) : TemplateName(TD));
11461145
} else {
11471146
// All results were non-template functions. This is a function template
11481147
// name.

clang/lib/Sema/SemaDeclCXX.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11547,12 +11547,12 @@ bool Sema::CheckDeductionGuideDeclarator(Declarator &D, QualType &R,
1154711547
TemplateName SpecifiedName = RetTST.getTypePtr()->getTemplateName();
1154811548
bool TemplateMatches =
1154911549
Context.hasSameTemplateName(SpecifiedName, GuidedTemplate);
11550-
auto TKind = SpecifiedName.getKind();
11551-
// A Using TemplateName can't actually be valid (either it's qualified, or
11552-
// we're in the wrong scope). But we have diagnosed these problems
11553-
// already.
11554-
bool SimplyWritten = TKind == TemplateName::Template ||
11555-
TKind == TemplateName::UsingTemplate;
11550+
11551+
const QualifiedTemplateName *Qualifiers =
11552+
SpecifiedName.getAsQualifiedTemplateName();
11553+
assert(Qualifiers && "expected QualifiedTemplate");
11554+
bool SimplyWritten = !Qualifiers->hasTemplateKeyword() &&
11555+
Qualifiers->getQualifier() == nullptr;
1155611556
if (SimplyWritten && TemplateMatches)
1155711557
AcceptableReturnType = true;
1155811558
else {

clang/lib/Sema/SemaExpr.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3284,10 +3284,10 @@ ExprResult Sema::BuildDeclarationNameExpr(
32843284
return CreateRecoveryExpr(NameInfo.getBeginLoc(), NameInfo.getEndLoc(), {});
32853285
}
32863286

3287-
if (TemplateDecl *Template = dyn_cast<TemplateDecl>(D)) {
3287+
if (TemplateDecl *TD = dyn_cast<TemplateDecl>(D)) {
32883288
// Specifically diagnose references to class templates that are missing
32893289
// a template argument list.
3290-
diagnoseMissingTemplateArguments(TemplateName(Template), Loc);
3290+
diagnoseMissingTemplateArguments(SS, /*TemplateKeyword=*/false, TD, Loc);
32913291
return ExprError();
32923292
}
32933293

clang/lib/Sema/SemaExprMember.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1194,7 +1194,8 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
11941194

11951195
if (VarTemplateDecl *VarTempl = dyn_cast<VarTemplateDecl>(MemberDecl)) {
11961196
if (!TemplateArgs) {
1197-
diagnoseMissingTemplateArguments(TemplateName(VarTempl), MemberLoc);
1197+
diagnoseMissingTemplateArguments(
1198+
SS, /*TemplateKeyword=*/TemplateKWLoc.isValid(), VarTempl, MemberLoc);
11981199
return ExprError();
11991200
}
12001201

clang/lib/Sema/SemaTemplate.cpp

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,7 @@ TemplateNameKind Sema::isTemplateName(Scope *S,
292292
Template =
293293
FoundUsingShadow ? TemplateName(FoundUsingShadow) : TemplateName(TD);
294294
assert(!FoundUsingShadow || FoundUsingShadow->getTargetDecl() == TD);
295-
if (SS.isSet() && !SS.isInvalid()) {
295+
if (!SS.isInvalid()) {
296296
NestedNameSpecifier *Qualifier = SS.getScopeRep();
297297
Template = Context.getQualifiedTemplateName(Qualifier, hasTemplateKeyword,
298298
Template);
@@ -342,8 +342,11 @@ bool Sema::isDeductionGuideName(Scope *S, const IdentifierInfo &Name,
342342
if (!TD || !getAsTypeTemplateDecl(TD))
343343
return false;
344344

345-
if (Template)
346-
*Template = TemplateTy::make(TemplateName(TD));
345+
if (Template) {
346+
TemplateName Name = Context.getQualifiedTemplateName(
347+
SS.getScopeRep(), /*TemplateKeyword=*/false, TemplateName(TD));
348+
*Template = TemplateTy::make(Name);
349+
}
347350
return true;
348351
}
349352

@@ -983,10 +986,6 @@ ParsedTemplateArgument Sema::ActOnTemplateTypeArgument(TypeResult ParsedType) {
983986

984987
if (auto DTST = TL.getAs<DeducedTemplateSpecializationTypeLoc>()) {
985988
TemplateName Name = DTST.getTypePtr()->getTemplateName();
986-
if (SS.isSet())
987-
Name = Context.getQualifiedTemplateName(SS.getScopeRep(),
988-
/*HasTemplateKeyword=*/false,
989-
Name);
990989
ParsedTemplateArgument Result(SS, TemplateTy::make(Name),
991990
DTST.getTemplateNameLoc());
992991
if (EllipsisLoc.isValid())
@@ -5621,6 +5620,15 @@ void Sema::diagnoseMissingTemplateArguments(TemplateName Name,
56215620
}
56225621
}
56235622

5623+
void Sema::diagnoseMissingTemplateArguments(const CXXScopeSpec &SS,
5624+
bool TemplateKeyword,
5625+
TemplateDecl *TD,
5626+
SourceLocation Loc) {
5627+
TemplateName Name = Context.getQualifiedTemplateName(
5628+
SS.getScopeRep(), TemplateKeyword, TemplateName(TD));
5629+
diagnoseMissingTemplateArguments(Name, Loc);
5630+
}
5631+
56245632
ExprResult
56255633
Sema::CheckConceptTemplateId(const CXXScopeSpec &SS,
56265634
SourceLocation TemplateKWLoc,
@@ -5691,7 +5699,8 @@ ExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS,
56915699
// Non-function templates require a template argument list.
56925700
if (auto *TD = R.getAsSingle<TemplateDecl>()) {
56935701
if (!TemplateArgs && !isa<FunctionTemplateDecl>(TD)) {
5694-
diagnoseMissingTemplateArguments(TemplateName(TD), R.getNameLoc());
5702+
diagnoseMissingTemplateArguments(
5703+
SS, /*TemplateKeyword=*/TemplateKWLoc.isValid(), TD, R.getNameLoc());
56955704
return ExprError();
56965705
}
56975706
}

0 commit comments

Comments
 (0)