зеркало из https://github.com/microsoft/clang-1.git
Use ParseUnqualifiedId when parsing id-expressions. This eliminates
yet another copy of the unqualified-id parsing code. Also, use UnqualifiedId to simplify the Action interface for building id-expressions. ActOnIdentifierExpr, ActOnCXXOperatorFunctionIdExpr, ActOnCXXConversionFunctionExpr, and ActOnTemplateIdExpr have all been removed in favor of the new ActOnIdExpression action. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@85904 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
519202d315
Коммит
02a24ee67c
|
@ -855,43 +855,29 @@ public:
|
|||
return SourceRange();
|
||||
}
|
||||
|
||||
/// ActOnIdentifierExpr - Parse an identifier in expression context.
|
||||
/// 'HasTrailingLParen' indicates whether or not the identifier has a '('
|
||||
/// token immediately after it.
|
||||
/// An optional CXXScopeSpec can be passed to indicate the C++ scope (class or
|
||||
/// namespace) that the identifier must be a member of.
|
||||
/// i.e. for "foo::bar", 'II' will be "bar" and 'SS' will be "foo::".
|
||||
virtual OwningExprResult ActOnIdentifierExpr(Scope *S, SourceLocation Loc,
|
||||
IdentifierInfo &II,
|
||||
bool HasTrailingLParen,
|
||||
const CXXScopeSpec *SS = 0,
|
||||
bool isAddressOfOperand = false){
|
||||
return ExprEmpty();
|
||||
}
|
||||
|
||||
/// ActOnOperatorFunctionIdExpr - Parse a C++ overloaded operator
|
||||
/// name (e.g., @c operator+ ) as an expression. This is very
|
||||
/// similar to ActOnIdentifierExpr, except that instead of providing
|
||||
/// an identifier the parser provides the kind of overloaded
|
||||
/// operator that was parsed.
|
||||
virtual OwningExprResult ActOnCXXOperatorFunctionIdExpr(
|
||||
Scope *S, SourceLocation OperatorLoc,
|
||||
OverloadedOperatorKind Op,
|
||||
bool HasTrailingLParen, const CXXScopeSpec &SS,
|
||||
bool isAddressOfOperand = false) {
|
||||
return ExprEmpty();
|
||||
}
|
||||
|
||||
/// ActOnCXXConversionFunctionExpr - Parse a C++ conversion function
|
||||
/// name (e.g., @c operator void const *) as an expression. This is
|
||||
/// very similar to ActOnIdentifierExpr, except that instead of
|
||||
/// providing an identifier the parser provides the type of the
|
||||
/// conversion function.
|
||||
virtual OwningExprResult ActOnCXXConversionFunctionExpr(
|
||||
Scope *S, SourceLocation OperatorLoc,
|
||||
TypeTy *Type, bool HasTrailingLParen,
|
||||
const CXXScopeSpec &SS,
|
||||
bool isAddressOfOperand = false) {
|
||||
/// \brief Parsed an id-expression (C++) or identifier (C) in expression
|
||||
/// context, e.g., the expression "x" that refers to a variable named "x".
|
||||
///
|
||||
/// \param S the scope in which this id-expression or identifier occurs.
|
||||
///
|
||||
/// \param SS the C++ nested-name-specifier that qualifies the name of the
|
||||
/// value, e.g., "std::" in "std::sort".
|
||||
///
|
||||
/// \param Name the name to which the id-expression refers. In C, this will
|
||||
/// always be an identifier. In C++, it may also be an overloaded operator,
|
||||
/// destructor name (if there is a nested-name-specifier), or template-id.
|
||||
///
|
||||
/// \param HasTrailingLParen whether the next token following the
|
||||
/// id-expression or identifier is a left parentheses ('(').
|
||||
///
|
||||
/// \param IsAddressOfOperand whether the token that precedes this
|
||||
/// id-expression or identifier was an ampersand ('&'), indicating that
|
||||
/// we will be taking the address of this expression.
|
||||
virtual OwningExprResult ActOnIdExpression(Scope *S,
|
||||
const CXXScopeSpec &SS,
|
||||
UnqualifiedId &Name,
|
||||
bool HasTrailingLParen,
|
||||
bool IsAddressOfOperand) {
|
||||
return ExprEmpty();
|
||||
}
|
||||
|
||||
|
@ -1711,40 +1697,6 @@ public:
|
|||
return TypeResult();
|
||||
}
|
||||
|
||||
/// \brief Form a reference to a template-id (that will refer to a function)
|
||||
/// from a template and a list of template arguments.
|
||||
///
|
||||
/// This action forms an expression that references the given template-id,
|
||||
/// possibly checking well-formedness of the template arguments. It does not
|
||||
/// imply the declaration of any entity.
|
||||
///
|
||||
/// \param SS The scope specifier that may precede the template name.
|
||||
///
|
||||
/// \param Template A template whose specialization results in a
|
||||
/// function or a dependent template.
|
||||
///
|
||||
/// \param TemplateNameLoc The location of the template name.
|
||||
///
|
||||
/// \param LAngleLoc The location of the left angle bracket ('<') that starts
|
||||
/// the template argument list.
|
||||
///
|
||||
/// \param TemplateArgs The template arguments in the template argument list,
|
||||
/// which may be empty.
|
||||
///
|
||||
/// \param TemplateArgLocs The locations of the template arguments.
|
||||
///
|
||||
/// \param RAngleLoc The location of the right angle bracket ('>') that
|
||||
/// closes the template argument list.
|
||||
virtual OwningExprResult ActOnTemplateIdExpr(const CXXScopeSpec &SS,
|
||||
TemplateTy Template,
|
||||
SourceLocation TemplateNameLoc,
|
||||
SourceLocation LAngleLoc,
|
||||
ASTTemplateArgsPtr TemplateArgs,
|
||||
SourceLocation *TemplateArgLocs,
|
||||
SourceLocation RAngleLoc) {
|
||||
return ExprError();
|
||||
}
|
||||
|
||||
/// \brief Form a dependent template name.
|
||||
///
|
||||
/// This action forms a dependent template name given the template
|
||||
|
|
|
@ -1213,8 +1213,8 @@ private:
|
|||
bool EnteringContext,
|
||||
UnqualifiedId &Id);
|
||||
bool ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext,
|
||||
bool IsExpressionContext,
|
||||
bool IsDeclarator,
|
||||
bool AllowDestructorName,
|
||||
bool AllowConstructorName,
|
||||
UnqualifiedId &Result);
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
|
|
@ -651,7 +651,11 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression,
|
|||
// Function designators are allowed to be undeclared (C99 6.5.1p2), so we
|
||||
// need to know whether or not this identifier is a function designator or
|
||||
// not.
|
||||
Res = Actions.ActOnIdentifierExpr(CurScope, ILoc, II, Tok.is(tok::l_paren));
|
||||
UnqualifiedId Name;
|
||||
CXXScopeSpec ScopeSpec;
|
||||
Name.setIdentifier(&II, ILoc);
|
||||
Res = Actions.ActOnIdExpression(CurScope, ScopeSpec, Name,
|
||||
Tok.is(tok::l_paren), false);
|
||||
// These can be followed by postfix-expr pieces.
|
||||
return ParsePostfixExpressionSuffix(move(Res));
|
||||
}
|
||||
|
|
|
@ -310,6 +310,18 @@ Parser::OwningExprResult Parser::ParseCXXIdExpression(bool isAddressOfOperand) {
|
|||
CXXScopeSpec SS;
|
||||
ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, false);
|
||||
|
||||
UnqualifiedId Name;
|
||||
if (ParseUnqualifiedId(SS,
|
||||
/*EnteringContext=*/false,
|
||||
/*AllowDestructorName=*/false,
|
||||
/*AllowConstructorName=*/false,
|
||||
Name))
|
||||
return ExprError();
|
||||
|
||||
return Actions.ActOnIdExpression(CurScope, SS, Name, Tok.is(tok::l_paren),
|
||||
isAddressOfOperand);
|
||||
|
||||
#if 0
|
||||
// unqualified-id:
|
||||
// identifier
|
||||
// operator-function-id
|
||||
|
@ -372,6 +384,7 @@ Parser::OwningExprResult Parser::ParseCXXIdExpression(bool isAddressOfOperand) {
|
|||
} // switch.
|
||||
|
||||
assert(0 && "The switch was supposed to take care everything.");
|
||||
#endif
|
||||
}
|
||||
|
||||
/// ParseCXXCasts - This handles the various ways to cast expressions to another
|
||||
|
|
|
@ -474,6 +474,7 @@ public:
|
|||
/// \brief Create a LocInfoType to hold the given QualType and DeclaratorInfo.
|
||||
QualType CreateLocInfoType(QualType T, DeclaratorInfo *DInfo);
|
||||
DeclarationName GetNameForDeclarator(Declarator &D);
|
||||
DeclarationName GetNameFromUnqualifiedId(UnqualifiedId &Name);
|
||||
static QualType GetTypeFromParser(TypeTy *Ty, DeclaratorInfo **DInfo = 0);
|
||||
bool CheckSpecifiedExceptionType(QualType T, const SourceRange &Range);
|
||||
bool CheckDistantExceptionSpec(QualType T);
|
||||
|
@ -1608,23 +1609,12 @@ public:
|
|||
// Primary Expressions.
|
||||
virtual SourceRange getExprRange(ExprTy *E) const;
|
||||
|
||||
virtual OwningExprResult ActOnIdentifierExpr(Scope *S, SourceLocation Loc,
|
||||
IdentifierInfo &II,
|
||||
bool HasTrailingLParen,
|
||||
const CXXScopeSpec *SS = 0,
|
||||
bool isAddressOfOperand = false);
|
||||
virtual OwningExprResult ActOnCXXOperatorFunctionIdExpr(Scope *S,
|
||||
SourceLocation OperatorLoc,
|
||||
OverloadedOperatorKind Op,
|
||||
bool HasTrailingLParen,
|
||||
const CXXScopeSpec &SS,
|
||||
bool isAddressOfOperand);
|
||||
virtual OwningExprResult ActOnCXXConversionFunctionExpr(Scope *S,
|
||||
SourceLocation OperatorLoc,
|
||||
TypeTy *Ty,
|
||||
bool HasTrailingLParen,
|
||||
const CXXScopeSpec &SS,
|
||||
bool isAddressOfOperand);
|
||||
virtual OwningExprResult ActOnIdExpression(Scope *S,
|
||||
const CXXScopeSpec &SS,
|
||||
UnqualifiedId &Name,
|
||||
bool HasTrailingLParen,
|
||||
bool IsAddressOfOperand);
|
||||
|
||||
OwningExprResult BuildDeclRefExpr(NamedDecl *D, QualType Ty,
|
||||
SourceLocation Loc, bool TypeDependent,
|
||||
bool ValueDependent,
|
||||
|
@ -2545,13 +2535,13 @@ public:
|
|||
unsigned NumTemplateArgs,
|
||||
SourceLocation RAngleLoc);
|
||||
|
||||
virtual OwningExprResult ActOnTemplateIdExpr(const CXXScopeSpec &SS,
|
||||
TemplateTy Template,
|
||||
SourceLocation TemplateNameLoc,
|
||||
SourceLocation LAngleLoc,
|
||||
ASTTemplateArgsPtr TemplateArgs,
|
||||
SourceLocation *TemplateArgLocs,
|
||||
SourceLocation RAngleLoc);
|
||||
OwningExprResult ActOnTemplateIdExpr(const CXXScopeSpec &SS,
|
||||
TemplateTy Template,
|
||||
SourceLocation TemplateNameLoc,
|
||||
SourceLocation LAngleLoc,
|
||||
ASTTemplateArgsPtr TemplateArgs,
|
||||
SourceLocation *TemplateArgLocs,
|
||||
SourceLocation RAngleLoc);
|
||||
|
||||
virtual TemplateTy ActOnDependentTemplateName(SourceLocation TemplateKWLoc,
|
||||
const IdentifierInfo &Name,
|
||||
|
|
|
@ -1606,52 +1606,56 @@ Sema::DeclPtrTy Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
|
|||
/// GetNameForDeclarator - Determine the full declaration name for the
|
||||
/// given Declarator.
|
||||
DeclarationName Sema::GetNameForDeclarator(Declarator &D) {
|
||||
UnqualifiedId &Name = D.getName();
|
||||
return GetNameFromUnqualifiedId(D.getName());
|
||||
}
|
||||
|
||||
/// \brief Retrieves the canonicalized name from a parsed unqualified-id.
|
||||
DeclarationName Sema::GetNameFromUnqualifiedId(UnqualifiedId &Name) {
|
||||
switch (Name.getKind()) {
|
||||
case UnqualifiedId::IK_Identifier:
|
||||
return DeclarationName(Name.Identifier);
|
||||
case UnqualifiedId::IK_Identifier:
|
||||
return DeclarationName(Name.Identifier);
|
||||
|
||||
case UnqualifiedId::IK_OperatorFunctionId:
|
||||
return Context.DeclarationNames.getCXXOperatorName(
|
||||
Name.OperatorFunctionId.Operator);
|
||||
case UnqualifiedId::IK_OperatorFunctionId:
|
||||
return Context.DeclarationNames.getCXXOperatorName(
|
||||
Name.OperatorFunctionId.Operator);
|
||||
|
||||
case UnqualifiedId::IK_ConversionFunctionId: {
|
||||
QualType Ty = GetTypeFromParser(Name.ConversionFunctionId);
|
||||
if (Ty.isNull())
|
||||
return DeclarationName();
|
||||
case UnqualifiedId::IK_ConversionFunctionId: {
|
||||
QualType Ty = GetTypeFromParser(Name.ConversionFunctionId);
|
||||
if (Ty.isNull())
|
||||
return DeclarationName();
|
||||
|
||||
return Context.DeclarationNames.getCXXConversionFunctionName(
|
||||
Context.getCanonicalType(Ty));
|
||||
}
|
||||
return Context.DeclarationNames.getCXXConversionFunctionName(
|
||||
Context.getCanonicalType(Ty));
|
||||
}
|
||||
|
||||
case UnqualifiedId::IK_ConstructorName: {
|
||||
QualType Ty = GetTypeFromParser(Name.ConstructorName);
|
||||
if (Ty.isNull())
|
||||
return DeclarationName();
|
||||
case UnqualifiedId::IK_ConstructorName: {
|
||||
QualType Ty = GetTypeFromParser(Name.ConstructorName);
|
||||
if (Ty.isNull())
|
||||
return DeclarationName();
|
||||
|
||||
return Context.DeclarationNames.getCXXConstructorName(
|
||||
Context.getCanonicalType(Ty));
|
||||
}
|
||||
return Context.DeclarationNames.getCXXConstructorName(
|
||||
Context.getCanonicalType(Ty));
|
||||
}
|
||||
|
||||
case UnqualifiedId::IK_DestructorName: {
|
||||
QualType Ty = GetTypeFromParser(Name.DestructorName);
|
||||
if (Ty.isNull())
|
||||
return DeclarationName();
|
||||
case UnqualifiedId::IK_DestructorName: {
|
||||
QualType Ty = GetTypeFromParser(Name.DestructorName);
|
||||
if (Ty.isNull())
|
||||
return DeclarationName();
|
||||
|
||||
return Context.DeclarationNames.getCXXDestructorName(
|
||||
Context.getCanonicalType(Ty));
|
||||
}
|
||||
return Context.DeclarationNames.getCXXDestructorName(
|
||||
Context.getCanonicalType(Ty));
|
||||
}
|
||||
|
||||
case UnqualifiedId::IK_TemplateId: {
|
||||
TemplateName TName
|
||||
case UnqualifiedId::IK_TemplateId: {
|
||||
TemplateName TName
|
||||
= TemplateName::getFromVoidPointer(Name.TemplateId->Template);
|
||||
if (TemplateDecl *Template = TName.getAsTemplateDecl())
|
||||
return Template->getDeclName();
|
||||
if (OverloadedFunctionDecl *Ovl = TName.getAsOverloadedFunctionDecl())
|
||||
return Ovl->getDeclName();
|
||||
if (TemplateDecl *Template = TName.getAsTemplateDecl())
|
||||
return Template->getDeclName();
|
||||
if (OverloadedFunctionDecl *Ovl = TName.getAsOverloadedFunctionDecl())
|
||||
return Ovl->getDeclName();
|
||||
|
||||
return DeclarationName();
|
||||
}
|
||||
return DeclarationName();
|
||||
}
|
||||
}
|
||||
|
||||
assert(false && "Unknown name kind");
|
||||
|
|
|
@ -436,20 +436,6 @@ static bool ShouldSnapshotBlockValueReference(BlockSemaInfo *CurBlock,
|
|||
|
||||
|
||||
|
||||
/// ActOnIdentifierExpr - The parser read an identifier in expression context,
|
||||
/// validate it per-C99 6.5.1. HasTrailingLParen indicates whether this
|
||||
/// identifier is used in a function call context.
|
||||
/// SS is only used for a C++ qualified-id (foo::bar) to indicate the
|
||||
/// class or namespace that the identifier must be a member of.
|
||||
Sema::OwningExprResult Sema::ActOnIdentifierExpr(Scope *S, SourceLocation Loc,
|
||||
IdentifierInfo &II,
|
||||
bool HasTrailingLParen,
|
||||
const CXXScopeSpec *SS,
|
||||
bool isAddressOfOperand) {
|
||||
return ActOnDeclarationNameExpr(S, Loc, &II, HasTrailingLParen, SS,
|
||||
isAddressOfOperand);
|
||||
}
|
||||
|
||||
/// BuildDeclRefExpr - Build a DeclRefExpr.
|
||||
Sema::OwningExprResult
|
||||
Sema::BuildDeclRefExpr(NamedDecl *D, QualType Ty, SourceLocation Loc,
|
||||
|
@ -654,15 +640,43 @@ Sema::BuildAnonymousStructUnionMemberReference(SourceLocation Loc,
|
|||
return Owned(Result);
|
||||
}
|
||||
|
||||
Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S,
|
||||
const CXXScopeSpec &SS,
|
||||
UnqualifiedId &Name,
|
||||
bool HasTrailingLParen,
|
||||
bool IsAddressOfOperand) {
|
||||
if (Name.getKind() == UnqualifiedId::IK_TemplateId) {
|
||||
ASTTemplateArgsPtr TemplateArgsPtr(*this,
|
||||
Name.TemplateId->getTemplateArgs(),
|
||||
Name.TemplateId->getTemplateArgIsType(),
|
||||
Name.TemplateId->NumArgs);
|
||||
return ActOnTemplateIdExpr(SS,
|
||||
TemplateTy::make(Name.TemplateId->Template),
|
||||
Name.TemplateId->TemplateNameLoc,
|
||||
Name.TemplateId->LAngleLoc,
|
||||
TemplateArgsPtr,
|
||||
Name.TemplateId->getTemplateArgLocations(),
|
||||
Name.TemplateId->RAngleLoc);
|
||||
}
|
||||
|
||||
// FIXME: We lose a bunch of source information by doing this. Later,
|
||||
// we'll want to merge ActOnDeclarationNameExpr's logic into
|
||||
// ActOnIdExpression.
|
||||
return ActOnDeclarationNameExpr(S,
|
||||
Name.StartLocation,
|
||||
GetNameFromUnqualifiedId(Name),
|
||||
HasTrailingLParen,
|
||||
&SS,
|
||||
IsAddressOfOperand);
|
||||
}
|
||||
|
||||
/// ActOnDeclarationNameExpr - The parser has read some kind of name
|
||||
/// (e.g., a C++ id-expression (C++ [expr.prim]p1)). This routine
|
||||
/// performs lookup on that name and returns an expression that refers
|
||||
/// to that name. This routine isn't directly called from the parser,
|
||||
/// because the parser doesn't know about DeclarationName. Rather,
|
||||
/// this routine is called by ActOnIdentifierExpr,
|
||||
/// ActOnOperatorFunctionIdExpr, and ActOnConversionFunctionExpr,
|
||||
/// which form the DeclarationName from the corresponding syntactic
|
||||
/// forms.
|
||||
/// this routine is called by ActOnIdExpression, which contains a
|
||||
/// parsed UnqualifiedId.
|
||||
///
|
||||
/// HasTrailingLParen indicates whether this identifier is used in a
|
||||
/// function call context. LookupCtx is only used for a C++
|
||||
|
@ -743,8 +757,11 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc,
|
|||
// FIXME: This should use a new expr for a direct reference, don't
|
||||
// turn this into Self->ivar, just return a BareIVarExpr or something.
|
||||
IdentifierInfo &II = Context.Idents.get("self");
|
||||
OwningExprResult SelfExpr = ActOnIdentifierExpr(S, SourceLocation(),
|
||||
II, false);
|
||||
UnqualifiedId SelfName;
|
||||
SelfName.setIdentifier(&II, SourceLocation());
|
||||
CXXScopeSpec SelfScopeSpec;
|
||||
OwningExprResult SelfExpr = ActOnIdExpression(S, SelfScopeSpec,
|
||||
SelfName, false, false);
|
||||
MarkDeclarationReferenced(Loc, IV);
|
||||
return Owned(new (Context)
|
||||
ObjCIvarRefExpr(IV, IV->getType(), Loc,
|
||||
|
@ -3985,7 +4002,7 @@ Sema::CheckSingleAssignmentConstraints(QualType lhsType, Expr *&rExpr) {
|
|||
|
||||
// This check seems unnatural, however it is necessary to ensure the proper
|
||||
// conversion of functions/arrays. If the conversion were done for all
|
||||
// DeclExpr's (created by ActOnIdentifierExpr), it would mess up the unary
|
||||
// DeclExpr's (created by ActOnIdExpression), it would mess up the unary
|
||||
// expressions that surpress this implicit conversion (&, sizeof).
|
||||
//
|
||||
// Suppress this for references: C++ 8.5.3p5.
|
||||
|
|
|
@ -22,41 +22,6 @@
|
|||
#include "llvm/ADT/STLExtras.h"
|
||||
using namespace clang;
|
||||
|
||||
/// ActOnCXXConversionFunctionExpr - Parse a C++ conversion function
|
||||
/// name (e.g., operator void const *) as an expression. This is
|
||||
/// very similar to ActOnIdentifierExpr, except that instead of
|
||||
/// providing an identifier the parser provides the type of the
|
||||
/// conversion function.
|
||||
Sema::OwningExprResult
|
||||
Sema::ActOnCXXConversionFunctionExpr(Scope *S, SourceLocation OperatorLoc,
|
||||
TypeTy *Ty, bool HasTrailingLParen,
|
||||
const CXXScopeSpec &SS,
|
||||
bool isAddressOfOperand) {
|
||||
//FIXME: Preserve type source info.
|
||||
QualType ConvType = GetTypeFromParser(Ty);
|
||||
CanQualType ConvTypeCanon = Context.getCanonicalType(ConvType);
|
||||
DeclarationName ConvName
|
||||
= Context.DeclarationNames.getCXXConversionFunctionName(ConvTypeCanon);
|
||||
return ActOnDeclarationNameExpr(S, OperatorLoc, ConvName, HasTrailingLParen,
|
||||
&SS, isAddressOfOperand);
|
||||
}
|
||||
|
||||
/// ActOnCXXOperatorFunctionIdExpr - Parse a C++ overloaded operator
|
||||
/// name (e.g., @c operator+ ) as an expression. This is very
|
||||
/// similar to ActOnIdentifierExpr, except that instead of providing
|
||||
/// an identifier the parser provides the kind of overloaded
|
||||
/// operator that was parsed.
|
||||
Sema::OwningExprResult
|
||||
Sema::ActOnCXXOperatorFunctionIdExpr(Scope *S, SourceLocation OperatorLoc,
|
||||
OverloadedOperatorKind Op,
|
||||
bool HasTrailingLParen,
|
||||
const CXXScopeSpec &SS,
|
||||
bool isAddressOfOperand) {
|
||||
DeclarationName Name = Context.DeclarationNames.getCXXOperatorName(Op);
|
||||
return ActOnDeclarationNameExpr(S, OperatorLoc, Name, HasTrailingLParen, &SS,
|
||||
isAddressOfOperand);
|
||||
}
|
||||
|
||||
/// ActOnCXXTypeidOfType - Parse typeid( type-id ).
|
||||
Action::OwningExprResult
|
||||
Sema::ActOnCXXTypeid(SourceLocation OpLoc, SourceLocation LParenLoc,
|
||||
|
|
Загрузка…
Ссылка в новой задаче