Index: include/clang/AST/ExprCXX.h =================================================================== --- include/clang/AST/ExprCXX.h +++ include/clang/AST/ExprCXX.h @@ -3306,7 +3306,11 @@ : public Expr, private llvm::TrailingObjects { + TemplateArgumentLoc, NamedDecl *> { + friend class ASTStmtReader; + friend class ASTStmtWriter; + friend TrailingObjects; + /// The expression for the base pointer or class reference, /// e.g., the \c x in x.f. Can be null in implicit accesses. Stmt *Base; @@ -3315,40 +3319,53 @@ /// implicit accesses. QualType BaseType; - /// Whether this member expression used the '->' operator or - /// the '.' operator. - bool IsArrow : 1; - - /// Whether this member expression has info for explicit template - /// keyword and arguments. - bool HasTemplateKWAndArgsInfo : 1; - - /// The location of the '->' or '.' operator. - SourceLocation OperatorLoc; - /// The nested-name-specifier that precedes the member name, if any. + /// FIXME: This could be in principle store as a trailing object. + /// However the performance impact of doing so should be investigated first. NestedNameSpecifierLoc QualifierLoc; - /// In a qualified member access expression such as t->Base::f, this - /// member stores the resolves of name lookup in the context of the member - /// access expression, to be used at instantiation time. - /// - /// FIXME: This member, along with the QualifierLoc, could - /// be stuck into a structure that is optionally allocated at the end of - /// the CXXDependentScopeMemberExpr, to save space in the common case. - NamedDecl *FirstQualifierFoundInScope; - /// The member to which this member expression refers, which /// can be name, overloaded operator, or destructor. /// /// FIXME: could also be a template-id DeclarationNameInfo MemberNameInfo; - size_t numTrailingObjects(OverloadToken) const { - return HasTemplateKWAndArgsInfo ? 1 : 0; + // CXXDependentScopeMemberExpr is followed by several trailing objects, + // some of which optional. They are in order: + // + // * An optional ASTTemplateKWAndArgsInfo for the explicitly specified + // template keyword and arguments. Present if and only if + // hasTemplateKWAndArgsInfo(). + // + // * An array of getNumTemplateArgs() TemplateArgumentLoc containing location + // information for the explicitly specified template arguments. + // + // * An optional NamedDecl *. In a qualified member access expression such + // as t->Base::f, this member stores the resolves of name lookup in the + // context of the member access expression, to be used at instantiation + // time. Present if and only if hasFirstQualifierFoundInScope(). + + bool hasTemplateKWAndArgsInfo() const { + return CXXDependentScopeMemberExprBits.HasTemplateKWAndArgsInfo; + } + + bool hasFirstQualifierFoundInScope() const { + return CXXDependentScopeMemberExprBits.HasFirstQualifierFoundInScope; } - CXXDependentScopeMemberExpr(const ASTContext &C, Expr *Base, + unsigned numTrailingObjects(OverloadToken) const { + return hasTemplateKWAndArgsInfo(); + } + + unsigned numTrailingObjects(OverloadToken) const { + return getNumTemplateArgs(); + } + + unsigned numTrailingObjects(OverloadToken) const { + return hasFirstQualifierFoundInScope(); + } + + CXXDependentScopeMemberExpr(const ASTContext &Ctx, Expr *Base, QualType BaseType, bool IsArrow, SourceLocation OperatorLoc, NestedNameSpecifierLoc QualifierLoc, @@ -3357,33 +3374,29 @@ DeclarationNameInfo MemberNameInfo, const TemplateArgumentListInfo *TemplateArgs); -public: - friend class ASTStmtReader; - friend class ASTStmtWriter; - friend TrailingObjects; - - CXXDependentScopeMemberExpr(const ASTContext &C, Expr *Base, - QualType BaseType, bool IsArrow, - SourceLocation OperatorLoc, - NestedNameSpecifierLoc QualifierLoc, - NamedDecl *FirstQualifierFoundInScope, - DeclarationNameInfo MemberNameInfo); + CXXDependentScopeMemberExpr(EmptyShell Empty, bool HasTemplateKWAndArgsInfo, + bool HasFirstQualifierFoundInScope); +public: static CXXDependentScopeMemberExpr * - Create(const ASTContext &C, Expr *Base, QualType BaseType, bool IsArrow, + Create(const ASTContext &Ctx, Expr *Base, QualType BaseType, bool IsArrow, SourceLocation OperatorLoc, NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc, NamedDecl *FirstQualifierFoundInScope, DeclarationNameInfo MemberNameInfo, const TemplateArgumentListInfo *TemplateArgs); static CXXDependentScopeMemberExpr * - CreateEmpty(const ASTContext &C, bool HasTemplateKWAndArgsInfo, - unsigned NumTemplateArgs); + CreateEmpty(const ASTContext &Ctx, bool HasTemplateKWAndArgsInfo, + unsigned NumTemplateArgs, bool HasFirstQualifierFoundInScope); /// True if this is an implicit access, i.e. one in which the /// member being accessed was not written in the source. The source /// location of the operator is invalid in this case. - bool isImplicitAccess() const; + bool isImplicitAccess() const { + if (!Base) + return true; + return cast(Base)->isImplicitCXXThis(); + } /// Retrieve the base object of this member expressions, /// e.g., the \c x in \c x.m. @@ -3396,13 +3409,14 @@ /// Determine whether this member expression used the '->' /// operator; otherwise, it used the '.' operator. - bool isArrow() const { return IsArrow; } + bool isArrow() const { return CXXDependentScopeMemberExprBits.IsArrow; } /// Retrieve the location of the '->' or '.' operator. - SourceLocation getOperatorLoc() const { return OperatorLoc; } + SourceLocation getOperatorLoc() const { + return CXXDependentScopeMemberExprBits.OperatorLoc; + } - /// Retrieve the nested-name-specifier that qualifies the member - /// name. + /// Retrieve the nested-name-specifier that qualifies the member name. NestedNameSpecifier *getQualifier() const { return QualifierLoc.getNestedNameSpecifier(); } @@ -3423,17 +3437,17 @@ /// combined with the results of name lookup into the type of the object /// expression itself (the class type of x). NamedDecl *getFirstQualifierFoundInScope() const { - return FirstQualifierFoundInScope; + if (!hasFirstQualifierFoundInScope()) + return nullptr; + return *getTrailingObjects(); } - /// Retrieve the name of the member that this expression - /// refers to. + /// Retrieve the name of the member that this expression refers to. const DeclarationNameInfo &getMemberNameInfo() const { return MemberNameInfo; } - /// Retrieve the name of the member that this expression - /// refers to. + /// Retrieve the name of the member that this expression refers to. DeclarationName getMember() const { return MemberNameInfo.getName(); } // Retrieve the location of the name of the member that this @@ -3443,21 +3457,24 @@ /// Retrieve the location of the template keyword preceding the /// member name, if any. SourceLocation getTemplateKeywordLoc() const { - if (!HasTemplateKWAndArgsInfo) return SourceLocation(); + if (!hasTemplateKWAndArgsInfo()) + return SourceLocation(); return getTrailingObjects()->TemplateKWLoc; } /// Retrieve the location of the left angle bracket starting the /// explicit template argument list following the member name, if any. SourceLocation getLAngleLoc() const { - if (!HasTemplateKWAndArgsInfo) return SourceLocation(); + if (!hasTemplateKWAndArgsInfo()) + return SourceLocation(); return getTrailingObjects()->LAngleLoc; } /// Retrieve the location of the right angle bracket ending the /// explicit template argument list following the member name, if any. SourceLocation getRAngleLoc() const { - if (!HasTemplateKWAndArgsInfo) return SourceLocation(); + if (!hasTemplateKWAndArgsInfo()) + return SourceLocation(); return getTrailingObjects()->RAngleLoc; } Index: include/clang/AST/Stmt.h =================================================================== --- include/clang/AST/Stmt.h +++ include/clang/AST/Stmt.h @@ -738,6 +738,28 @@ unsigned NumArgs; }; + class CXXDependentScopeMemberExprBitfields { + friend class ASTStmtReader; + friend class CXXDependentScopeMemberExpr; + + unsigned : NumExprBits; + + /// Whether this member expression used the '->' operator or + /// the '.' operator. + unsigned IsArrow : 1; + + /// Whether this member expression has info for explicit template + /// keyword and arguments. + unsigned HasTemplateKWAndArgsInfo : 1; + + /// See getFirstQualifierFoundInScope() and the comment listing + /// the trailing objects. + unsigned HasFirstQualifierFoundInScope : 1; + + /// The location of the '->' or '.' operator. + SourceLocation OperatorLoc; + }; + //===--- C++ Coroutines TS bitfields classes ---===// class CoawaitExprBitfields { @@ -825,6 +847,7 @@ CXXConstructExprBitfields CXXConstructExprBits; ExprWithCleanupsBitfields ExprWithCleanupsBits; CXXUnresolvedConstructExprBitfields CXXUnresolvedConstructExprBits; + CXXDependentScopeMemberExprBitfields CXXDependentScopeMemberExprBits; // C++ Coroutines TS expressions CoawaitExprBitfields CoawaitBits; Index: lib/AST/ExprCXX.cpp =================================================================== --- lib/AST/ExprCXX.cpp +++ lib/AST/ExprCXX.cpp @@ -1301,24 +1301,26 @@ } CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr( - const ASTContext &C, Expr *Base, QualType BaseType, bool IsArrow, + const ASTContext &Ctx, Expr *Base, QualType BaseType, bool IsArrow, SourceLocation OperatorLoc, NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc, NamedDecl *FirstQualifierFoundInScope, DeclarationNameInfo MemberNameInfo, const TemplateArgumentListInfo *TemplateArgs) - : Expr(CXXDependentScopeMemberExprClass, C.DependentTy, VK_LValue, + : Expr(CXXDependentScopeMemberExprClass, Ctx.DependentTy, VK_LValue, OK_Ordinary, true, true, true, ((Base && Base->containsUnexpandedParameterPack()) || - (QualifierLoc && - QualifierLoc.getNestedNameSpecifier() - ->containsUnexpandedParameterPack()) || + (QualifierLoc && QualifierLoc.getNestedNameSpecifier() + ->containsUnexpandedParameterPack()) || MemberNameInfo.containsUnexpandedParameterPack())), - Base(Base), BaseType(BaseType), IsArrow(IsArrow), - HasTemplateKWAndArgsInfo(TemplateArgs != nullptr || - TemplateKWLoc.isValid()), - OperatorLoc(OperatorLoc), QualifierLoc(QualifierLoc), - FirstQualifierFoundInScope(FirstQualifierFoundInScope), + Base(Base), BaseType(BaseType), QualifierLoc(QualifierLoc), MemberNameInfo(MemberNameInfo) { + CXXDependentScopeMemberExprBits.IsArrow = IsArrow; + CXXDependentScopeMemberExprBits.HasTemplateKWAndArgsInfo = + (TemplateArgs != nullptr) || TemplateKWLoc.isValid(); + CXXDependentScopeMemberExprBits.HasFirstQualifierFoundInScope = + FirstQualifierFoundInScope != nullptr; + CXXDependentScopeMemberExprBits.OperatorLoc = OperatorLoc; + if (TemplateArgs) { bool Dependent = true; bool InstantiationDependent = true; @@ -1332,56 +1334,54 @@ getTrailingObjects()->initializeFrom( TemplateKWLoc); } + + if (hasFirstQualifierFoundInScope()) + *getTrailingObjects() = FirstQualifierFoundInScope; } -CXXDependentScopeMemberExpr * -CXXDependentScopeMemberExpr::Create(const ASTContext &C, - Expr *Base, QualType BaseType, bool IsArrow, - SourceLocation OperatorLoc, - NestedNameSpecifierLoc QualifierLoc, - SourceLocation TemplateKWLoc, - NamedDecl *FirstQualifierFoundInScope, - DeclarationNameInfo MemberNameInfo, - const TemplateArgumentListInfo *TemplateArgs) { - bool HasTemplateKWAndArgsInfo = TemplateArgs || TemplateKWLoc.isValid(); +CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr( + EmptyShell Empty, bool HasTemplateKWAndArgsInfo, + bool HasFirstQualifierFoundInScope) + : Expr(CXXDependentScopeMemberExprClass, Empty) { + CXXDependentScopeMemberExprBits.HasTemplateKWAndArgsInfo = + HasTemplateKWAndArgsInfo; + CXXDependentScopeMemberExprBits.HasFirstQualifierFoundInScope = + HasFirstQualifierFoundInScope; +} + +CXXDependentScopeMemberExpr *CXXDependentScopeMemberExpr::Create( + const ASTContext &Ctx, Expr *Base, QualType BaseType, bool IsArrow, + SourceLocation OperatorLoc, NestedNameSpecifierLoc QualifierLoc, + SourceLocation TemplateKWLoc, NamedDecl *FirstQualifierFoundInScope, + DeclarationNameInfo MemberNameInfo, + const TemplateArgumentListInfo *TemplateArgs) { + bool HasTemplateKWAndArgsInfo = + (TemplateArgs != nullptr) || TemplateKWLoc.isValid(); unsigned NumTemplateArgs = TemplateArgs ? TemplateArgs->size() : 0; - std::size_t Size = - totalSizeToAlloc( - HasTemplateKWAndArgsInfo, NumTemplateArgs); + bool HasFirstQualifierFoundInScope = FirstQualifierFoundInScope != nullptr; - void *Mem = C.Allocate(Size, alignof(CXXDependentScopeMemberExpr)); - return new (Mem) CXXDependentScopeMemberExpr(C, Base, BaseType, - IsArrow, OperatorLoc, - QualifierLoc, - TemplateKWLoc, - FirstQualifierFoundInScope, - MemberNameInfo, TemplateArgs); -} + unsigned Size = totalSizeToAlloc( + HasTemplateKWAndArgsInfo, NumTemplateArgs, HasFirstQualifierFoundInScope); -CXXDependentScopeMemberExpr * -CXXDependentScopeMemberExpr::CreateEmpty(const ASTContext &C, - bool HasTemplateKWAndArgsInfo, - unsigned NumTemplateArgs) { - assert(NumTemplateArgs == 0 || HasTemplateKWAndArgsInfo); - std::size_t Size = - totalSizeToAlloc( - HasTemplateKWAndArgsInfo, NumTemplateArgs); - void *Mem = C.Allocate(Size, alignof(CXXDependentScopeMemberExpr)); - auto *E = - new (Mem) CXXDependentScopeMemberExpr(C, nullptr, QualType(), - false, SourceLocation(), - NestedNameSpecifierLoc(), - SourceLocation(), nullptr, - DeclarationNameInfo(), nullptr); - E->HasTemplateKWAndArgsInfo = HasTemplateKWAndArgsInfo; - return E; + void *Mem = Ctx.Allocate(Size, alignof(CXXDependentScopeMemberExpr)); + return new (Mem) CXXDependentScopeMemberExpr( + Ctx, Base, BaseType, IsArrow, OperatorLoc, QualifierLoc, TemplateKWLoc, + FirstQualifierFoundInScope, MemberNameInfo, TemplateArgs); } -bool CXXDependentScopeMemberExpr::isImplicitAccess() const { - if (!Base) - return true; +CXXDependentScopeMemberExpr *CXXDependentScopeMemberExpr::CreateEmpty( + const ASTContext &Ctx, bool HasTemplateKWAndArgsInfo, + unsigned NumTemplateArgs, bool HasFirstQualifierFoundInScope) { + assert(NumTemplateArgs == 0 || HasTemplateKWAndArgsInfo); - return cast(Base)->isImplicitCXXThis(); + unsigned Size = totalSizeToAlloc( + HasTemplateKWAndArgsInfo, NumTemplateArgs, HasFirstQualifierFoundInScope); + + void *Mem = Ctx.Allocate(Size, alignof(CXXDependentScopeMemberExpr)); + return new (Mem) CXXDependentScopeMemberExpr( + EmptyShell(), HasTemplateKWAndArgsInfo, HasFirstQualifierFoundInScope); } static bool hasOnlyNonStaticMemberFunctions(UnresolvedSetIterator begin, Index: lib/Serialization/ASTReaderStmt.cpp =================================================================== --- lib/Serialization/ASTReaderStmt.cpp +++ lib/Serialization/ASTReaderStmt.cpp @@ -1584,22 +1584,37 @@ E->SubExpr = Record.readSubExpr(); } -void -ASTStmtReader::VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *E){ +void ASTStmtReader::VisitCXXDependentScopeMemberExpr( + CXXDependentScopeMemberExpr *E) { VisitExpr(E); - if (Record.readInt()) // HasTemplateKWAndArgsInfo + bool HasTemplateKWAndArgsInfo = Record.readInt(); + unsigned NumTemplateArgs = Record.readInt(); + bool HasFirstQualifierFoundInScope = Record.readInt(); + + assert((HasTemplateKWAndArgsInfo == E->hasTemplateKWAndArgsInfo()) && + "Wrong HasTemplateKWAndArgsInfo!"); + assert( + (HasFirstQualifierFoundInScope == E->hasFirstQualifierFoundInScope()) && + "Wrong HasFirstQualifierFoundInScope!"); + + if (HasTemplateKWAndArgsInfo) ReadTemplateKWAndArgsInfo( *E->getTrailingObjects(), - E->getTrailingObjects(), - /*NumTemplateArgs=*/Record.readInt()); + E->getTrailingObjects(), NumTemplateArgs); - E->Base = Record.readSubExpr(); + assert((NumTemplateArgs == E->getNumTemplateArgs()) && + "Wrong NumTemplateArgs!"); + + E->CXXDependentScopeMemberExprBits.IsArrow = Record.readInt(); + E->CXXDependentScopeMemberExprBits.OperatorLoc = ReadSourceLocation(); E->BaseType = Record.readType(); - E->IsArrow = Record.readInt(); - E->OperatorLoc = ReadSourceLocation(); E->QualifierLoc = Record.readNestedNameSpecifierLoc(); - E->FirstQualifierFoundInScope = ReadDeclAs(); + E->Base = Record.readSubExpr(); + + if (HasFirstQualifierFoundInScope) + *E->getTrailingObjects() = ReadDeclAs(); + ReadDeclarationNameInfo(E->MemberNameInfo); } @@ -3224,11 +3239,12 @@ break; case EXPR_CXX_DEPENDENT_SCOPE_MEMBER: - S = CXXDependentScopeMemberExpr::CreateEmpty(Context, - /*HasTemplateKWAndArgsInfo=*/Record[ASTStmtReader::NumExprFields], - /*NumTemplateArgs=*/Record[ASTStmtReader::NumExprFields] - ? Record[ASTStmtReader::NumExprFields + 1] - : 0); + S = CXXDependentScopeMemberExpr::CreateEmpty( + Context, + /*HasTemplateKWAndArgsInfo=*/Record[ASTStmtReader::NumExprFields], + /*NumTemplateArgs=*/Record[ASTStmtReader::NumExprFields + 1], + /*HasFirstQualifierFoundInScope=*/ + Record[ASTStmtReader::NumExprFields + 2]); break; case EXPR_CXX_DEPENDENT_SCOPE_DECL_REF: Index: lib/Serialization/ASTWriterStmt.cpp =================================================================== --- lib/Serialization/ASTWriterStmt.cpp +++ lib/Serialization/ASTWriterStmt.cpp @@ -1554,31 +1554,36 @@ Code = serialization::EXPR_EXPR_WITH_CLEANUPS; } -void -ASTStmtWriter::VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *E){ +void ASTStmtWriter::VisitCXXDependentScopeMemberExpr( + CXXDependentScopeMemberExpr *E) { VisitExpr(E); - // Don't emit anything here, HasTemplateKWAndArgsInfo must be - // emitted first. + // Don't emit anything here (or if you do you will have to update + // the corresponding deserialization function). - Record.push_back(E->HasTemplateKWAndArgsInfo); - if (E->HasTemplateKWAndArgsInfo) { + Record.push_back(E->hasTemplateKWAndArgsInfo()); + Record.push_back(E->getNumTemplateArgs()); + Record.push_back(E->hasFirstQualifierFoundInScope()); + + if (E->hasTemplateKWAndArgsInfo()) { const ASTTemplateKWAndArgsInfo &ArgInfo = *E->getTrailingObjects(); - Record.push_back(ArgInfo.NumTemplateArgs); AddTemplateKWAndArgsInfo(ArgInfo, E->getTrailingObjects()); } + Record.push_back(E->isArrow()); + Record.AddSourceLocation(E->getOperatorLoc()); + Record.AddTypeRef(E->getBaseType()); + Record.AddNestedNameSpecifierLoc(E->getQualifierLoc()); if (!E->isImplicitAccess()) Record.AddStmt(E->getBase()); else Record.AddStmt(nullptr); - Record.AddTypeRef(E->getBaseType()); - Record.push_back(E->isArrow()); - Record.AddSourceLocation(E->getOperatorLoc()); - Record.AddNestedNameSpecifierLoc(E->getQualifierLoc()); - Record.AddDeclRef(E->getFirstQualifierFoundInScope()); + + if (E->hasFirstQualifierFoundInScope()) + Record.AddDeclRef(E->getFirstQualifierFoundInScope()); + Record.AddDeclarationNameInfo(E->MemberNameInfo); Code = serialization::EXPR_CXX_DEPENDENT_SCOPE_MEMBER; }