Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion clang/include/clang/AST/APValue.h
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,7 @@ class APValue {
DataType Data;

// A reflection can represent a value, but is also -itself- a value.
//
//
// When 'ReflectionDepth' is nonzero 'N', the APValue represents the otherwise
// described value with N "layers of reflection" over it. The otherwise
// equivalent APValue for which ReflectionDepth is zero is referred to as the
Expand Down Expand Up @@ -576,6 +576,10 @@ class APValue {
return isReflection() &&
getReflectionKind() == ReflectionKind::DataMemberSpec;
}
bool isReflectedEnumeratorSpec() const {
return isReflection() &&
getReflectionKind() == ReflectionKind::EnumeratorSpec;
}
bool isReflectedAnnotation() const {
return isReflection() && getReflectionKind() == ReflectionKind::Annotation;
}
Expand Down Expand Up @@ -770,6 +774,7 @@ class APValue {
ParmVarDecl *getReflectedParameter() const;
CXXBaseSpecifier *getReflectedBaseSpecifier() const;
TagDataMemberSpec *getReflectedDataMemberSpec() const;
EnumeratorSpec *getReflectedEnumeratorSpec() const;
CXX26AnnotationAttr *getReflectedAnnotation() const;

void setInt(APSInt I) {
Expand Down
13 changes: 10 additions & 3 deletions clang/include/clang/AST/MetaActions.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ class CXXRecordDecl;
class Decl;
class DeclContext;
class DeclRefExpr;
class EnumeratorSpec;
class Expr;
class FunctionDecl;
class FunctionTemplateDecl;
Expand Down Expand Up @@ -146,9 +147,15 @@ class MetaActions {
Decl *ContainingDecl,
SourceLocation DefinitionLoc) = 0;

// ============================
// Annotation Synthesis Support
// ============================
// Synthesize an enumerator using description from 'Spec' and augment 'ED' with it.
virtual EnumConstantDecl *
SynthesizeEnumerator(EnumDecl *ED, EnumConstantDecl *prevEnum,
const EnumeratorSpec *Spec, Decl *ContainingDecl,
SourceLocation DefinitionLoc) = 0;

// ============================
// Annotation Synthesis Support
// ============================

virtual AttributeCommonInfo *SynthesizeAnnotation(Expr *CE,
SourceLocation Loc) = 0;
Expand Down
16 changes: 15 additions & 1 deletion clang/include/clang/AST/Reflection.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ enum class ReflectionKind {
///
/// Corresponds to an APValue (plus a QualType).
Object,

/// \brief A reflection of a value (i.e., the result of a prvalue).
///
/// Corresponds to an APValue (plus a QualType).
Expand Down Expand Up @@ -112,6 +112,9 @@ enum class ReflectionKind {

/// \brief A reflection of an annotation (P2996 ext).
Annotation,

/// \brief A reflection of an enumerator for define_enum.
EnumeratorSpec,
};


Expand All @@ -129,6 +132,17 @@ struct TagDataMemberSpec {
bool operator==(TagDataMemberSpec const& Rhs) const;
bool operator!=(TagDataMemberSpec const& Rhs) const;
};


// Hold definition of an enumerator for define_enum
struct EnumeratorSpec {
std::string name;
bool hasValue;
int64_t val;
std::vector<APValue> annotations;
std::vector<APValue> attributes;
};

} // namespace clang

#endif
2 changes: 2 additions & 0 deletions clang/include/clang/Basic/DiagnosticMetafnKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,8 @@ def metafn_injected_decl_non_plainly_consteval : Note<
"cannot produce an injected declaration from a non-plainly "
"constant-evaluated context">;

// define_enum
def metafn_enum_already_complete: Note<"%0 already has enumerators defined">;
// Annotation injection.
def metafn_cannot_annotate : Note<"cannot attach an annotation to %1">;

Expand Down
12 changes: 12 additions & 0 deletions clang/lib/AST/APValue.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/LocInfoType.h"
#include "clang/AST/Reflection.h"
#include "clang/AST/Type.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
Expand Down Expand Up @@ -964,6 +965,13 @@ TagDataMemberSpec *APValue::getReflectedDataMemberSpec() const {
const_cast<void *>(getOpaqueReflectionData()));
}

EnumeratorSpec *APValue::getReflectedEnumeratorSpec() const {
assert(getReflectionKind() == ReflectionKind::EnumeratorSpec &&
"not a reflection of a description of an enum for define");
return reinterpret_cast<EnumeratorSpec *>(
const_cast<void *>(getOpaqueReflectionData()));
}

CXX26AnnotationAttr *APValue::getReflectedAnnotation() const {
assert(getReflectionKind() == ReflectionKind::Annotation &&
"not a reflection of an annotation");
Expand Down Expand Up @@ -1327,6 +1335,9 @@ void APValue::printPretty(raw_ostream &Out, const PrintingPolicy &Policy,
case ReflectionKind::DataMemberSpec:
Repr = "data-member-spec";
break;
case ReflectionKind::EnumeratorSpec:
Repr = "enum-for-define-spec";
break;
case ReflectionKind::Annotation:
Repr = "annotation";
break;
Expand Down Expand Up @@ -1667,6 +1678,7 @@ void APValue::setReflection(ReflectionKind RK, const void *Ptr) {
case ReflectionKind::Parameter:
case ReflectionKind::BaseSpecifier:
case ReflectionKind::DataMemberSpec:
case ReflectionKind::EnumeratorSpec:
case ReflectionKind::Annotation:
SelfData.Kind = RK;
SelfData.Data = Ptr;
Expand Down
170 changes: 170 additions & 0 deletions clang/lib/AST/ExprConstantMeta.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/raw_ostream.h"
#include <optional>


namespace clang {
Expand Down Expand Up @@ -587,12 +588,25 @@ static bool data_member_spec(APValue &Result, ASTContext &C, MetaActions &Meta,
SourceRange Range, ArrayRef<Expr *> Args,
Decl *ContainingDecl);

// TODO
static bool enum_member_spec(APValue &Result, ASTContext &C, MetaActions &Meta,
EvalFn Evaluator, DiagFn Diagnoser,
bool AllowInjection, QualType ResultTy,
SourceRange Range, ArrayRef<Expr *> Args,
Decl *ContainingDecl);

static bool define_aggregate(APValue &Result, ASTContext &C, MetaActions &Meta,
EvalFn Evaluator, DiagFn Diagnoser,
bool AllowInjection, QualType ResultTy,
SourceRange Range, ArrayRef<Expr *> Args,
Decl *ContainingDecl);

static bool define_enum(APValue &Result, ASTContext &C, MetaActions &Meta,
EvalFn Evaluator, DiagFn Diagnoser,
bool AllowInjection, QualType ResultTy,
SourceRange Range, ArrayRef<Expr *> Args,
Decl *ContainingDecl);

static bool offset_of(APValue &Result, ASTContext &C, MetaActions &Meta,
EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection,
QualType ResultTy, SourceRange Range,
Expand Down Expand Up @@ -823,7 +837,9 @@ static constexpr Metafunction Metafunctions[] = {
{ Metafunction::MFRK_bool, 1, 1, is_user_declared },
{ Metafunction::MFRK_metaInfo, 2, 2, reflect_result },
{ Metafunction::MFRK_metaInfo, 10, 10, data_member_spec },
{ Metafunction::MFRK_metaInfo, 8, 8, enum_member_spec },
{ Metafunction::MFRK_metaInfo, 3, 3, define_aggregate },
{ Metafunction::MFRK_metaInfo, 3, 3, define_enum },
{ Metafunction::MFRK_spliceFromArg, 2, 2, offset_of },
{ Metafunction::MFRK_sizeT, 1, 1, size_of },
{ Metafunction::MFRK_spliceFromArg, 2, 2, bit_offset_of },
Expand Down Expand Up @@ -920,6 +936,10 @@ static APValue makeReflection(TagDataMemberSpec *TDMS) {
return APValue(ReflectionKind::DataMemberSpec, TDMS);
}

static APValue makeReflection(EnumeratorSpec *EMS) {
return APValue(ReflectionKind::EnumeratorSpec, EMS);
}

static APValue makeReflection(CXX26AnnotationAttr *A) {
return APValue(ReflectionKind::Annotation, A);
}
Expand Down Expand Up @@ -5161,6 +5181,156 @@ bool data_member_spec(APValue &Result, ASTContext &C, MetaActions &Meta,
return SetAndSucceed(Result, makeReflection(TDMS));
}

bool enum_member_spec(APValue &Result, ASTContext &C, MetaActions &Meta,
EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection,
QualType ResultTy, SourceRange Range,
ArrayRef<Expr *> Args, Decl *ContainingDecl) {

// TODO diagnostic
// TODO annotations
// TODO attributes
// TODO utf8

// ARGS:
//
// ^^const char, s.size(), s.data(),
// val,
// annotations.size(), annotations.begin(),
// attributes.size(), attributes.begin());
APValue Scratch;
int ArgIdx = 0;

// Evaluate the character type.
if (!Evaluator(Scratch, Args[ArgIdx++], true))
return true;
QualType CharTy = Scratch.getReflectedType();

std::string Name;
if (!Evaluator(Scratch, Args[ArgIdx++], true))
return true;
size_t nameLen = Scratch.getInt().getExtValue();
Name.resize(nameLen);
Name[nameLen]='\0';
// Why cant i make EvaluateCharRangeAsString work ?...
for (uint64_t k = 0; k < nameLen; ++k) {
llvm::APInt Idx(C.getTypeSize(C.getSizeType()), k, false);
Expr *Synthesized = IntegerLiteral::Create(C, Idx, C.getSizeType(),
Args[ArgIdx]->getExprLoc());

Synthesized = new (C) ArraySubscriptExpr(Args[ArgIdx], Synthesized,
CharTy, VK_LValue, OK_Ordinary,
Range.getBegin());
if (Synthesized->isValueDependent() || Synthesized->isTypeDependent())
return true;

if (!Evaluator(Scratch, Synthesized, true))
return true;

Name[k] = static_cast<char>(Scratch.getInt().getExtValue());
}
ArgIdx++;
// Value of the enumerator
APValue Val;
if (!Evaluator(Val, Args[ArgIdx++], true))
return true;

EnumeratorSpec * ES = new (C) EnumeratorSpec{
Name,
!Val.isNullReflection(),
Val.isNullReflection() ? 0: Val.getInt().getExtValue(),
{},
{}
};
return SetAndSucceed(Result, makeReflection(ES));
}

bool define_enum(APValue &Result, ASTContext &C, MetaActions &Meta,
EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection,
QualType ResultTy, SourceRange Range, ArrayRef<Expr *> Args,
Decl *ContainingDecl) {
if (!AllowInjection) {
return Diagnoser(Range.getBegin(),
diag::metafn_injected_decl_non_plainly_consteval);
}
assert(Args[0]->getType()->isReflectionType());
APValue Scratch;
if (!Evaluator(Scratch, Args[0], true)) {
return true;
}

// Checking we have the reflection of an enum type as first arg.
if (!Scratch.isReflectedType()) {
return DiagnoseReflectionKind(Diagnoser, Range, "an enum type",
DescriptionOf(Scratch));
}
QualType TargetEnum = Scratch.getReflectedType();
EnumDecl *foundDecl = llvm::dyn_cast<EnumDecl>(findTypeDecl(TargetEnum));
if (!foundDecl) {
return DiagnoseReflectionKind(Diagnoser, Range, "an enum type",
DescriptionOf(Scratch));
}

// Need to check we havent seen enumerators for this enum yet...
if (!foundDecl->enumerators().empty()) {
// Diagnostic on found enumerators
return Diagnoser(Range.getBegin(), diag::metafn_enum_already_complete)
<< TargetEnum.getAsString();
}

// Get nb of enumerators spec.
if (!Evaluator(Scratch, Args[1], true))
return true;
size_t NumEnumerators = static_cast<size_t>(Scratch.getInt().getExtValue());
SmallVector<EnumeratorSpec *, 4> EnumSpecs;
llvm::FoldingSetNodeID ID;
llvm::StringSet<> MemberNames;
for (size_t k = 0; k < NumEnumerators; ++k) {
// Extract the reflection from the list of member specs.
llvm::APInt Idx(C.getTypeSize(C.getSizeType()), k, false);
Expr *Synthesized =
IntegerLiteral::Create(C, Idx, C.getSizeType(), Args[2]->getExprLoc());

Synthesized =
new (C) ArraySubscriptExpr(Args[2], Synthesized, C.MetaInfoTy,
VK_LValue, OK_Ordinary, Range.getBegin());
if (Synthesized->isValueDependent() || Synthesized->isTypeDependent())
return true;

if (!Evaluator(Scratch, Synthesized, true))
return true;
if (!Scratch.isReflectedEnumeratorSpec())
return DiagnoseReflectionKind(
Diagnoser, Range, "a description of an enumerator for 'define_enum'",
DescriptionOf(Scratch));
EnumSpecs.push_back(Scratch.getReflectedEnumeratorSpec());
}

EnumConstantDecl *runningEnum = nullptr;
for (const auto &enumSpec : EnumSpecs) {
runningEnum =
Meta.SynthesizeEnumerator(foundDecl, runningEnum, enumSpec,
ContainingDecl, Args[0]->getExprLoc());
foundDecl->addDecl(runningEnum);
}
// TODO complete the enumDecl definition...
unsigned NumNegativeBits = 0, NumPositiveBits = 0;
(void)C.computeEnumBits(foundDecl->enumerators(), NumNegativeBits, NumPositiveBits);
QualType BestType, BestPromotionType;
QualType NewType =
foundDecl->isFixed() ? foundDecl->getIntegerType() : BestType;
// For scoped enums, “promotion” isn’t used for implicit integral promotions;
// keeping it equal to the underlying type is a safe default.

for (auto *ECD : foundDecl->enumerators()) {
// C++ [dcl.enum]p4: Following the closing brace of an enum-specifier,
// each enumerator has the type of its enumeration.
ECD->setType(TargetEnum);
}
foundDecl->completeDefinition(NewType, NewType, NumNegativeBits,
NumPositiveBits);
return SetAndSucceed(Result, makeReflection(foundDecl));
}

bool define_aggregate(APValue &Result, ASTContext &C, MetaActions &Meta,
EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection,
QualType ResultTy, SourceRange Range,
Expand Down
19 changes: 19 additions & 0 deletions clang/lib/Sema/SemaReflect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -487,6 +487,25 @@ class MetaActionsImpl : public MetaActions {
return Result.get();
}

EnumConstantDecl *
SynthesizeEnumerator(EnumDecl *ED, EnumConstantDecl *prevEnum,
const EnumeratorSpec *enumSpec, Decl *ContainingDecl,
SourceLocation DefinitionLoc) override {
IdentifierInfo *II = &(S.Context.Idents.get(enumSpec->name));
Expr *Val = enumSpec->hasValue
? IntegerLiteral::Create(
S.Context, llvm::APSInt::get(enumSpec->val),
S.Context.getSizeType(), DefinitionLoc)
: nullptr;
return S.CheckEnumConstant(ED, prevEnum, DefinitionLoc, II, Val);

// We need this really...
//
// return llvm::dyn_cast<EnumConstantDecl>(
// S.ActOnEnumConstant(S.getCurScope(), ED, prevEnum, DefinitionLoc, II,
// {}, DefinitionLoc, Val));
}

CXXRecordDecl *DefineAggregate(CXXRecordDecl *IncompleteDecl,
ArrayRef<TagDataMemberSpec *> MemberSpecs,
Decl *ContainingDecl,
Expand Down
Loading