Skip to content
71 changes: 68 additions & 3 deletions clang/include/clang/AST/APValue.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
#include "llvm/ADT/PointerIntPair.h"
#include "llvm/ADT/PointerUnion.h"
#include "llvm/Support/AlignOf.h"
#include "llvm/Support/PointerLikeTypeTraits.h"
#include <cstdint>

namespace clang {
namespace serialization {
Expand All @@ -40,6 +42,10 @@ template <typename T> class BasicReaderBase;
class ValueDecl;
class QualType;

namespace interp {
class Pointer;
} // namespace interp

/// Symbolic representation of typeid(T) for some type T.
class TypeInfoLValue {
const Type *T;
Expand Down Expand Up @@ -88,7 +94,8 @@ class DynamicAllocLValue {

static constexpr int NumLowBitsAvailable = 3;
};
}

} // namespace clang

namespace llvm {
template<> struct PointerLikeTypeTraits<clang::TypeInfoLValue> {
Expand All @@ -113,7 +120,37 @@ template<> struct PointerLikeTypeTraits<clang::DynamicAllocLValue> {
static constexpr int NumLowBitsAvailable =
clang::DynamicAllocLValue::NumLowBitsAvailable;
};
}

// since these are all forward defs, alignof(T) fails and the default falls back
// to treating all of these as `void *`, which has a minimum alignment of only 4
template <> struct PointerLikeTypeTraits<clang::Expr *> {
static inline void *getAsVoidPointer(clang::Expr *P) { return P; }
static inline clang::Expr *getFromVoidPointer(void *P) {
return static_cast<clang::Expr *>(P);
}

// checked elsewhere (Expr.h)
static constexpr int NumLowBitsAvailable = 3;
};
template <> struct PointerLikeTypeTraits<clang::ValueDecl *> {
static inline void *getAsVoidPointer(clang::ValueDecl *P) { return P; }
static inline clang::ValueDecl *getFromVoidPointer(void *P) {
return static_cast<clang::ValueDecl *>(P);
}

// checked elsewhere (ValueDecl.h)
static constexpr int NumLowBitsAvailable = 3;
};
template <> struct PointerLikeTypeTraits<clang::interp::Pointer *> {
static inline void *getAsVoidPointer(clang::interp::Pointer *P) { return P; }
static inline clang::interp::Pointer *getFromVoidPointer(void *P) {
return static_cast<clang::interp::Pointer *>(P);
}

// checked elsewhere (Interp/Pointer.h)
static constexpr int NumLowBitsAvailable = 3;
};
} // namespace llvm

namespace clang {
/// APValue - This class implements a discriminated union of [uninitialized]
Expand Down Expand Up @@ -145,15 +182,34 @@ class APValue {

class LValueBase {
typedef llvm::PointerUnion<const ValueDecl *, const Expr *, TypeInfoLValue,
DynamicAllocLValue>
DynamicAllocLValue, const interp::Pointer *>
PtrTy;

static_assert(
llvm::pointer_union_detail::PointerUnionUIntTraits<
const ValueDecl *, const Expr *, TypeInfoLValue, DynamicAllocLValue,
const interp::Pointer *>::NumLowBitsAvailable >= 3);

static_assert(
llvm::PointerLikeTypeTraits<TypeInfoLValue>::NumLowBitsAvailable >= 3);
static_assert(
llvm::PointerLikeTypeTraits<DynamicAllocLValue>::NumLowBitsAvailable >=
3);
static_assert(
llvm::PointerLikeTypeTraits<const Expr *>::NumLowBitsAvailable >= 3);
static_assert(
llvm::PointerLikeTypeTraits<const ValueDecl *>::NumLowBitsAvailable >=
3);
static_assert(llvm::PointerLikeTypeTraits<
const interp::Pointer *>::NumLowBitsAvailable >= 3);

public:
LValueBase() : Local{} {}
LValueBase(const ValueDecl *P, unsigned I = 0, unsigned V = 0);
LValueBase(const Expr *P, unsigned I = 0, unsigned V = 0);
static LValueBase getDynamicAlloc(DynamicAllocLValue LV, QualType Type);
static LValueBase getTypeInfo(TypeInfoLValue LV, QualType TypeInfo);
static LValueBase getInterpPtr(interp::Pointer *LV);

void Profile(llvm::FoldingSetNodeID &ID) const;

Expand All @@ -177,6 +233,8 @@ class APValue {
QualType getTypeInfoType() const;
QualType getDynamicAllocType() const;

APValue *getInterpRVal(ASTContext &Ctx);

QualType getType() const;

friend bool operator==(const LValueBase &LHS, const LValueBase &RHS);
Expand All @@ -197,7 +255,14 @@ class APValue {
void *TypeInfoType;
/// The QualType, if this is a DynamicAllocLValue.
void *DynamicAllocType;
/// The APValue, if this is an interp::Pointer
APValue *Val;
};

bool hasLocal() const {
return !(is<TypeInfoLValue>() || is<DynamicAllocLValue>() ||
is<const interp::Pointer *>());
}
};

/// A FieldDecl or CXXRecordDecl, along with a flag indicating whether we
Expand Down
5 changes: 5 additions & 0 deletions clang/include/clang/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -737,6 +737,11 @@ class ValueDecl : public NamedDecl {
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classofKind(Kind K) { return K >= firstValue && K <= lastValue; }
};
// PointerLikeTypeTraits is specialized so it can be used with a forward-decl of
// ValueDecl. Verify that we got it right.
static_assert(llvm::PointerLikeTypeTraits<ValueDecl *>::NumLowBitsAvailable <=
llvm::detail::ConstantLog2<alignof(ValueDecl)>::value,
"PointerLikeTypeTraits<ValueDecl *> assumes too much alignment.");

/// A struct with extended info about a syntactic
/// name qualifier, to be used for the case of out-of-line declarations.
Expand Down
2 changes: 2 additions & 0 deletions clang/include/clang/AST/Expr.h
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,8 @@ class Expr : public ValueStmt {
friend class ASTStmtReader; // Sets dependence directly.

public:
static bool toggleInterp();

QualType getType() const { return TR; }
void setType(QualType t) {
// In C++, the type of an expression is always adjusted so that it
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/AST/PropertiesBase.td
Original file line number Diff line number Diff line change
Expand Up @@ -451,6 +451,7 @@ let Class = PropertyTypeCase<APValue, "LValue"> in {
bool lvalueBaseIsExpr = (bool) expr;
bool lvalueBaseIsTypeInfo = lvalueBase.is<TypeInfoLValue>();
bool lvalueBaseIsDynamicAlloc = lvalueBase.is<DynamicAllocLValue>();
// TODO[seth]: what about interp::Pointer* ?
QualType elemTy;
if (lvalueBase) {
if (lvalueBaseIsTypeInfo) {
Expand Down
26 changes: 19 additions & 7 deletions clang/include/clang/AST/TemplateBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,16 +35,28 @@ namespace llvm {

class FoldingSetNodeID;

// TODO[seth]: move this elsewhere so this file can still see it without
// requiring
// an #include<APValue.h> ?
//
// NB: it's kind of unnecessary, since this only uses two bits anyway
// (guaranteed by the void* fallback):
//
// ```c++
// llvm::PointerUnion<TemplateTemplateArgLocInfo *, Expr *, TypeSourceInfo *>
// Pointer;
// ```
//
// Provide PointerLikeTypeTraits for clang::Expr*, this default one requires a
// full definition of Expr, but this file only sees a forward del because of
// the dependency.
template <> struct PointerLikeTypeTraits<clang::Expr *> {
static inline void *getAsVoidPointer(clang::Expr *P) { return P; }
static inline clang::Expr *getFromVoidPointer(void *P) {
return static_cast<clang::Expr *>(P);
}
static constexpr int NumLowBitsAvailable = 2;
};
// template <> struct PointerLikeTypeTraits<clang::Expr *> {
// static inline void *getAsVoidPointer(clang::Expr *P) { return P; }
// static inline clang::Expr *getFromVoidPointer(void *P) {
// return static_cast<clang::Expr *>(P);
// }
// static constexpr int NumLowBitsAvailable = 3;
// };

} // namespace llvm

Expand Down
30 changes: 23 additions & 7 deletions clang/lib/AST/APValue.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
//===----------------------------------------------------------------------===//

#include "clang/AST/APValue.h"
#include "Interp/Pointer.h"
#include "Linkage.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/CharUnits.h"
Expand Down Expand Up @@ -60,6 +61,12 @@ APValue::LValueBase APValue::LValueBase::getTypeInfo(TypeInfoLValue LV,
return Base;
}

APValue::LValueBase APValue::LValueBase::getInterpPtr(interp::Pointer *LV) {
LValueBase Base;
Base.Ptr = LV;
return Base;
}

QualType APValue::LValueBase::getType() const {
if (!*this) return QualType();
if (const ValueDecl *D = dyn_cast<const ValueDecl*>()) {
Expand All @@ -85,7 +92,10 @@ QualType APValue::LValueBase::getType() const {
if (is<DynamicAllocLValue>())
return getDynamicAllocType();

const Expr *Base = get<const Expr*>();
if (const auto *Ptr = dyn_cast<const interp::Pointer *>())
return Ptr->getType();

const Expr *Base = get<const Expr *>();

// For a materialized temporary, the type of the temporary we materialized
// may not be the type of the expression.
Expand All @@ -106,12 +116,11 @@ QualType APValue::LValueBase::getType() const {
}

unsigned APValue::LValueBase::getCallIndex() const {
return (is<TypeInfoLValue>() || is<DynamicAllocLValue>()) ? 0
: Local.CallIndex;
return hasLocal() ? Local.CallIndex : 0;
}

unsigned APValue::LValueBase::getVersion() const {
return (is<TypeInfoLValue>() || is<DynamicAllocLValue>()) ? 0 : Local.Version;
return hasLocal() ? Local.Version : 0;
}

QualType APValue::LValueBase::getTypeInfoType() const {
Expand All @@ -124,9 +133,15 @@ QualType APValue::LValueBase::getDynamicAllocType() const {
return QualType::getFromOpaquePtr(DynamicAllocType);
}

APValue *APValue::LValueBase::getInterpRVal(ASTContext &Ctx) {
assert(is<const interp::Pointer *>() && "not an interp::Pointer");
Val = new APValue(*(get<const interp::Pointer *>()->toRValue(Ctx)));
return Val;
}

void APValue::LValueBase::Profile(llvm::FoldingSetNodeID &ID) const {
ID.AddPointer(Ptr.getOpaqueValue());
if (is<TypeInfoLValue>() || is<DynamicAllocLValue>())
if (!hasLocal())
return;
ID.AddInteger(Local.CallIndex);
ID.AddInteger(Local.Version);
Expand All @@ -137,7 +152,7 @@ bool operator==(const APValue::LValueBase &LHS,
const APValue::LValueBase &RHS) {
if (LHS.Ptr != RHS.Ptr)
return false;
if (LHS.is<TypeInfoLValue>() || LHS.is<DynamicAllocLValue>())
if (!LHS.hasLocal())
return true;
return LHS.Local.CallIndex == RHS.Local.CallIndex &&
LHS.Local.Version == RHS.Local.Version;
Expand Down Expand Up @@ -200,7 +215,7 @@ llvm::DenseMapInfo<clang::APValue::LValueBase>::getTombstoneKey() {

namespace clang {
llvm::hash_code hash_value(const APValue::LValueBase &Base) {
if (Base.is<TypeInfoLValue>() || Base.is<DynamicAllocLValue>())
if (!Base.hasLocal())
return llvm::hash_value(Base.getOpaqueValue());
return llvm::hash_combine(Base.getOpaqueValue(), Base.getCallIndex(),
Base.getVersion());
Expand Down Expand Up @@ -1184,6 +1199,7 @@ LinkageInfo LinkageComputer::getLVForValue(const APValue &V,
if (MergeLV(getLVForDecl(MTE->getExtendingDecl(), computation)))
break;
} else {
// TODO[seth]: what about interp::Pointer?
assert(V.getLValueBase().is<DynamicAllocLValue>() &&
"unexpected LValueBase kind");
return LinkageInfo::internal();
Expand Down
1 change: 1 addition & 0 deletions clang/lib/AST/ASTImporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10263,6 +10263,7 @@ ASTNodeImporter::ImportAPValue(const APValue &FromValue) {
APValue::LValueBase Base;
QualType FromElemTy;
if (FromValue.getLValueBase()) {
// TODO[seth]: what about interp::Pointer?
assert(!FromValue.getLValueBase().is<DynamicAllocLValue>() &&
"in C++20 dynamic allocation are transient so they shouldn't "
"appear in the AST");
Expand Down
Loading