Commit 0c922d87 authored by Nico Hartmann's avatar Nico Hartmann Committed by V8 LUCI CQ

[torque] Generate asserts for C++ object definitions

This CL adds the requirements to port object definitions back to C++.
A @cppObjectDefinition is introduced to annotate classes for which
Torque shall merely generate asserts to check that offsets match between
Torque and C++.

As a first object, this CL ports Oddball back to C++.

Bug: v8:12710
Change-Id: I1304d8980f6318ffccbc2ef7284cb9d46ff579e8
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3523046Reviewed-by: 's avatarCamillo Bruni <cbruni@chromium.org>
Reviewed-by: 's avatarTobias Tebbi <tebbi@chromium.org>
Reviewed-by: 's avatarDominik Inführ <dinfuehr@chromium.org>
Commit-Queue: Nico Hartmann <nicohartmann@chromium.org>
Cr-Commit-Position: refs/heads/main@{#79856}
parent bb5cc0d5
...@@ -434,6 +434,13 @@ F FUNCTION_CAST(Address addr) { ...@@ -434,6 +434,13 @@ F FUNCTION_CAST(Address addr) {
#define USES_FUNCTION_DESCRIPTORS 0 #define USES_FUNCTION_DESCRIPTORS 0
#endif #endif
constexpr bool StaticStringsEqual(const char* s1, const char* s2) {
for (;; ++s1, ++s2) {
if (*s1 != *s2) return false;
if (*s1 == '\0') return true;
}
}
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// Declarations for use in both the preparser and the rest of V8. // Declarations for use in both the preparser and the rest of V8.
......
...@@ -990,9 +990,23 @@ void JSGlobalObject::JSGlobalObjectVerify(Isolate* isolate) { ...@@ -990,9 +990,23 @@ void JSGlobalObject::JSGlobalObjectVerify(Isolate* isolate) {
} }
void Oddball::OddballVerify(Isolate* isolate) { void Oddball::OddballVerify(Isolate* isolate) {
TorqueGeneratedOddball::OddballVerify(isolate); PrimitiveHeapObjectVerify(isolate);
CHECK(IsOddball(isolate));
Heap* heap = isolate->heap(); Heap* heap = isolate->heap();
Object string = to_string();
VerifyPointer(isolate, string);
CHECK(string.IsString());
Object type = type_of();
VerifyPointer(isolate, type);
CHECK(type.IsString());
Object kind_value = TaggedField<Object>::load(*this, kKindOffset);
VerifyPointer(isolate, kind_value);
CHECK(kind_value.IsSmi());
Object number = to_number(); Object number = to_number();
VerifyPointer(isolate, number);
CHECK(number.IsSmi() || number.IsHeapNumber());
if (number.IsHeapObject()) { if (number.IsHeapObject()) {
CHECK(number == ReadOnlyRoots(heap).nan_value() || CHECK(number == ReadOnlyRoots(heap).nan_value() ||
number == ReadOnlyRoots(heap).hole_nan_value()); number == ReadOnlyRoots(heap).hole_nan_value());
......
...@@ -40,6 +40,7 @@ namespace internal { ...@@ -40,6 +40,7 @@ namespace internal {
V(JSWeakRef) \ V(JSWeakRef) \
V(Map) \ V(Map) \
V(NativeContext) \ V(NativeContext) \
V(Oddball) \
V(PreparseData) \ V(PreparseData) \
V(PromiseOnStack) \ V(PromiseOnStack) \
V(PropertyArray) \ V(PropertyArray) \
......
...@@ -172,6 +172,9 @@ VisitorId Map::GetVisitorId(Map map) { ...@@ -172,6 +172,9 @@ VisitorId Map::GetVisitorId(Map map) {
case FEEDBACK_METADATA_TYPE: case FEEDBACK_METADATA_TYPE:
return kVisitFeedbackMetadata; return kVisitFeedbackMetadata;
case ODDBALL_TYPE:
return kVisitOddball;
case MAP_TYPE: case MAP_TYPE:
return kVisitMap; return kVisitMap;
......
...@@ -56,6 +56,7 @@ enum InstanceType : uint16_t; ...@@ -56,6 +56,7 @@ enum InstanceType : uint16_t;
V(JSWeakCollection) \ V(JSWeakCollection) \
V(Map) \ V(Map) \
V(NativeContext) \ V(NativeContext) \
V(Oddball) \
V(PreparseData) \ V(PreparseData) \
V(PromiseOnStack) \ V(PromiseOnStack) \
V(PropertyArray) \ V(PropertyArray) \
......
...@@ -105,6 +105,13 @@ ...@@ -105,6 +105,13 @@
} \ } \
type holder::name(PtrComprCageBase cage_base, AcquireLoadTag) const type holder::name(PtrComprCageBase cage_base, AcquireLoadTag) const
#define TQ_FIELD_TYPE(name, tq_type) \
static constexpr const char* k##name##TqFieldType = tq_type;
#define DECL_FIELD_OFFSET_TQ(name, value, tq_type) \
static const int k##name##Offset = value; \
TQ_FIELD_TYPE(name, tq_type)
#define DECL_SETTER(name, type) \ #define DECL_SETTER(name, type) \
inline void set_##name(type value, \ inline void set_##name(type value, \
WriteBarrierMode mode = UPDATE_WRITE_BARRIER); WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
...@@ -683,3 +690,6 @@ static_assert(sizeof(unsigned) == sizeof(uint32_t), ...@@ -683,3 +690,6 @@ static_assert(sizeof(unsigned) == sizeof(uint32_t),
#define TQ_OBJECT_CONSTRUCTORS_IMPL(Type) \ #define TQ_OBJECT_CONSTRUCTORS_IMPL(Type) \
inline Type::Type(Address ptr) \ inline Type::Type(Address ptr) \
: TorqueGenerated##Type<Type, Type::Super>(ptr) {} : TorqueGenerated##Type<Type, Type::Super>(ptr) {}
#define TQ_CPP_OBJECT_DEFINITION_ASSERTS(_class, parent) \
template class TorqueGenerated##_class##Asserts<_class, parent>;
...@@ -1283,11 +1283,13 @@ auto BodyDescriptorApply(InstanceType type, Args&&... args) { ...@@ -1283,11 +1283,13 @@ auto BodyDescriptorApply(InstanceType type, Args&&... args) {
case HEAP_NUMBER_TYPE: case HEAP_NUMBER_TYPE:
return CALL_APPLY(HeapNumber); return CALL_APPLY(HeapNumber);
case BYTE_ARRAY_TYPE: case BYTE_ARRAY_TYPE:
return CALL_APPLY(BigInt); return CALL_APPLY(ByteArray);
case BIGINT_TYPE: case BIGINT_TYPE:
return CALL_APPLY(BigInt); return CALL_APPLY(BigInt);
case ALLOCATION_SITE_TYPE: case ALLOCATION_SITE_TYPE:
return CALL_APPLY(AllocationSite); return CALL_APPLY(AllocationSite);
case ODDBALL_TYPE:
return CALL_APPLY(Oddball);
#define MAKE_STRUCT_CASE(TYPE, Name, name) \ #define MAKE_STRUCT_CASE(TYPE, Name, name) \
case TYPE: \ case TYPE: \
......
...@@ -17,18 +17,30 @@ ...@@ -17,18 +17,30 @@
namespace v8 { namespace v8 {
namespace internal { namespace internal {
#include "torque-generated/src/objects/oddball-tq-inl.inc" TQ_CPP_OBJECT_DEFINITION_ASSERTS(Oddball, PrimitiveHeapObject)
TQ_OBJECT_CONSTRUCTORS_IMPL(Oddball) OBJECT_CONSTRUCTORS_IMPL(Oddball, PrimitiveHeapObject)
CAST_ACCESSOR(Oddball)
DEF_PRIMITIVE_ACCESSORS(Oddball, to_number_raw, kToNumberRawOffset, double)
void Oddball::set_to_number_raw_as_bits(uint64_t bits) { void Oddball::set_to_number_raw_as_bits(uint64_t bits) {
// Bug(v8:8875): HeapNumber's double may be unaligned. // Bug(v8:8875): HeapNumber's double may be unaligned.
base::WriteUnalignedValue<uint64_t>(field_address(kToNumberRawOffset), bits); base::WriteUnalignedValue<uint64_t>(field_address(kToNumberRawOffset), bits);
} }
byte Oddball::kind() const { return TorqueGeneratedOddball::kind(); } ACCESSORS(Oddball, to_string, String, kToStringOffset)
ACCESSORS(Oddball, to_number, Object, kToNumberOffset)
ACCESSORS(Oddball, type_of, String, kTypeOfOffset)
void Oddball::set_kind(byte value) { TorqueGeneratedOddball::set_kind(value); } byte Oddball::kind() const {
return Smi::ToInt(TaggedField<Smi>::load(*this, kKindOffset));
}
void Oddball::set_kind(byte value) {
WRITE_FIELD(*this, kKindOffset, Smi::FromInt(value));
}
// static // static
Handle<Object> Oddball::ToNumber(Isolate* isolate, Handle<Oddball> input) { Handle<Object> Oddball::ToNumber(Isolate* isolate, Handle<Oddball> input) {
......
...@@ -16,28 +16,48 @@ namespace internal { ...@@ -16,28 +16,48 @@ namespace internal {
#include "torque-generated/src/objects/oddball-tq.inc" #include "torque-generated/src/objects/oddball-tq.inc"
// The Oddball describes objects null, undefined, true, and false. // The Oddball describes objects null, undefined, true, and false.
class Oddball : public TorqueGeneratedOddball<Oddball, PrimitiveHeapObject> { class Oddball : public PrimitiveHeapObject {
public: public:
// [to_number_raw]: Cached raw to_number computed at startup. // [to_number_raw]: Cached raw to_number computed at startup.
DECL_PRIMITIVE_ACCESSORS(to_number_raw, double)
inline void set_to_number_raw_as_bits(uint64_t bits); inline void set_to_number_raw_as_bits(uint64_t bits);
// [to_string]: Cached to_string computed at startup.
DECL_ACCESSORS(to_string, String)
// [to_number]: Cached to_number computed at startup.
DECL_ACCESSORS(to_number, Object)
// [typeof]: Cached type_of computed at startup.
DECL_ACCESSORS(type_of, String)
inline byte kind() const; inline byte kind() const;
inline void set_kind(byte kind); inline void set_kind(byte kind);
// Oddball has a custom verifier.
void OddballVerify(Isolate* isolate);
// ES6 section 7.1.3 ToNumber for Boolean, Null, Undefined. // ES6 section 7.1.3 ToNumber for Boolean, Null, Undefined.
V8_WARN_UNUSED_RESULT static inline Handle<Object> ToNumber( V8_WARN_UNUSED_RESULT static inline Handle<Object> ToNumber(
Isolate* isolate, Handle<Oddball> input); Isolate* isolate, Handle<Oddball> input);
V8_INLINE bool ToBool(Isolate* isolate) const; V8_INLINE bool ToBool(Isolate* isolate) const;
DECL_CAST(Oddball)
// Dispatched behavior.
DECL_VERIFIER(Oddball)
// Initialize the fields. // Initialize the fields.
static void Initialize(Isolate* isolate, Handle<Oddball> oddball, static void Initialize(Isolate* isolate, Handle<Oddball> oddball,
const char* to_string, Handle<Object> to_number, const char* to_string, Handle<Object> to_number,
const char* type_of, byte kind); const char* type_of, byte kind);
// Layout description.
DECL_FIELD_OFFSET_TQ(ToNumberRaw, HeapObject::kHeaderSize, "float64")
DECL_FIELD_OFFSET_TQ(ToString, kToNumberRawOffset + kDoubleSize, "String")
DECL_FIELD_OFFSET_TQ(ToNumber, kToStringOffset + kTaggedSize, "Number")
DECL_FIELD_OFFSET_TQ(TypeOf, kToNumberOffset + kTaggedSize, "String")
DECL_FIELD_OFFSET_TQ(Kind, kTypeOfOffset + kTaggedSize, "Smi")
static const int kSize = kKindOffset + kTaggedSize;
static const byte kFalse = 0; static const byte kFalse = 0;
static const byte kTrue = 1; static const byte kTrue = 1;
static const byte kNotBooleanMask = static_cast<byte>(~1); static const byte kNotBooleanMask = static_cast<byte>(~1);
...@@ -53,7 +73,8 @@ class Oddball : public TorqueGeneratedOddball<Oddball, PrimitiveHeapObject> { ...@@ -53,7 +73,8 @@ class Oddball : public TorqueGeneratedOddball<Oddball, PrimitiveHeapObject> {
static const byte kSelfReferenceMarker = 10; static const byte kSelfReferenceMarker = 10;
static const byte kBasicBlockCountersMarker = 11; static const byte kBasicBlockCountersMarker = 11;
class BodyDescriptor; using BodyDescriptor =
FixedBodyDescriptor<kToStringOffset, kKindOffset, kSize>;
STATIC_ASSERT(kKindOffset == Internals::kOddballKindOffset); STATIC_ASSERT(kKindOffset == Internals::kOddballKindOffset);
STATIC_ASSERT(kNull == Internals::kNullOddballKind); STATIC_ASSERT(kNull == Internals::kNullOddballKind);
...@@ -61,7 +82,7 @@ class Oddball : public TorqueGeneratedOddball<Oddball, PrimitiveHeapObject> { ...@@ -61,7 +82,7 @@ class Oddball : public TorqueGeneratedOddball<Oddball, PrimitiveHeapObject> {
DECL_PRINTER(Oddball) DECL_PRINTER(Oddball)
TQ_OBJECT_CONSTRUCTORS(Oddball) OBJECT_CONSTRUCTORS(Oddball, PrimitiveHeapObject);
}; };
} // namespace internal } // namespace internal
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
@generateBodyDescriptor @cppObjectDefinition
@apiExposedInstanceTypeValue(0x83) @apiExposedInstanceTypeValue(0x83)
@highestInstanceTypeWithinParentClassRange @highestInstanceTypeWithinParentClassRange
extern class Oddball extends PrimitiveHeapObject { extern class Oddball extends PrimitiveHeapObject {
......
...@@ -111,6 +111,8 @@ static const char* const ANNOTATION_EXPORT = "@export"; ...@@ -111,6 +111,8 @@ static const char* const ANNOTATION_EXPORT = "@export";
static const char* const ANNOTATION_DO_NOT_GENERATE_CAST = "@doNotGenerateCast"; static const char* const ANNOTATION_DO_NOT_GENERATE_CAST = "@doNotGenerateCast";
static const char* const ANNOTATION_USE_PARENT_TYPE_CHECKER = static const char* const ANNOTATION_USE_PARENT_TYPE_CHECKER =
"@useParentTypeChecker"; "@useParentTypeChecker";
static const char* const ANNOTATION_CPP_OBJECT_DEFINITION =
"@cppObjectDefinition";
// Generate C++ accessors with relaxed store semantics. // Generate C++ accessors with relaxed store semantics.
// Weak<T> and MaybeObject fields always use relaxed store. // Weak<T> and MaybeObject fields always use relaxed store.
static const char* const ANNOTATION_CPP_RELAXED_STORE = "@cppRelaxedStore"; static const char* const ANNOTATION_CPP_RELAXED_STORE = "@cppRelaxedStore";
...@@ -162,6 +164,7 @@ enum class ClassFlag { ...@@ -162,6 +164,7 @@ enum class ClassFlag {
kDoNotGenerateCast = 1 << 11, kDoNotGenerateCast = 1 << 11,
kGenerateUniqueMap = 1 << 12, kGenerateUniqueMap = 1 << 12,
kGenerateFactoryFunction = 1 << 13, kGenerateFactoryFunction = 1 << 13,
kCppObjectDefinition = 1 << 14,
}; };
using ClassFlags = base::Flags<ClassFlag>; using ClassFlags = base::Flags<ClassFlag>;
......
...@@ -3995,6 +3995,7 @@ class CppClassGenerator { ...@@ -3995,6 +3995,7 @@ class CppClassGenerator {
} }
void GenerateClass(); void GenerateClass();
void GenerateCppObjectDefinitionAsserts();
private: private:
SourcePosition Position(); SourcePosition Position();
...@@ -4124,8 +4125,6 @@ void CppClassGenerator::GenerateClass() { ...@@ -4124,8 +4125,6 @@ void CppClassGenerator::GenerateClass() {
<< "::cast(*this), " << "::cast(*this), "
"isolate);\n"; "isolate);\n";
impl_ << "}\n\n"; impl_ << "}\n\n";
}
if (type_->ShouldGenerateVerify()) {
impl_ << "\n"; impl_ << "\n";
} }
...@@ -4241,6 +4240,36 @@ void CppClassGenerator::GenerateClass() { ...@@ -4241,6 +4240,36 @@ void CppClassGenerator::GenerateClass() {
} }
} }
void CppClassGenerator::GenerateCppObjectDefinitionAsserts() {
hdr_ << "// Definition " << Position() << "\n"
<< template_decl() << "\n"
<< "class " << gen_name_ << "Asserts {\n";
ClassFieldOffsetGenerator g(hdr_, inl_, type_, gen_name_,
type_->GetSuperClass());
for (auto f : type_->fields()) {
CurrentSourcePosition::Scope scope(f.pos);
g.RecordOffsetFor(f);
}
g.Finish();
hdr_ << "\n";
for (auto f : type_->fields()) {
std::string field = "k" + CamelifyString(f.name_and_type.name) + "Offset";
std::string type = f.name_and_type.type->SimpleName();
hdr_ << " static_assert(" << field << " == D::" << field << ",\n"
<< " \"Values of " << name_ << "::" << field
<< " defined in Torque and C++ do not match\");\n"
<< " static_assert(StaticStringsEqual(\"" << type << "\", D::k"
<< CamelifyString(f.name_and_type.name) << "TqFieldType),\n"
<< " \"Types of " << name_ << "::" << field
<< " specified in Torque and C++ do not match\");\n";
}
hdr_ << " static_assert(kSize == D::kSize);\n";
hdr_ << "};\n\n";
}
void CppClassGenerator::GenerateClassCasts() { void CppClassGenerator::GenerateClassCasts() {
cpp::Class owner({cpp::TemplateParameter("D"), cpp::TemplateParameter("P")}, cpp::Class owner({cpp::TemplateParameter("D"), cpp::TemplateParameter("P")},
gen_name_); gen_name_);
...@@ -4704,7 +4733,9 @@ void ImplementationVisitor::GenerateClassDefinitions( ...@@ -4704,7 +4733,9 @@ void ImplementationVisitor::GenerateClassDefinitions(
std::string name = type->ShouldGenerateCppClassDefinitions() std::string name = type->ShouldGenerateCppClassDefinitions()
? type->name() ? type->name()
: type->GetGeneratedTNodeTypeName(); : type->GetGeneratedTNodeTypeName();
header << "class " << name << ";\n"; if (type->ShouldGenerateCppClassDefinitions()) {
header << "class " << name << ";\n";
}
forward_declarations << "class " << name << ";\n"; forward_declarations << "class " << name << ";\n";
} }
...@@ -4718,6 +4749,9 @@ void ImplementationVisitor::GenerateClassDefinitions( ...@@ -4718,6 +4749,9 @@ void ImplementationVisitor::GenerateClassDefinitions(
if (type->ShouldGenerateCppClassDefinitions()) { if (type->ShouldGenerateCppClassDefinitions()) {
CppClassGenerator g(type, header, inline_header, implementation); CppClassGenerator g(type, header, inline_header, implementation);
g.GenerateClass(); g.GenerateClass();
} else if (type->ShouldGenerateCppObjectDefinitionAsserts()) {
CppClassGenerator g(type, header, inline_header, implementation);
g.GenerateCppObjectDefinitionAsserts();
} }
for (const Field& f : type->fields()) { for (const Field& f : type->fields()) {
const Type* field_type = f.name_and_type.type; const Type* field_type = f.name_and_type.type;
......
...@@ -975,7 +975,8 @@ base::Optional<ParseResult> MakeClassDeclaration( ...@@ -975,7 +975,8 @@ base::Optional<ParseResult> MakeClassDeclaration(
ANNOTATION_EXPORT, ANNOTATION_DO_NOT_GENERATE_CAST, ANNOTATION_EXPORT, ANNOTATION_DO_NOT_GENERATE_CAST,
ANNOTATION_GENERATE_UNIQUE_MAP, ANNOTATION_GENERATE_FACTORY_FUNCTION, ANNOTATION_GENERATE_UNIQUE_MAP, ANNOTATION_GENERATE_FACTORY_FUNCTION,
ANNOTATION_HIGHEST_INSTANCE_TYPE_WITHIN_PARENT, ANNOTATION_HIGHEST_INSTANCE_TYPE_WITHIN_PARENT,
ANNOTATION_LOWEST_INSTANCE_TYPE_WITHIN_PARENT}, ANNOTATION_LOWEST_INSTANCE_TYPE_WITHIN_PARENT,
ANNOTATION_CPP_OBJECT_DEFINITION},
{ANNOTATION_RESERVE_BITS_IN_INSTANCE_TYPE, {ANNOTATION_RESERVE_BITS_IN_INSTANCE_TYPE,
ANNOTATION_INSTANCE_TYPE_VALUE}); ANNOTATION_INSTANCE_TYPE_VALUE});
ClassFlags flags = ClassFlag::kNone; ClassFlags flags = ClassFlag::kNone;
...@@ -1020,6 +1021,9 @@ base::Optional<ParseResult> MakeClassDeclaration( ...@@ -1020,6 +1021,9 @@ base::Optional<ParseResult> MakeClassDeclaration(
if (annotations.Contains(ANNOTATION_LOWEST_INSTANCE_TYPE_WITHIN_PARENT)) { if (annotations.Contains(ANNOTATION_LOWEST_INSTANCE_TYPE_WITHIN_PARENT)) {
flags |= ClassFlag::kLowestInstanceTypeWithinParent; flags |= ClassFlag::kLowestInstanceTypeWithinParent;
} }
if (annotations.Contains(ANNOTATION_CPP_OBJECT_DEFINITION)) {
flags |= ClassFlag::kCppObjectDefinition;
}
auto is_extern = child_results->NextAs<bool>(); auto is_extern = child_results->NextAs<bool>();
if (is_extern) flags |= ClassFlag::kExtern; if (is_extern) flags |= ClassFlag::kExtern;
......
...@@ -668,16 +668,21 @@ class ClassType final : public AggregateType { ...@@ -668,16 +668,21 @@ class ClassType final : public AggregateType {
std::string GetGeneratedTNodeTypeNameImpl() const override; std::string GetGeneratedTNodeTypeNameImpl() const override;
bool IsExtern() const { return flags_ & ClassFlag::kExtern; } bool IsExtern() const { return flags_ & ClassFlag::kExtern; }
bool ShouldGeneratePrint() const { bool ShouldGeneratePrint() const {
return !IsExtern() || (ShouldGenerateCppClassDefinitions() && if (flags_ & ClassFlag::kCppObjectDefinition) return false;
!IsAbstract() && !HasUndefinedLayout()); if (!IsExtern()) return true;
if (!ShouldGenerateCppClassDefinitions()) return false;
return !IsAbstract() && !HasUndefinedLayout();
} }
bool ShouldGenerateVerify() const { bool ShouldGenerateVerify() const {
return !IsExtern() || (ShouldGenerateCppClassDefinitions() && if (flags_ & ClassFlag::kCppObjectDefinition) return false;
!HasUndefinedLayout() && !IsShape()); if (!IsExtern()) return true;
if (!ShouldGenerateCppClassDefinitions()) return false;
return !HasUndefinedLayout() && !IsShape();
} }
bool ShouldGenerateBodyDescriptor() const { bool ShouldGenerateBodyDescriptor() const {
return flags_ & ClassFlag::kGenerateBodyDescriptor || if (flags_ & ClassFlag::kCppObjectDefinition) return false;
(!IsAbstract() && !IsExtern()); if (flags_ & ClassFlag::kGenerateBodyDescriptor) return true;
return !IsAbstract() && !IsExtern();
} }
bool DoNotGenerateCast() const { bool DoNotGenerateCast() const {
return flags_ & ClassFlag::kDoNotGenerateCast; return flags_ & ClassFlag::kDoNotGenerateCast;
...@@ -688,8 +693,12 @@ class ClassType final : public AggregateType { ...@@ -688,8 +693,12 @@ class ClassType final : public AggregateType {
return flags_ & ClassFlag::kHasSameInstanceTypeAsParent; return flags_ & ClassFlag::kHasSameInstanceTypeAsParent;
} }
bool ShouldGenerateCppClassDefinitions() const { bool ShouldGenerateCppClassDefinitions() const {
if (flags_ & ClassFlag::kCppObjectDefinition) return false;
return (flags_ & ClassFlag::kGenerateCppClassDefinitions) || !IsExtern(); return (flags_ & ClassFlag::kGenerateCppClassDefinitions) || !IsExtern();
} }
bool ShouldGenerateCppObjectDefinitionAsserts() const {
return flags_ & ClassFlag::kCppObjectDefinition;
}
bool ShouldGenerateFullClassDefinition() const { return !IsExtern(); } bool ShouldGenerateFullClassDefinition() const { return !IsExtern(); }
bool ShouldGenerateUniqueMap() const { bool ShouldGenerateUniqueMap() const {
return (flags_ & ClassFlag::kGenerateUniqueMap) || return (flags_ & ClassFlag::kGenerateUniqueMap) ||
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment