Index: include/clang/AST/Expr.h =================================================================== --- include/clang/AST/Expr.h +++ include/clang/AST/Expr.h @@ -32,6 +32,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/Support/AtomicOrdering.h" #include "llvm/Support/Compiler.h" +#include "llvm/Support/TrailingObjects.h" namespace clang { class APValue; @@ -1204,64 +1205,6 @@ friend class ASTStmtWriter; }; -/// [C99 6.4.2.2] - A predefined identifier such as __func__. -class PredefinedExpr : public Expr { -public: - enum IdentType { - Func, - Function, - LFunction, // Same as Function, but as wide string. - FuncDName, - FuncSig, - LFuncSig, // Same as FuncSig, but as as wide string - PrettyFunction, - /// The same as PrettyFunction, except that the - /// 'virtual' keyword is omitted for virtual member functions. - PrettyFunctionNoVirtual - }; - -private: - SourceLocation Loc; - IdentType Type; - Stmt *FnName; - -public: - PredefinedExpr(SourceLocation L, QualType FNTy, IdentType IT, - StringLiteral *SL); - - /// Construct an empty predefined expression. - explicit PredefinedExpr(EmptyShell Empty) - : Expr(PredefinedExprClass, Empty), Loc(), Type(Func), FnName(nullptr) {} - - IdentType getIdentType() const { return Type; } - - SourceLocation getLocation() const { return Loc; } - void setLocation(SourceLocation L) { Loc = L; } - - StringLiteral *getFunctionName(); - const StringLiteral *getFunctionName() const { - return const_cast(this)->getFunctionName(); - } - - static StringRef getIdentTypeName(IdentType IT); - static std::string ComputeName(IdentType IT, const Decl *CurrentDecl); - - SourceLocation getBeginLoc() const LLVM_READONLY { return Loc; } - SourceLocation getEndLoc() const LLVM_READONLY { return Loc; } - - static bool classof(const Stmt *T) { - return T->getStmtClass() == PredefinedExprClass; - } - - // Iterators - child_range children() { return child_range(&FnName, &FnName + 1); } - const_child_range children() const { - return const_child_range(&FnName, &FnName + 1); - } - - friend class ASTStmtReader; -}; - /// Used by IntegerLiteral/FloatingLiteral to store the numeric without /// leaking memory. /// @@ -1732,6 +1675,90 @@ } }; +/// [C99 6.4.2.2] - A predefined identifier such as __func__. +class PredefinedExpr final + : public Expr, + private llvm::TrailingObjects { + friend class ASTStmtReader; + friend TrailingObjects; + + // PredefinedExpr is optionally followed by a single trailing + // "Stmt *" for the predefined identifier. It is present if and only if + // hasFunctionName() is true and is in fact a "StringLiteral *". + +public: + enum IdentType { + Func, + Function, + LFunction, // Same as Function, but as wide string. + FuncDName, + FuncSig, + LFuncSig, // Same as FuncSig, but as as wide string + PrettyFunction, + /// The same as PrettyFunction, except that the + /// 'virtual' keyword is omitted for virtual member functions. + PrettyFunctionNoVirtual + }; + +private: + PredefinedExpr(SourceLocation L, QualType FNTy, IdentType IT, + StringLiteral *SL); + + explicit PredefinedExpr(EmptyShell Empty, bool HasFunctionName); + + bool hasFunctionName() const { return PredefinedExprBits.HasFnName; } + + void setFunctionName(StringLiteral *SL) { + assert(hasFunctionName() && + "This PredefinedExpr has no storage for a function name!"); + *getTrailingObjects() = SL; + } + +public: + /// Create a PredefinedExpr. + static PredefinedExpr *Create(const ASTContext &Ctx, SourceLocation L, + QualType FNTy, IdentType IT, StringLiteral *SL); + + /// Create an empty PredefinedExpr. + static PredefinedExpr *CreateEmpty(const ASTContext &Ctx, + bool HasFunctionName); + + IdentType getIdentType() const { + return static_cast(PredefinedExprBits.Type); + } + + SourceLocation getLocation() const { return PredefinedExprBits.Loc; } + void setLocation(SourceLocation L) { PredefinedExprBits.Loc = L; } + + StringLiteral *getFunctionName() { + return hasFunctionName() + ? static_cast(*getTrailingObjects()) + : nullptr; + } + + const StringLiteral *getFunctionName() const { + return hasFunctionName() + ? static_cast(*getTrailingObjects()) + : nullptr; + } + + static StringRef getIdentTypeName(IdentType IT); + static std::string ComputeName(IdentType IT, const Decl *CurrentDecl); + + SourceLocation getBeginLoc() const { return getLocation(); } + SourceLocation getEndLoc() const { return getLocation(); } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == PredefinedExprClass; + } + + // Iterators + child_range children() { + return child_range(getTrailingObjects(), + getTrailingObjects() + hasFunctionName()); + } +}; + /// ParenExpr - This represents a parethesized expression, e.g. "(1)". This /// AST node is only formed if full location information is requested. class ParenExpr : public Expr { Index: include/clang/AST/Stmt.h =================================================================== --- include/clang/AST/Stmt.h +++ include/clang/AST/Stmt.h @@ -268,6 +268,24 @@ }; enum { NumExprBits = 17 }; + class PredefinedExprBitfields { + friend class ASTStmtReader; + friend class PredefinedExpr; + + unsigned : NumExprBits; + + /// The type of this PredefinedExpr. One of the enumeration values + /// in PredefinedExpr::IdentType. + unsigned Type : 4; + + /// True if this PredefinedExpr has a trailing "StringLiteral *" + /// for the predefined identifier. + unsigned HasFnName : 1; + + /// The location of this PredefinedExpr. + SourceLocation Loc; + }; + class CharacterLiteralBitfields { friend class CharacterLiteral; @@ -432,6 +450,7 @@ // Expressions ExprBitfields ExprBits; + PredefinedExprBitfields PredefinedExprBits; CharacterLiteralBitfields CharacterLiteralBits; FloatingLiteralBitfields FloatingLiteralBits; UnaryExprOrTypeTraitExprBitfields UnaryExprOrTypeTraitExprBits; Index: lib/AST/ASTImporter.cpp =================================================================== --- lib/AST/ASTImporter.cpp +++ lib/AST/ASTImporter.cpp @@ -6148,8 +6148,8 @@ StringLiteral *ToFunctionName; std::tie(ToBeginLoc, ToType, ToFunctionName) = *Imp; - return new (Importer.getToContext()) PredefinedExpr( - ToBeginLoc, ToType, E->getIdentType(), ToFunctionName); + return PredefinedExpr::Create(Importer.getToContext(), ToBeginLoc, ToType, + E->getIdentType(), ToFunctionName); } ExpectedStmt ASTNodeImporter::VisitDeclRefExpr(DeclRefExpr *E) { Index: lib/AST/Expr.cpp =================================================================== --- lib/AST/Expr.cpp +++ lib/AST/Expr.cpp @@ -463,11 +463,36 @@ : Expr(PredefinedExprClass, FNTy, VK_LValue, OK_Ordinary, FNTy->isDependentType(), FNTy->isDependentType(), FNTy->isInstantiationDependentType(), - /*ContainsUnexpandedParameterPack=*/false), - Loc(L), Type(IT), FnName(SL) {} - -StringLiteral *PredefinedExpr::getFunctionName() { - return cast_or_null(FnName); + /*ContainsUnexpandedParameterPack=*/false) { + PredefinedExprBits.Type = IT; + assert((getIdentType() == IT) && + "IdentType do not fit in PredefinedExprBitfields!"); + bool HasFunctionName = !!SL; + PredefinedExprBits.HasFnName = HasFunctionName; + PredefinedExprBits.Loc = L; + if (HasFunctionName) + setFunctionName(SL); +} + +PredefinedExpr::PredefinedExpr(EmptyShell Empty, bool HasFunctionName) + : Expr(PredefinedExprClass, Empty) { + PredefinedExprBits.HasFnName = HasFunctionName; +} + +PredefinedExpr *PredefinedExpr::Create(const ASTContext &Ctx, SourceLocation L, + QualType FNTy, IdentType IT, + StringLiteral *SL) { + bool HasFunctionName = !!SL; + void *Mem = Ctx.Allocate(totalSizeToAlloc(HasFunctionName), + alignof(PredefinedExpr)); + return new (Mem) PredefinedExpr(L, FNTy, IT, SL); +} + +PredefinedExpr *PredefinedExpr::CreateEmpty(const ASTContext &Ctx, + bool HasFunctionName) { + void *Mem = Ctx.Allocate(totalSizeToAlloc(HasFunctionName), + alignof(PredefinedExpr)); + return new (Mem) PredefinedExpr(EmptyShell(), HasFunctionName); } StringRef PredefinedExpr::getIdentTypeName(PredefinedExpr::IdentType IT) { Index: lib/Sema/SemaExpr.cpp =================================================================== --- lib/Sema/SemaExpr.cpp +++ lib/Sema/SemaExpr.cpp @@ -3083,7 +3083,7 @@ } } - return new (Context) PredefinedExpr(Loc, ResTy, IT, SL); + return PredefinedExpr::Create(Context, Loc, ResTy, IT, SL); } ExprResult Sema::ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind) { Index: lib/Serialization/ASTReaderStmt.cpp =================================================================== --- lib/Serialization/ASTReaderStmt.cpp +++ lib/Serialization/ASTReaderStmt.cpp @@ -496,9 +496,12 @@ void ASTStmtReader::VisitPredefinedExpr(PredefinedExpr *E) { VisitExpr(E); + bool HasFunctionName = Record.readInt(); + E->PredefinedExprBits.HasFnName = HasFunctionName; + E->PredefinedExprBits.Type = Record.readInt(); E->setLocation(ReadSourceLocation()); - E->Type = (PredefinedExpr::IdentType)Record.readInt(); - E->FnName = cast_or_null(Record.readSubExpr()); + if (HasFunctionName) + E->setFunctionName(cast(Record.readSubExpr())); } void ASTStmtReader::VisitDeclRefExpr(DeclRefExpr *E) { @@ -2334,12 +2337,14 @@ break; case STMT_CAPTURED: - S = CapturedStmt::CreateDeserialized(Context, - Record[ASTStmtReader::NumStmtFields]); + S = CapturedStmt::CreateDeserialized( + Context, Record[ASTStmtReader::NumStmtFields]); break; case EXPR_PREDEFINED: - S = new (Context) PredefinedExpr(Empty); + S = PredefinedExpr::CreateEmpty( + Context, + /*HasFunctionName*/ Record[ASTStmtReader::NumExprFields]); break; case EXPR_DECL_REF: Index: lib/Serialization/ASTWriterStmt.cpp =================================================================== --- lib/Serialization/ASTWriterStmt.cpp +++ lib/Serialization/ASTWriterStmt.cpp @@ -388,9 +388,13 @@ void ASTStmtWriter::VisitPredefinedExpr(PredefinedExpr *E) { VisitExpr(E); - Record.AddSourceLocation(E->getLocation()); + + bool HasFunctionName = !!E->getFunctionName(); + Record.push_back(HasFunctionName); Record.push_back(E->getIdentType()); // FIXME: stable encoding - Record.AddStmt(E->getFunctionName()); + Record.AddSourceLocation(E->getLocation()); + if (HasFunctionName) + Record.AddStmt(E->getFunctionName()); Code = serialization::EXPR_PREDEFINED; }