forked from OSchip/llvm-project
Preliminary AST representation and semantic analysis for
explicitly-specified template argument lists in member reference expressions, e.g., x->f<int>() llvm-svn: 80646
This commit is contained in:
parent
b1b2016b83
commit
84f14dd674
|
@ -1042,6 +1042,31 @@ struct NameQualifier {
|
|||
/// \brief The source range covered by the nested name specifier.
|
||||
SourceRange Range;
|
||||
};
|
||||
|
||||
/// \brief Represents an explicit template argument list in C++, e.g.,
|
||||
/// the "<int>" in "sort<int>".
|
||||
struct ExplicitTemplateArgumentList {
|
||||
/// \brief The source location of the left angle bracket ('<');
|
||||
SourceLocation LAngleLoc;
|
||||
|
||||
/// \brief The source location of the right angle bracket ('>');
|
||||
SourceLocation RAngleLoc;
|
||||
|
||||
/// \brief The number of template arguments in TemplateArgs.
|
||||
/// The actual template arguments (if any) are stored after the
|
||||
/// ExplicitTemplateArgumentList structure.
|
||||
unsigned NumTemplateArgs;
|
||||
|
||||
/// \brief Retrieve the template arguments
|
||||
TemplateArgument *getTemplateArgs() {
|
||||
return reinterpret_cast<TemplateArgument *> (this + 1);
|
||||
}
|
||||
|
||||
/// \brief Retrieve the template arguments
|
||||
const TemplateArgument *getTemplateArgs() const {
|
||||
return reinterpret_cast<const TemplateArgument *> (this + 1);
|
||||
}
|
||||
};
|
||||
|
||||
/// MemberExpr - [C99 6.5.2.3] Structure and Union Members. X->F and X.F.
|
||||
///
|
||||
|
@ -1061,9 +1086,17 @@ class MemberExpr : public Expr {
|
|||
bool IsArrow : 1;
|
||||
|
||||
/// \brief True if this member expression used a nested-name-specifier to
|
||||
/// refer to the member, e.g., "x->Base::f".
|
||||
/// refer to the member, e.g., "x->Base::f". When true, a NameQualifier
|
||||
/// structure is allocated immediately after the MemberExpr.
|
||||
bool HasQualifier : 1;
|
||||
|
||||
/// \brief True if this member expression specified a template argument list
|
||||
/// explicitly, e.g., x->f<int>. When true, an ExplicitTemplateArgumentList
|
||||
/// structure (and its TemplateArguments) are allocated immediately after
|
||||
/// the MemberExpr or, if the member expression also has a qualifier, after
|
||||
/// the NameQualifier structure.
|
||||
bool HasExplicitTemplateArgumentList : 1;
|
||||
|
||||
/// \brief Retrieve the qualifier that preceded the member name, if any.
|
||||
NameQualifier *getMemberQualifier() {
|
||||
if (!HasQualifier)
|
||||
|
@ -1074,15 +1107,33 @@ class MemberExpr : public Expr {
|
|||
|
||||
/// \brief Retrieve the qualifier that preceded the member name, if any.
|
||||
const NameQualifier *getMemberQualifier() const {
|
||||
if (!HasQualifier)
|
||||
return const_cast<MemberExpr *>(this)->getMemberQualifier();
|
||||
}
|
||||
|
||||
/// \brief Retrieve the explicit template argument list that followed the
|
||||
/// member template name, if any.
|
||||
ExplicitTemplateArgumentList *getExplicitTemplateArgumentList() {
|
||||
if (!HasExplicitTemplateArgumentList)
|
||||
return 0;
|
||||
|
||||
return reinterpret_cast<const NameQualifier *> (this + 1);
|
||||
if (!HasQualifier)
|
||||
return reinterpret_cast<ExplicitTemplateArgumentList *>(this + 1);
|
||||
|
||||
return reinterpret_cast<ExplicitTemplateArgumentList *>(
|
||||
getMemberQualifier() + 1);
|
||||
}
|
||||
|
||||
/// \brief Retrieve the explicit template argument list that followed the
|
||||
/// member template name, if any.
|
||||
const ExplicitTemplateArgumentList *getExplicitTemplateArgumentList() const {
|
||||
return const_cast<MemberExpr *>(this)->getExplicitTemplateArgumentList();
|
||||
}
|
||||
|
||||
MemberExpr(Expr *base, bool isarrow, NestedNameSpecifier *qual,
|
||||
SourceRange qualrange, NamedDecl *memberdecl, SourceLocation l,
|
||||
QualType ty);
|
||||
bool has_explicit, SourceLocation langle,
|
||||
const TemplateArgument *targs, unsigned numtargs,
|
||||
SourceLocation rangle, QualType ty);
|
||||
|
||||
public:
|
||||
MemberExpr(Expr *base, bool isarrow, NamedDecl *memberdecl, SourceLocation l,
|
||||
|
@ -1090,7 +1141,7 @@ public:
|
|||
: Expr(MemberExprClass, ty,
|
||||
base->isTypeDependent(), base->isValueDependent()),
|
||||
Base(base), MemberDecl(memberdecl), MemberLoc(l), IsArrow(isarrow),
|
||||
HasQualifier(false) {}
|
||||
HasQualifier(false), HasExplicitTemplateArgumentList(false) {}
|
||||
|
||||
/// \brief Build an empty member reference expression.
|
||||
explicit MemberExpr(EmptyShell Empty) : Expr(MemberExprClass, Empty) { }
|
||||
|
@ -1098,7 +1149,13 @@ public:
|
|||
static MemberExpr *Create(ASTContext &C, Expr *base, bool isarrow,
|
||||
NestedNameSpecifier *qual, SourceRange qualrange,
|
||||
NamedDecl *memberdecl,
|
||||
SourceLocation l, QualType ty);
|
||||
SourceLocation l,
|
||||
bool has_explicit,
|
||||
SourceLocation langle,
|
||||
const TemplateArgument *targs,
|
||||
unsigned numtargs,
|
||||
SourceLocation rangle,
|
||||
QualType ty);
|
||||
|
||||
void setBase(Expr *E) { Base = E; }
|
||||
Expr *getBase() const { return cast<Expr>(Base); }
|
||||
|
@ -1110,7 +1167,7 @@ public:
|
|||
NamedDecl *getMemberDecl() const { return MemberDecl; }
|
||||
void setMemberDecl(NamedDecl *D) { MemberDecl = D; }
|
||||
|
||||
/// \brief Determines whether this adorned member expression actually had
|
||||
/// \brief Determines whether this member expression actually had
|
||||
/// a C++ nested-name-specifier prior to the name of the member, e.g.,
|
||||
/// x->Base::foo.
|
||||
bool hasQualifier() const { return HasQualifier; }
|
||||
|
@ -1134,6 +1191,48 @@ public:
|
|||
|
||||
return getMemberQualifier()->NNS;
|
||||
}
|
||||
|
||||
/// \brief Determines whether this member expression actually had a C++
|
||||
/// template argument list explicitly specified, e.g., x.f<int>.
|
||||
bool hasExplicitTemplateArgumentList() {
|
||||
return HasExplicitTemplateArgumentList;
|
||||
}
|
||||
|
||||
/// \brief Retrieve the location of the left angle bracket following the
|
||||
/// member name ('<'), if any.
|
||||
SourceLocation getLAngleLoc() const {
|
||||
if (!HasExplicitTemplateArgumentList)
|
||||
return SourceLocation();
|
||||
|
||||
return getExplicitTemplateArgumentList()->LAngleLoc;
|
||||
}
|
||||
|
||||
/// \brief Retrieve the template arguments provided as part of this
|
||||
/// template-id.
|
||||
const TemplateArgument *getTemplateArgs() const {
|
||||
if (!HasExplicitTemplateArgumentList)
|
||||
return 0;
|
||||
|
||||
return getExplicitTemplateArgumentList()->getTemplateArgs();
|
||||
}
|
||||
|
||||
/// \brief Retrieve the number of template arguments provided as part of this
|
||||
/// template-id.
|
||||
unsigned getNumTemplateArgs() const {
|
||||
if (!HasExplicitTemplateArgumentList)
|
||||
return 0;
|
||||
|
||||
return getExplicitTemplateArgumentList()->NumTemplateArgs;
|
||||
}
|
||||
|
||||
/// \brief Retrieve the location of the right angle bracket following the
|
||||
/// template arguments ('>').
|
||||
SourceLocation getRAngleLoc() const {
|
||||
if (!HasExplicitTemplateArgumentList)
|
||||
return SourceLocation();
|
||||
|
||||
return getExplicitTemplateArgumentList()->RAngleLoc;
|
||||
}
|
||||
|
||||
bool isArrow() const { return IsArrow; }
|
||||
void setArrow(bool A) { IsArrow = A; }
|
||||
|
@ -1146,10 +1245,14 @@ public:
|
|||
virtual SourceRange getSourceRange() const {
|
||||
// If we have an implicit base (like a C++ implicit this),
|
||||
// make sure not to return its location
|
||||
SourceLocation EndLoc = MemberLoc;
|
||||
if (HasExplicitTemplateArgumentList)
|
||||
EndLoc = getRAngleLoc();
|
||||
|
||||
SourceLocation BaseLoc = getBase()->getLocStart();
|
||||
if (BaseLoc.isInvalid())
|
||||
return SourceRange(MemberLoc, MemberLoc);
|
||||
return SourceRange(BaseLoc, MemberLoc);
|
||||
return SourceRange(MemberLoc, EndLoc);
|
||||
return SourceRange(BaseLoc, EndLoc);
|
||||
}
|
||||
|
||||
virtual SourceLocation getExprLoc() const { return MemberLoc; }
|
||||
|
|
|
@ -264,31 +264,58 @@ QualType CallExpr::getCallReturnType() const {
|
|||
|
||||
MemberExpr::MemberExpr(Expr *base, bool isarrow, NestedNameSpecifier *qual,
|
||||
SourceRange qualrange, NamedDecl *memberdecl,
|
||||
SourceLocation l, QualType ty)
|
||||
SourceLocation l, bool has_explicit,
|
||||
SourceLocation langle,
|
||||
const TemplateArgument *targs, unsigned numtargs,
|
||||
SourceLocation rangle, QualType ty)
|
||||
: Expr(MemberExprClass, ty,
|
||||
base->isTypeDependent() || (qual && qual->isDependent()),
|
||||
base->isValueDependent() || (qual && qual->isDependent())),
|
||||
Base(base), MemberDecl(memberdecl), MemberLoc(l), IsArrow(isarrow),
|
||||
HasQualifier(qual != 0) {
|
||||
HasQualifier(qual != 0), HasExplicitTemplateArgumentList(has_explicit) {
|
||||
// Initialize the qualifier, if any.
|
||||
if (HasQualifier) {
|
||||
NameQualifier *NQ = getMemberQualifier();
|
||||
NQ->NNS = qual;
|
||||
NQ->Range = qualrange;
|
||||
}
|
||||
|
||||
// Initialize the explicit template argument list, if any.
|
||||
if (HasExplicitTemplateArgumentList) {
|
||||
ExplicitTemplateArgumentList *ETemplateArgs
|
||||
= getExplicitTemplateArgumentList();
|
||||
ETemplateArgs->LAngleLoc = langle;
|
||||
ETemplateArgs->RAngleLoc = rangle;
|
||||
ETemplateArgs->NumTemplateArgs = numtargs;
|
||||
|
||||
TemplateArgument *TemplateArgs = ETemplateArgs->getTemplateArgs();
|
||||
for (unsigned I = 0; I < numtargs; ++I)
|
||||
new (TemplateArgs + I) TemplateArgument(targs[I]);
|
||||
}
|
||||
}
|
||||
|
||||
MemberExpr *MemberExpr::Create(ASTContext &C, Expr *base, bool isarrow,
|
||||
NestedNameSpecifier *qual,
|
||||
SourceRange qualrange,
|
||||
NamedDecl *memberdecl,
|
||||
SourceLocation l, QualType ty) {
|
||||
SourceLocation l,
|
||||
bool has_explicit,
|
||||
SourceLocation langle,
|
||||
const TemplateArgument *targs,
|
||||
unsigned numtargs,
|
||||
SourceLocation rangle,
|
||||
QualType ty) {
|
||||
std::size_t Size = sizeof(MemberExpr);
|
||||
if (qual != 0)
|
||||
Size += sizeof(NameQualifier);
|
||||
|
||||
if (has_explicit)
|
||||
Size += sizeof(ExplicitTemplateArgumentList) +
|
||||
sizeof(TemplateArgument) * numtargs;
|
||||
|
||||
void *Mem = C.Allocate(Size, llvm::alignof<MemberExpr>());
|
||||
return new (Mem) MemberExpr(base, isarrow, qual, qualrange, memberdecl, l,
|
||||
return new (Mem) MemberExpr(base, isarrow, qual, qualrange, memberdecl, l,
|
||||
has_explicit, langle, targs, numtargs, rangle,
|
||||
ty);
|
||||
}
|
||||
|
||||
|
|
|
@ -743,6 +743,12 @@ void StmtPrinter::VisitMemberExpr(MemberExpr *Node) {
|
|||
Qualifier->print(OS, Policy);
|
||||
|
||||
OS << Node->getMemberDecl()->getNameAsString();
|
||||
|
||||
if (Node->hasExplicitTemplateArgumentList())
|
||||
OS << TemplateSpecializationType::PrintTemplateArgumentList(
|
||||
Node->getTemplateArgs(),
|
||||
Node->getNumTemplateArgs(),
|
||||
Policy);
|
||||
}
|
||||
void StmtPrinter::VisitObjCIsaExpr(ObjCIsaExpr *Node) {
|
||||
PrintExpr(Node->getBase());
|
||||
|
|
|
@ -416,6 +416,7 @@ void PCHStmtWriter::VisitMemberExpr(MemberExpr *E) {
|
|||
Writer.AddSourceLocation(E->getMemberLoc(), Record);
|
||||
Record.push_back(E->isArrow());
|
||||
// FIXME: C++ nested-name-specifier
|
||||
// FIXME: C++ template argument list
|
||||
Code = pch::EXPR_MEMBER;
|
||||
}
|
||||
|
||||
|
|
|
@ -1602,12 +1602,32 @@ public:
|
|||
SourceLocation LLoc,
|
||||
ExprArg Idx,
|
||||
SourceLocation RLoc);
|
||||
|
||||
OwningExprResult BuildMemberReferenceExpr(Scope *S, ExprArg Base,
|
||||
SourceLocation OpLoc,
|
||||
tok::TokenKind OpKind,
|
||||
SourceLocation MemberLoc,
|
||||
DeclarationName MemberName,
|
||||
DeclPtrTy ImplDecl,
|
||||
const CXXScopeSpec *SS = 0) {
|
||||
// FIXME: Temporary helper while we migrate existing calls to
|
||||
// BuildMemberReferenceExpr to support explicitly-specified template
|
||||
// arguments.
|
||||
return BuildMemberReferenceExpr(S, move(Base), OpLoc, OpKind, MemberLoc,
|
||||
MemberName, false, SourceLocation(), 0, 0,
|
||||
SourceLocation(), ImplDecl, SS);
|
||||
}
|
||||
|
||||
OwningExprResult BuildMemberReferenceExpr(Scope *S, ExprArg Base,
|
||||
SourceLocation OpLoc,
|
||||
tok::TokenKind OpKind,
|
||||
SourceLocation MemberLoc,
|
||||
DeclarationName MemberName,
|
||||
bool HasExplicitTemplateArgs,
|
||||
SourceLocation LAngleLoc,
|
||||
const TemplateArgument *ExplicitTemplateArgs,
|
||||
unsigned NumExplicitTemplateArgs,
|
||||
SourceLocation RAngleLoc,
|
||||
DeclPtrTy ImplDecl,
|
||||
const CXXScopeSpec *SS = 0);
|
||||
|
||||
|
|
|
@ -885,7 +885,10 @@ static MemberExpr *BuildMemberExpr(ASTContext &C, Expr *Base, bool isArrow,
|
|||
if (SS && SS->isSet())
|
||||
return MemberExpr::Create(C, Base, isArrow,
|
||||
(NestedNameSpecifier *)SS->getScopeRep(),
|
||||
SS->getRange(), Member, Loc, Ty);
|
||||
SS->getRange(), Member, Loc,
|
||||
// FIXME: Explicit template argument lists
|
||||
false, SourceLocation(), 0, 0, SourceLocation(),
|
||||
Ty);
|
||||
|
||||
return new (C) MemberExpr(Base, isArrow, Member, Loc, Ty);
|
||||
}
|
||||
|
@ -1980,6 +1983,11 @@ Action::OwningExprResult
|
|||
Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
|
||||
tok::TokenKind OpKind, SourceLocation MemberLoc,
|
||||
DeclarationName MemberName,
|
||||
bool HasExplicitTemplateArgs,
|
||||
SourceLocation LAngleLoc,
|
||||
const TemplateArgument *ExplicitTemplateArgs,
|
||||
unsigned NumExplicitTemplateArgs,
|
||||
SourceLocation RAngleLoc,
|
||||
DeclPtrTy ObjCImpDecl, const CXXScopeSpec *SS) {
|
||||
if (SS && SS->isInvalid())
|
||||
return ExprError();
|
||||
|
@ -2153,14 +2161,34 @@ Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
|
|||
if (FunctionTemplateDecl *FunTmpl
|
||||
= dyn_cast<FunctionTemplateDecl>(MemberDecl)) {
|
||||
MarkDeclarationReferenced(MemberLoc, MemberDecl);
|
||||
|
||||
if (HasExplicitTemplateArgs)
|
||||
return Owned(MemberExpr::Create(Context, BaseExpr, OpKind == tok::arrow,
|
||||
(NestedNameSpecifier *)(SS? SS->getScopeRep() : 0),
|
||||
SS? SS->getRange() : SourceRange(),
|
||||
FunTmpl, MemberLoc, true,
|
||||
LAngleLoc, ExplicitTemplateArgs,
|
||||
NumExplicitTemplateArgs, RAngleLoc,
|
||||
Context.OverloadTy));
|
||||
|
||||
return Owned(BuildMemberExpr(Context, BaseExpr, OpKind == tok::arrow, SS,
|
||||
FunTmpl, MemberLoc,
|
||||
Context.OverloadTy));
|
||||
}
|
||||
if (OverloadedFunctionDecl *Ovl
|
||||
= dyn_cast<OverloadedFunctionDecl>(MemberDecl))
|
||||
= dyn_cast<OverloadedFunctionDecl>(MemberDecl)) {
|
||||
if (HasExplicitTemplateArgs)
|
||||
return Owned(MemberExpr::Create(Context, BaseExpr, OpKind == tok::arrow,
|
||||
(NestedNameSpecifier *)(SS? SS->getScopeRep() : 0),
|
||||
SS? SS->getRange() : SourceRange(),
|
||||
Ovl, MemberLoc, true,
|
||||
LAngleLoc, ExplicitTemplateArgs,
|
||||
NumExplicitTemplateArgs, RAngleLoc,
|
||||
Context.OverloadTy));
|
||||
|
||||
return Owned(BuildMemberExpr(Context, BaseExpr, OpKind == tok::arrow, SS,
|
||||
Ovl, MemberLoc, Context.OverloadTy));
|
||||
}
|
||||
if (EnumConstantDecl *Enum = dyn_cast<EnumConstantDecl>(MemberDecl)) {
|
||||
MarkDeclarationReferenced(MemberLoc, MemberDecl);
|
||||
return Owned(BuildMemberExpr(Context, BaseExpr, OpKind == tok::arrow, SS,
|
||||
|
|
|
@ -1831,21 +1831,6 @@ Sema::ActOnConversionOperatorReferenceExpr(Scope *S, ExprArg Base,
|
|||
ConvName, DeclPtrTy(), SS);
|
||||
}
|
||||
|
||||
Sema::OwningExprResult
|
||||
Sema::ActOnMemberTemplateIdReferenceExpr(Scope *S, ExprArg Base,
|
||||
SourceLocation OpLoc,
|
||||
tok::TokenKind OpKind,
|
||||
const CXXScopeSpec &SS,
|
||||
TemplateTy Template,
|
||||
SourceLocation TemplateNameLoc,
|
||||
SourceLocation LAngleLoc,
|
||||
ASTTemplateArgsPtr TemplateArgs,
|
||||
SourceLocation *TemplateArgLocs,
|
||||
SourceLocation RAngleLoc) {
|
||||
// FIXME: Implement!
|
||||
return ExprError();
|
||||
}
|
||||
|
||||
Sema::OwningExprResult Sema::ActOnFinishFullExpr(ExprArg Arg) {
|
||||
Expr *FullExpr = Arg.takeAs<Expr>();
|
||||
if (FullExpr)
|
||||
|
|
|
@ -4563,9 +4563,11 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
|
|||
AddMethodCandidate(Method, ObjectArg, Args, NumArgs, CandidateSet,
|
||||
/*SuppressUserConversions=*/false);
|
||||
else
|
||||
AddMethodTemplateCandidate(cast<FunctionTemplateDecl>(*Func),
|
||||
/*FIXME:*/false, /*FIXME:*/0,
|
||||
/*FIXME:*/0, ObjectArg, Args, NumArgs,
|
||||
AddMethodTemplateCandidate(cast<FunctionTemplateDecl>(*Func),
|
||||
MemExpr->hasExplicitTemplateArgumentList(),
|
||||
MemExpr->getTemplateArgs(),
|
||||
MemExpr->getNumTemplateArgs(),
|
||||
ObjectArg, Args, NumArgs,
|
||||
CandidateSet,
|
||||
/*SuppressUsedConversions=*/false);
|
||||
}
|
||||
|
|
|
@ -1084,6 +1084,41 @@ Sema::OwningExprResult Sema::ActOnTemplateIdExpr(TemplateTy TemplateD,
|
|||
RAngleLoc);
|
||||
}
|
||||
|
||||
Sema::OwningExprResult
|
||||
Sema::ActOnMemberTemplateIdReferenceExpr(Scope *S, ExprArg Base,
|
||||
SourceLocation OpLoc,
|
||||
tok::TokenKind OpKind,
|
||||
const CXXScopeSpec &SS,
|
||||
TemplateTy TemplateD,
|
||||
SourceLocation TemplateNameLoc,
|
||||
SourceLocation LAngleLoc,
|
||||
ASTTemplateArgsPtr TemplateArgsIn,
|
||||
SourceLocation *TemplateArgLocs,
|
||||
SourceLocation RAngleLoc) {
|
||||
TemplateName Template = TemplateD.getAsVal<TemplateName>();
|
||||
|
||||
// FIXME: We're going to end up looking up the template based on its name,
|
||||
// twice!
|
||||
DeclarationName Name;
|
||||
if (TemplateDecl *ActualTemplate = Template.getAsTemplateDecl())
|
||||
Name = ActualTemplate->getDeclName();
|
||||
else if (OverloadedFunctionDecl *Ovl = Template.getAsOverloadedFunctionDecl())
|
||||
Name = Ovl->getDeclName();
|
||||
else
|
||||
assert(false && "Cannot support dependent template names yet");
|
||||
|
||||
// Translate the parser's template argument list in our AST format.
|
||||
llvm::SmallVector<TemplateArgument, 16> TemplateArgs;
|
||||
translateTemplateArguments(TemplateArgsIn, TemplateArgLocs, TemplateArgs);
|
||||
TemplateArgsIn.release();
|
||||
|
||||
// Do we have the save the actual template name? We might need it...
|
||||
return BuildMemberReferenceExpr(S, move(Base), OpLoc, OpKind, TemplateNameLoc,
|
||||
Name, true, LAngleLoc,
|
||||
TemplateArgs.data(), TemplateArgs.size(),
|
||||
RAngleLoc, DeclPtrTy(), &SS);
|
||||
}
|
||||
|
||||
/// \brief Form a dependent template name.
|
||||
///
|
||||
/// This action forms a dependent template name given the template
|
||||
|
|
|
@ -2964,7 +2964,7 @@ TreeTransform<Derived>::TransformMemberExpr(MemberExpr *E) {
|
|||
Qualifier
|
||||
= getDerived().TransformNestedNameSpecifier(E->getQualifier(),
|
||||
E->getQualifierRange());
|
||||
if (Qualifier == 0);
|
||||
if (Qualifier == 0)
|
||||
return SemaRef.ExprError();
|
||||
}
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@ void test_X_f1_address() {
|
|||
void test_X_f0_explicit(X x, int i, long l) {
|
||||
int &ir1 = x.f0<int>(i);
|
||||
int &ir2 = x.f0<>(i);
|
||||
int &ir3 = x.f0<long>(i);
|
||||
long &il1 = x.f0<long>(i);
|
||||
}
|
||||
|
||||
// PR4608
|
||||
|
|
Loading…
Reference in New Issue