[fidlc] Using canonicalized types for enum declarations
Test: make -j 72 HOST_USE_ASAN=true tools && ./build-x64/host_tests/fidl-compiler-test
Change-Id: I8b12617a2fade8e8d2bcac0413ffa0b3bcd8a284
diff --git a/system/host/fidl/include/fidl/flat_ast.h b/system/host/fidl/include/fidl/flat_ast.h
index 2ea65a6..fff5c77 100644
--- a/system/host/fidl/include/fidl/flat_ast.h
+++ b/system/host/fidl/include/fidl/flat_ast.h
@@ -666,14 +666,19 @@
std::unique_ptr<raw::AttributeList> attributes;
};
- Enum(std::unique_ptr<raw::AttributeList> attributes, Name name, types::PrimitiveSubtype subtype,
+ Enum(std::unique_ptr<raw::AttributeList> attributes, Name name,
+ std::unique_ptr<raw::IdentifierType> maybe_subtype,
std::vector<Member> members)
: Decl(Kind::kEnum, std::move(attributes), std::move(name)),
- type(std::make_unique<PrimitiveType>(subtype)),
+ maybe_subtype(std::move(maybe_subtype)),
members(std::move(members)) {}
- std::unique_ptr<PrimitiveType> type;
+ // Set during construction.
+ std::unique_ptr<raw::IdentifierType> maybe_subtype;
std::vector<Member> members;
+
+ // Set during compilation.
+ const PrimitiveType* type = nullptr;
TypeShape typeshape;
};
diff --git a/system/host/fidl/lib/flat_ast.cpp b/system/host/fidl/lib/flat_ast.cpp
index 39613e0..a6dcccb 100644
--- a/system/host/fidl/lib/flat_ast.cpp
+++ b/system/host/fidl/lib/flat_ast.cpp
@@ -951,41 +951,19 @@
return false;
auto attributes = std::move(member->attributes);
members.emplace_back(location, std::move(value), std::move(attributes));
- }
- auto type = types::PrimitiveSubtype::kUint32;
- if (enum_declaration->maybe_subtype) {
- auto location = enum_declaration->maybe_subtype->location();
- Name subtype_name;
- if (!CompileCompoundIdentifier(enum_declaration->maybe_subtype->identifier.get(),
- location, &subtype_name)) {
- return false;
- }
- auto primitive_type = LookupPrimitiveType(subtype_name);
- if (primitive_type == nullptr) {
- std::string message("enums may only be of primitive types, found ");
- message += NameName(subtype_name, ".", "/");
- return Fail(location, message);
- }
- type = primitive_type->subtype;
+ // TODO(pascallouis): right now, members are not registered. Look into
+ // registering them, potentially under the enum name qualifier such as
+ // <name_of_enum>.<name_of_member>.
}
- auto attributes = std::move(enum_declaration->attributes);
- auto name = Name(this, enum_declaration->identifier->location());
-
- enum_declarations_.push_back(
- std::make_unique<Enum>(std::move(attributes), std::move(name), type, std::move(members)));
+ enum_declarations_.push_back(std::make_unique<Enum>(
+ std::move(enum_declaration->attributes),
+ Name(this, enum_declaration->identifier->location()),
+ std::move(enum_declaration->maybe_subtype),
+ std::move(members)));
if (!RegisterDecl(enum_declarations_.back().get()))
return false;
- // TODO(pascallouis): right now, members are not registered. Look into
- // registering them, potentially under the enum name qualifier such as
- // <name_of_enum>.<name_of_member>.
- //
- // When doing this, change type ownership to be at library level, rather
- // than node level, and change references from std::unique_ptr<Type> to
- // const Type* throughout raw and flat nodes. Otherwhise, it's that much
- // harder to create inferred types, and share types, e.g. here between the
- // enum decl and the multiple const decl for each member.
return true;
}
@@ -1228,6 +1206,7 @@
bool Library::ResolveConstant(Constant* constant, const Type* type) {
assert(constant != nullptr);
+
if (constant->IsResolved())
return true;
@@ -1509,7 +1488,7 @@
// forbidding that out-of-range values be assignable to this enum in
// const declarations.
auto enum_decl = static_cast<const flat::Enum*>(decl);
- return enum_decl->type.get();
+ return enum_decl->type;
}
default:
return type;
@@ -1841,7 +1820,28 @@
bool Library::CompileEnum(Enum* enum_declaration) {
Compiling guard(enum_declaration);
- switch (enum_declaration->type->subtype) {
+
+ Name subtype_name(nullptr, "uint32");
+ if (enum_declaration->maybe_subtype) {
+ auto location = enum_declaration->maybe_subtype->location();
+ if (!CompileCompoundIdentifier(enum_declaration->maybe_subtype->identifier.get(),
+ location, &subtype_name)) {
+ return false;
+ }
+ }
+
+ auto primitive_type = LookupPrimitiveType(subtype_name);
+ if (primitive_type == nullptr) {
+ std::string message("enums may only be of integral primitive type, found ");
+ message += NameName(subtype_name, ".", "/");
+ return Fail(*enum_declaration, message);
+ }
+
+ enum_declaration->type = primitive_type;
+ enum_declaration->typeshape = PrimitiveTypeShape(primitive_type->subtype);
+
+ // Validate constants.
+ switch (primitive_type->subtype) {
case types::PrimitiveSubtype::kInt8:
if (!ValidateEnumMembers<int8_t>(enum_declaration))
return false;
@@ -1877,12 +1877,11 @@
case types::PrimitiveSubtype::kBool:
case types::PrimitiveSubtype::kFloat32:
case types::PrimitiveSubtype::kFloat64:
- // These are not allowed as enum subtypes.
- return Fail(*enum_declaration, "Enums cannot be bools, statuses, or floats");
+ std::string message("enums may only be of integral primitive type, found ");
+ message += NameName(subtype_name, ".", "/");
+ return Fail(*enum_declaration, message);
}
- enum_declaration->typeshape = PrimitiveTypeShape(enum_declaration->type->subtype);
-
auto placement_ok = error_reporter_->Checkpoint();
// Attributes: check placement.
ValidateAttributesPlacement(
@@ -2494,7 +2493,7 @@
for (auto& member : enum_decl->members) {
assert(member.value != nullptr && "Compiler bug: enum member value is null!");
- if (!ResolveConstant(member.value.get(), enum_decl->type.get()))
+ if (!ResolveConstant(member.value.get(), enum_decl->type))
return Fail(member.name, "unable to resolve struct member");
// Check that the enum member identifier hasn't been used yet