Index: include/clang/AST/Expr.h =================================================================== --- include/clang/AST/Expr.h +++ include/clang/AST/Expr.h @@ -1396,45 +1396,69 @@ } }; -class CharacterLiteral : public Expr { +class CharacterLiteral final + : public Expr, + private llvm::TrailingObjects { + friend class ASTReader; + friend class ASTStmtReader; + friend TrailingObjects; + public: - enum CharacterKind { - Ascii, - Wide, - UTF8, - UTF16, - UTF32 - }; + enum CharacterKind { Ascii, Wide, UTF8, UTF16, UTF32 }; private: - unsigned Value; - SourceLocation Loc; -public: - // type should be IntTy - CharacterLiteral(unsigned value, CharacterKind kind, QualType type, - SourceLocation l) - : Expr(CharacterLiteralClass, type, VK_RValue, OK_Ordinary, false, false, - false, false), - Value(value), Loc(l) { - CharacterLiteralBits.Kind = kind; + // The vast majority of character literals have a value which fits into + // 8 bits. For this reason in the common case the value is stored inline + // in CharacterLiteralBits and isSmallValue() is true. Otherwise the + // value is stored in a trailing unsigned and isSmallValue() is false. + // Note that the kind of the character literal do not matter for this. + // It is therefore perfectly possible to have an UTF32 character literal + // with its value stored inline, as long as the value is <= MaxSmallValue. + enum { MaxSmallValue = 255 }; + static bool isSmallValue(unsigned Val) { return Val <= MaxSmallValue; } + + /// True if the value of this character literal is stored inline. + bool isSmallValue() const { return CharacterLiteralBits.IsSmallValue; } + + + void setValue(unsigned Val) { + if (isSmallValue()) { + assert(isSmallValue(Val) && + "This value is too large to be stored in this CharacterLiteral!"); + CharacterLiteralBits.SmallValue = Val; + } else + *getTrailingObjects() = Val; } - /// Construct an empty character literal. - CharacterLiteral(EmptyShell Empty) : Expr(CharacterLiteralClass, Empty) { } + // Build a character literal. + CharacterLiteral(unsigned Value, CharacterKind Kind, QualType Type, + SourceLocation Loc); - SourceLocation getLocation() const { return Loc; } + /// Build an empty character literal. + CharacterLiteral(EmptyShell Empty, bool IsSmallValue); + +public: + /// Create a character literal. + static CharacterLiteral *Create(const ASTContext &Ctx, unsigned Value, + CharacterKind Kind, QualType Type, + SourceLocation Loc); + + /// Create a character literal, optionally with storage for a large value. + static CharacterLiteral *CreateEmpty(const ASTContext &Ctx, + bool IsSmallValue); + + SourceLocation getLocation() const { return CharacterLiteralBits.Loc; } CharacterKind getKind() const { return static_cast(CharacterLiteralBits.Kind); } - SourceLocation getBeginLoc() const LLVM_READONLY { return Loc; } - SourceLocation getEndLoc() const LLVM_READONLY { return Loc; } - - unsigned getValue() const { return Value; } + SourceLocation getBeginLoc() const { return getLocation(); } + SourceLocation getEndLoc() const { return getLocation(); } - void setLocation(SourceLocation Location) { Loc = Location; } - void setKind(CharacterKind kind) { CharacterLiteralBits.Kind = kind; } - void setValue(unsigned Val) { Value = Val; } + unsigned getValue() const { + return isSmallValue() ? CharacterLiteralBits.SmallValue + : *getTrailingObjects(); + } static bool classof(const Stmt *T) { return T->getStmtClass() == CharacterLiteralClass; Index: include/clang/AST/Stmt.h =================================================================== --- include/clang/AST/Stmt.h +++ include/clang/AST/Stmt.h @@ -361,11 +361,21 @@ }; class CharacterLiteralBitfields { + friend class ASTStmtReader; friend class CharacterLiteral; unsigned : NumExprBits; unsigned Kind : 3; + + /// The vast majority of character literals have a value which fits into + /// 8 bits. In this case this value is stored here and IsSmallValue + /// is true. Otherwise, the value is stored as a trailing object and + /// IsSmallValue is false. + unsigned SmallValue : 8; + unsigned IsSmallValue : 1; + + SourceLocation Loc; }; enum APFloatSemantics { Index: lib/AST/ASTImporter.cpp =================================================================== --- lib/AST/ASTImporter.cpp +++ lib/AST/ASTImporter.cpp @@ -6289,8 +6289,8 @@ if (!ToLocationOrErr) return ToLocationOrErr.takeError(); - return new (Importer.getToContext()) CharacterLiteral( - E->getValue(), E->getKind(), *ToTypeOrErr, *ToLocationOrErr); + return CharacterLiteral::Create(Importer.getToContext(), E->getValue(), + E->getKind(), *ToTypeOrErr, *ToLocationOrErr); } ExpectedStmt ASTNodeImporter::VisitStringLiteral(StringLiteral *E) { Index: lib/AST/Expr.cpp =================================================================== --- lib/AST/Expr.cpp +++ lib/AST/Expr.cpp @@ -815,6 +815,37 @@ return S.str(); } +CharacterLiteral::CharacterLiteral(unsigned Value, CharacterKind Kind, + QualType Type, SourceLocation Loc) + : Expr(CharacterLiteralClass, Type, VK_RValue, OK_Ordinary, false, false, + false, false) { + CharacterLiteralBits.Kind = Kind; + CharacterLiteralBits.Loc = Loc; + CharacterLiteralBits.IsSmallValue = isSmallValue(Value); + setValue(Value); +} + +CharacterLiteral::CharacterLiteral(EmptyShell Empty, bool IsSmallValue) + : Expr(CharacterLiteralClass, Empty) { + CharacterLiteralBits.IsSmallValue = IsSmallValue; +} + +CharacterLiteral *CharacterLiteral::Create(const ASTContext &Ctx, + unsigned Value, CharacterKind Kind, + QualType Type, SourceLocation Loc) { + bool IsSmallValue = isSmallValue(Value); + void *Mem = Ctx.Allocate(totalSizeToAlloc(!IsSmallValue), + alignof(CharacterLiteral)); + return new (Mem) CharacterLiteral(Value, Kind, Type, Loc); +} + +CharacterLiteral *CharacterLiteral::CreateEmpty(const ASTContext &Ctx, + bool IsSmallValue) { + void *Mem = Ctx.Allocate(totalSizeToAlloc(!IsSmallValue), + alignof(CharacterLiteral)); + return new (Mem) CharacterLiteral(EmptyShell(), IsSmallValue); +} + FloatingLiteral::FloatingLiteral(const ASTContext &C, const llvm::APFloat &V, bool isexact, QualType Type, SourceLocation L) : Expr(FloatingLiteralClass, Type, VK_RValue, OK_Ordinary, false, false, Index: lib/Sema/SemaExpr.cpp =================================================================== --- lib/Sema/SemaExpr.cpp +++ lib/Sema/SemaExpr.cpp @@ -3139,8 +3139,8 @@ else if (Literal.isUTF8()) Kind = CharacterLiteral::UTF8; - Expr *Lit = new (Context) CharacterLiteral(Literal.getValue(), Kind, Ty, - Tok.getLocation()); + Expr *Lit = CharacterLiteral::Create(Context, Literal.getValue(), Kind, Ty, + Tok.getLocation()); if (Literal.getUDSuffix().empty()) return Lit; Index: lib/Sema/SemaTemplate.cpp =================================================================== --- lib/Sema/SemaTemplate.cpp +++ lib/Sema/SemaTemplate.cpp @@ -6865,8 +6865,9 @@ else Kind = CharacterLiteral::Ascii; - E = new (Context) CharacterLiteral(Arg.getAsIntegral().getZExtValue(), - Kind, T, Loc); + E = CharacterLiteral::Create(Context, Arg.getAsIntegral().getZExtValue(), + Kind, T, Loc); + } else if (T->isBooleanType()) { E = new (Context) CXXBoolLiteralExpr(Arg.getAsIntegral().getBoolValue(), T, Loc); Index: lib/Serialization/ASTReaderStmt.cpp =================================================================== --- lib/Serialization/ASTReaderStmt.cpp +++ lib/Serialization/ASTReaderStmt.cpp @@ -636,8 +636,8 @@ void ASTStmtReader::VisitCharacterLiteral(CharacterLiteral *E) { VisitExpr(E); E->setValue(Record.readInt()); - E->setLocation(ReadSourceLocation()); - E->setKind(static_cast(Record.readInt())); + E->CharacterLiteralBits.Loc = ReadSourceLocation(); + E->CharacterLiteralBits.Kind = Record.readInt(); } void ASTStmtReader::VisitParenExpr(ParenExpr *E) { @@ -2454,7 +2454,10 @@ break; case EXPR_CHARACTER_LITERAL: - S = new (Context) CharacterLiteral(Empty); + S = CharacterLiteral::CreateEmpty( + Context, + /* IsSmallValue=*/CharacterLiteral::isSmallValue( + Record[ASTStmtReader::NumExprFields + 0])); break; case EXPR_PAREN: