union {
uintptr_t TypeOrValue;
struct {
- char Value[sizeof(llvm::APSInt)];
+ // We store a decomposed APSInt with the data allocated by ASTContext if
+ // BitWidth > 64. The memory may be shared between multiple
+ // TemplateArgument instances.
+ union {
+ uint64_t VAL; ///< Used to store the <= 64 bits integer value.
+ const uint64_t *pVal; ///< Used to store the >64 bits integer value.
+ };
+ unsigned BitWidth : 31;
+ unsigned IsUnsigned : 1;
void *Type;
} Integer;
struct {
TypeOrValue = reinterpret_cast<uintptr_t>(D);
}
- /// \brief Construct an integral constant template argument.
- TemplateArgument(const llvm::APSInt &Value, QualType Type) : Kind(Integral) {
- // FIXME: Large integral values will get leaked. Do something
- // similar to what we did with IntegerLiteral.
- new (Integer.Value) llvm::APSInt(Value);
+ /// \brief Construct an integral constant template argument. The memory to
+ /// store the value is allocated with Ctx.
+ TemplateArgument(ASTContext &Ctx, const llvm::APSInt &Value, QualType Type);
+
+ /// \brief Construct an integral constant template argument with the same
+ /// value as Other but a different type.
+ TemplateArgument(const TemplateArgument &Other, QualType Type)
+ : Kind(Integral) {
+ Integer = Other.Integer;
Integer.Type = Type.getAsOpaquePtr();
}
this->Args.NumArgs = NumArgs;
}
- /// \brief Copy constructor for a template argument.
- TemplateArgument(const TemplateArgument &Other) : Kind(Other.Kind) {
- // FIXME: Large integral values will get leaked. Do something
- // similar to what we did with IntegerLiteral.
- if (Kind == Integral) {
- new (Integer.Value) llvm::APSInt(*Other.getAsIntegral());
- Integer.Type = Other.Integer.Type;
- } else if (Kind == Pack) {
- Args.NumArgs = Other.Args.NumArgs;
- Args.Args = Other.Args.Args;
- } else if (Kind == Template || Kind == TemplateExpansion) {
- TemplateArg.Name = Other.TemplateArg.Name;
- TemplateArg.NumExpansions = Other.TemplateArg.NumExpansions;
- } else
- TypeOrValue = Other.TypeOrValue;
- }
-
- TemplateArgument& operator=(const TemplateArgument& Other) {
- using llvm::APSInt;
-
- if (Kind == Other.Kind && Kind == Integral) {
- // Copy integral values.
- *this->getAsIntegral() = *Other.getAsIntegral();
- Integer.Type = Other.Integer.Type;
- return *this;
- }
-
- // Destroy the current integral value, if that's what we're holding.
- if (Kind == Integral)
- getAsIntegral()->~APSInt();
-
- Kind = Other.Kind;
-
- if (Other.Kind == Integral) {
- new (Integer.Value) llvm::APSInt(*Other.getAsIntegral());
- Integer.Type = Other.Integer.Type;
- } else if (Other.Kind == Pack) {
- Args.NumArgs = Other.Args.NumArgs;
- Args.Args = Other.Args.Args;
- } else if (Kind == Template || Kind == TemplateExpansion) {
- TemplateArg.Name = Other.TemplateArg.Name;
- TemplateArg.NumExpansions = Other.TemplateArg.NumExpansions;
- } else {
- TypeOrValue = Other.TypeOrValue;
- }
-
- return *this;
- }
-
- ~TemplateArgument() {
- using llvm::APSInt;
-
- if (Kind == Integral)
- getAsIntegral()->~APSInt();
- }
-
/// \brief Create a new template argument pack by copying the given set of
/// template arguments.
static TemplateArgument CreatePackCopy(ASTContext &Context,
llvm::Optional<unsigned> getNumTemplateExpansions() const;
/// \brief Retrieve the template argument as an integral value.
- llvm::APSInt *getAsIntegral() {
- if (Kind != Integral)
- return 0;
- return reinterpret_cast<llvm::APSInt*>(&Integer.Value[0]);
- }
-
- const llvm::APSInt *getAsIntegral() const {
- return const_cast<TemplateArgument*>(this)->getAsIntegral();
+ // FIXME: Provide a way to read the integral data without copying the value.
+ llvm::APSInt getAsIntegral() const {
+ if (Integer.BitWidth <= 64)
+ return llvm::APSInt(llvm::APInt(Integer.BitWidth, Integer.VAL),
+ Integer.IsUnsigned);
+ return llvm::APSInt(llvm::APInt(Integer.BitWidth,
+ llvm::makeArrayRef(Integer.pVal, Integer.BitWidth / 8)),
+ Integer.IsUnsigned);
}
/// \brief Retrieve the type of the integral value.
/// \brief Construct an integral non-type template argument that
/// has been deduced, possibly from an array bound.
- DeducedTemplateArgument(const llvm::APSInt &Value,
+ DeducedTemplateArgument(ASTContext &Ctx,
+ const llvm::APSInt &Value,
QualType ValueType,
bool DeducedFromArrayBound)
- : TemplateArgument(Value, ValueType),
+ : TemplateArgument(Ctx, Value, ValueType),
DeducedFromArrayBound(DeducedFromArrayBound) { }
/// \brief For a non-type template argument, determine whether the
Arg.getNumTemplateExpansions());
case TemplateArgument::Integral:
- return TemplateArgument(*Arg.getAsIntegral(),
- getCanonicalType(Arg.getIntegralType()));
+ return TemplateArgument(Arg, getCanonicalType(Arg.getIntegralType()));
case TemplateArgument::Type:
return TemplateArgument(getCanonicalType(Arg.getAsType()));
Arg2.getIntegralType()))
return false;
- return IsSameValue(*Arg1.getAsIntegral(), *Arg2.getAsIntegral());
+ return IsSameValue(Arg1.getAsIntegral(), Arg2.getAsIntegral());
case TemplateArgument::Declaration:
if (!Arg1.getAsDecl() || !Arg2.getAsDecl())
QualType ToType = Importer.Import(From.getIntegralType());
if (ToType.isNull())
return TemplateArgument();
- return TemplateArgument(*From.getAsIntegral(), ToType);
+ return TemplateArgument(From, ToType);
}
case TemplateArgument::Declaration:
}
case TemplateArgument::Integral: {
push("integer");
- setInteger("value", *A.getAsIntegral());
+ setInteger("value", A.getAsIntegral());
completeAttrs();
pop();
break;
break;
}
case TemplateArgument::Integral:
- mangleIntegerLiteral(A.getIntegralType(), *A.getAsIntegral());
+ mangleIntegerLiteral(A.getIntegralType(), A.getAsIntegral());
break;
case TemplateArgument::Declaration: {
assert(P && "Missing template parameter for declaration argument");
mangleType(TA.getAsType());
break;
case TemplateArgument::Integral:
- mangleIntegerLiteral(TA.getIntegralType(), *TA.getAsIntegral());
+ mangleIntegerLiteral(TA.getIntegralType(), TA.getAsIntegral());
break;
default: {
// Issue a diagnostic.
const TemplateArgument &Pack = Args->get(0);
for (TemplateArgument::pack_iterator I = Pack.pack_begin(),
E = Pack.pack_end(); I != E; ++I) {
- char C = (char)I->getAsIntegral()->getZExtValue();
+ char C = (char)I->getAsIntegral().getZExtValue();
OS << C;
}
break;
break;
case TemplateArgument::Integral:
- Arg.getAsIntegral()->Profile(ID);
+ Arg.getAsIntegral().Profile(ID);
VisitType(Arg.getIntegralType());
break;
static void printIntegral(const TemplateArgument &TemplArg,
raw_ostream &Out) {
const ::clang::Type *T = TemplArg.getIntegralType().getTypePtr();
- const llvm::APSInt *Val = TemplArg.getAsIntegral();
+ const llvm::APSInt &Val = TemplArg.getAsIntegral();
if (T->isBooleanType()) {
- Out << (Val->getBoolValue() ? "true" : "false");
+ Out << (Val.getBoolValue() ? "true" : "false");
} else if (T->isCharType()) {
- const char Ch = Val->getZExtValue();
+ const char Ch = Val.getZExtValue();
Out << ((Ch == '\'') ? "'\\" : "'");
Out.write_escaped(StringRef(&Ch, 1), /*UseHexEscapes=*/ true);
Out << "'";
} else {
- Out << Val->toString(10);
+ Out << Val;
}
}
// TemplateArgument Implementation
//===----------------------------------------------------------------------===//
+TemplateArgument::TemplateArgument(ASTContext &Ctx, const llvm::APSInt &Value,
+ QualType Type)
+ : Kind(Integral) {
+ // Copy the APSInt value into our decomposed form.
+ Integer.BitWidth = Value.getBitWidth();
+ Integer.IsUnsigned = Value.isUnsigned();
+ // If the value is large, we have to get additional memory from the ASTContext
+ if (Integer.BitWidth > 64) {
+ void *Mem = Ctx.Allocate(Integer.BitWidth / 8);
+ std::memcpy(Mem, Value.getRawData(), Integer.BitWidth / 8);
+ Integer.pVal = static_cast<uint64_t *>(Mem);
+ } else {
+ Integer.VAL = Value.getZExtValue();
+ }
+
+ Integer.Type = Type.getAsOpaquePtr();
+}
+
TemplateArgument TemplateArgument::CreatePackCopy(ASTContext &Context,
const TemplateArgument *Args,
unsigned NumArgs) {
}
case Integral:
- getAsIntegral()->Profile(ID);
+ getAsIntegral().Profile(ID);
getIntegralType().Profile(ID);
break;
case Integral:
return getIntegralType() == Other.getIntegralType() &&
- *getAsIntegral() == *Other.getAsIntegral();
+ getAsIntegral() == Other.getAsIntegral();
case Pack:
if (Args.NumArgs != Other.Args.NumArgs) return false;
return DB << "nullptr";
case TemplateArgument::Integral:
- return DB << Arg.getAsIntegral()->toString(10);
+ return DB << Arg.getAsIntegral().toString(10);
case TemplateArgument::Template:
return DB << Arg.getAsTemplate();
llvm::DIType TTy = getOrCreateType(TA.getIntegralType(), Unit);
llvm::DITemplateValueParameter TVP =
DBuilder.createTemplateValueParameter(TheCU, ND->getName(), TTy,
- TA.getAsIntegral()->getZExtValue());
+ TA.getAsIntegral().getZExtValue());
TemplateParams.push_back(TVP);
}
}
llvm::APSInt Value(CharBits, CharIsUnsigned);
for (unsigned I = 0, N = Literal.getUDSuffixOffset(); I != N; ++I) {
Value = ThisTokBegin[I];
- TemplateArgument Arg(Value, Context.CharTy);
+ TemplateArgument Arg(Context, Value, Context.CharTy);
TemplateArgumentLocInfo ArgInfo;
ExplicitArgs.addArgument(TemplateArgumentLoc(Arg, ArgInfo));
}
IntegerType = Enum->getDecl()->getIntegerType();
Value = Value.extOrTrunc(Context.getTypeSize(IntegerType));
- Converted = TemplateArgument(Value, Context.getCanonicalType(ParamType));
+ Converted = TemplateArgument(Context, Value,
+ Context.getCanonicalType(ParamType));
return ArgResult;
}
}
}
- Converted = TemplateArgument(Value,
+ Converted = TemplateArgument(Context, Value,
ParamType->isEnumeralType()
? Context.getCanonicalType(ParamType)
: IntegerType);
Kind = CharacterLiteral::Ascii;
return Owned(new (Context) CharacterLiteral(
- Arg.getAsIntegral()->getZExtValue(),
+ Arg.getAsIntegral().getZExtValue(),
Kind, T, Loc));
}
if (T->isBooleanType())
return Owned(new (Context) CXXBoolLiteralExpr(
- Arg.getAsIntegral()->getBoolValue(),
+ Arg.getAsIntegral().getBoolValue(),
T, Loc));
if (T->isNullPtrType())
else
BT = T;
- Expr *E = IntegerLiteral::Create(Context, *Arg.getAsIntegral(), BT, Loc);
+ Expr *E = IntegerLiteral::Create(Context, Arg.getAsIntegral(), BT, Loc);
if (T->isEnumeralType()) {
// FIXME: This is a hack. We need a better way to handle substituted
// non-type template parameters.
if (Y.getKind() == TemplateArgument::Expression ||
Y.getKind() == TemplateArgument::Declaration ||
(Y.getKind() == TemplateArgument::Integral &&
- hasSameExtendedValue(*X.getAsIntegral(), *Y.getAsIntegral())))
+ hasSameExtendedValue(X.getAsIntegral(), Y.getAsIntegral())))
return DeducedTemplateArgument(X,
X.wasDeducedFromArrayBound() &&
Y.wasDeducedFromArrayBound());
assert(NTTP->getDepth() == 0 &&
"Cannot deduce non-type template argument with depth > 0");
- DeducedTemplateArgument NewDeduced(Value, ValueType, DeducedFromArrayBound);
+ DeducedTemplateArgument NewDeduced(S.Context, Value, ValueType,
+ DeducedFromArrayBound);
DeducedTemplateArgument Result = checkDeducedTemplateArguments(S.Context,
Deduced[NTTP->getIndex()],
NewDeduced);
case TemplateArgument::Integral:
if (Arg.getKind() == TemplateArgument::Integral) {
- if (hasSameExtendedValue(*Param.getAsIntegral(), *Arg.getAsIntegral()))
+ if (hasSameExtendedValue(Param.getAsIntegral(), Arg.getAsIntegral()))
return Sema::TDK_Success;
Info.FirstArg = Param;
= getDeducedParameterFromExpr(Param.getAsExpr())) {
if (Arg.getKind() == TemplateArgument::Integral)
return DeduceNonTypeTemplateArgument(S, NTTP,
- *Arg.getAsIntegral(),
+ Arg.getAsIntegral(),
Arg.getIntegralType(),
/*ArrayBound=*/false,
Info, Deduced);
Y.getAsTemplateOrTemplatePattern()).getAsVoidPointer();
case TemplateArgument::Integral:
- return *X.getAsIntegral() == *Y.getAsIntegral();
+ return X.getAsIntegral() == Y.getAsIntegral();
case TemplateArgument::Expression: {
llvm::FoldingSetNodeID XID, YID;
case TemplateArgument::Integral: {
llvm::APSInt Value = ReadAPSInt(Record, Idx);
QualType T = readType(F, Record, Idx);
- return TemplateArgument(Value, T);
+ return TemplateArgument(Context, Value, T);
}
case TemplateArgument::Template:
return TemplateArgument(ReadTemplateName(F, Record, Idx));
AddDeclRef(Arg.getAsDecl(), Record);
break;
case TemplateArgument::Integral:
- AddAPSInt(*Arg.getAsIntegral(), Record);
+ AddAPSInt(Arg.getAsIntegral(), Record);
AddTypeRef(Arg.getIntegralType(), Record);
break;
case TemplateArgument::Template:
case TemplateArgument::Integral:
Out << 'V';
VisitType(Arg.getIntegralType());
- Out << *Arg.getAsIntegral();
+ Out << Arg.getAsIntegral();
break;
}
}