+struct declaration *ctf_declaration_variant_visit(FILE *fd,
+ int depth, const char *name, const char *choice,
+ struct cds_list_head *declaration_list,
+ int has_body, struct declaration_scope *declaration_scope,
+ struct ctf_trace *trace)
+{
+ struct declaration_untagged_variant *untagged_variant_declaration;
+ struct declaration_variant *variant_declaration;
+ struct ctf_node *iter;
+ int ret;
+
+ /*
+ * For named variant (without body), lookup in
+ * declaration scope. Don't take reference on variant
+ * declaration: ref is only taken upon definition.
+ */
+ if (!has_body) {
+ assert(name);
+ untagged_variant_declaration =
+ lookup_variant_declaration(g_quark_from_string(name),
+ declaration_scope);
+ } else {
+ /* For unnamed variant, create type */
+ /* For named variant (with body), create type and add to declaration scope */
+ if (name) {
+ if (lookup_variant_declaration(g_quark_from_string(name),
+ declaration_scope)) {
+
+ fprintf(fd, "[error] %s: variant %s already declared in scope\n", __func__, name);
+ return NULL;
+ }
+ }
+ untagged_variant_declaration = untagged_variant_declaration_new(declaration_scope);
+ cds_list_for_each_entry(iter, declaration_list, siblings) {
+ ret = ctf_variant_declaration_list_visit(fd, depth + 1, iter,
+ untagged_variant_declaration, trace);
+ if (ret)
+ goto error;
+ }
+ if (name) {
+ ret = register_variant_declaration(g_quark_from_string(name),
+ untagged_variant_declaration,
+ declaration_scope);
+ assert(!ret);
+ }
+ }
+ /*
+ * if tagged, create tagged variant and return. else return
+ * untagged variant.
+ */
+ if (!choice) {
+ return &untagged_variant_declaration->p;
+ } else {
+ variant_declaration = variant_declaration_new(untagged_variant_declaration, choice);
+ if (!variant_declaration)
+ goto error;
+ declaration_unref(&untagged_variant_declaration->p);
+ return &variant_declaration->p;
+ }
+error:
+ untagged_variant_declaration->p.declaration_free(&untagged_variant_declaration->p);
+ return NULL;
+}
+
+static
+int ctf_enumerator_list_visit(FILE *fd, int depth,
+ struct ctf_node *enumerator,
+ struct declaration_enum *enum_declaration)
+{
+ GQuark q;
+ struct ctf_node *iter;
+
+ q = g_quark_from_string(enumerator->u.enumerator.id);
+ if (enum_declaration->integer_declaration->signedness) {
+ int64_t start, end;
+ int nr_vals = 0;
+
+ cds_list_for_each_entry(iter, &enumerator->u.enumerator.values, siblings) {
+ int64_t *target;
+
+ assert(iter->type == NODE_UNARY_EXPRESSION);
+ if (nr_vals == 0)
+ target = &start;
+ else
+ target = &end;
+
+ switch (iter->u.unary_expression.type) {
+ case UNARY_SIGNED_CONSTANT:
+ *target = iter->u.unary_expression.u.signed_constant;
+ break;
+ case UNARY_UNSIGNED_CONSTANT:
+ *target = iter->u.unary_expression.u.unsigned_constant;
+ break;
+ default:
+ fprintf(fd, "[error] %s: invalid enumerator\n", __func__);
+ return -EINVAL;
+ }
+ if (nr_vals > 1) {
+ fprintf(fd, "[error] %s: invalid enumerator\n", __func__);
+ return -EINVAL;
+ }
+ nr_vals++;
+ }
+ if (nr_vals == 1)
+ end = start;
+ enum_signed_insert(enum_declaration, start, end, q);
+ } else {
+ uint64_t start, end;
+ int nr_vals = 0;
+
+ cds_list_for_each_entry(iter, &enumerator->u.enumerator.values, siblings) {
+ uint64_t *target;
+
+ assert(iter->type == NODE_UNARY_EXPRESSION);
+ if (nr_vals == 0)
+ target = &start;
+ else
+ target = &end;
+
+ switch (iter->u.unary_expression.type) {
+ case UNARY_UNSIGNED_CONSTANT:
+ *target = iter->u.unary_expression.u.unsigned_constant;
+ break;
+ case UNARY_SIGNED_CONSTANT:
+ /*
+ * We don't accept signed constants for enums with unsigned
+ * container type.
+ */
+ fprintf(fd, "[error] %s: invalid enumerator (signed constant encountered, but enum container type is unsigned)\n", __func__);
+ return -EINVAL;
+ default:
+ fprintf(fd, "[error] %s: invalid enumerator\n", __func__);
+ return -EINVAL;
+ }
+ if (nr_vals > 1) {
+ fprintf(fd, "[error] %s: invalid enumerator\n", __func__);
+ return -EINVAL;
+ }
+ nr_vals++;
+ }
+ if (nr_vals == 1)
+ end = start;
+ enum_unsigned_insert(enum_declaration, start, end, q);
+ }
+ return 0;
+}
+
+static
+struct declaration *ctf_declaration_enum_visit(FILE *fd, int depth,
+ const char *name,
+ struct ctf_node *container_type,
+ struct cds_list_head *enumerator_list,
+ int has_body,
+ struct declaration_scope *declaration_scope,
+ struct ctf_trace *trace)
+{
+ struct declaration *declaration;
+ struct declaration_enum *enum_declaration;
+ struct declaration_integer *integer_declaration;
+ struct ctf_node *iter;
+ GQuark dummy_id;
+ int ret;
+
+ /*
+ * For named enum (without body), lookup in
+ * declaration scope. Don't take reference on enum
+ * declaration: ref is only taken upon definition.
+ */
+ if (!has_body) {
+ assert(name);
+ enum_declaration =
+ lookup_enum_declaration(g_quark_from_string(name),
+ declaration_scope);
+ return &enum_declaration->p;
+ } else {
+ /* For unnamed enum, create type */
+ /* For named enum (with body), create type and add to declaration scope */
+ if (name) {
+ if (lookup_enum_declaration(g_quark_from_string(name),
+ declaration_scope)) {
+
+ fprintf(fd, "[error] %s: enum %s already declared in scope\n", __func__, name);
+ return NULL;
+ }
+ }
+ if (!container_type) {
+ declaration = lookup_declaration(g_quark_from_static_string("int"),
+ declaration_scope);
+ if (!declaration) {
+ fprintf(fd, "[error] %s: \"int\" type declaration missing for enumeration\n", __func__);
+ return NULL;
+ }
+ } else {
+ declaration = ctf_type_declarator_visit(fd, depth,
+ container_type,
+ &dummy_id, NULL,
+ declaration_scope,
+ NULL, trace);
+ }
+ if (!declaration) {
+ fprintf(fd, "[error] %s: unable to create container type for enumeration\n", __func__);
+ return NULL;
+ }
+ if (declaration->id != CTF_TYPE_INTEGER) {
+ fprintf(fd, "[error] %s: container type for enumeration is not integer\n", __func__);
+ return NULL;
+ }
+ integer_declaration = container_of(declaration, struct declaration_integer, p);
+ enum_declaration = enum_declaration_new(integer_declaration);
+ declaration_unref(&integer_declaration->p); /* leave ref to enum */
+ cds_list_for_each_entry(iter, enumerator_list, siblings) {
+ ret = ctf_enumerator_list_visit(fd, depth + 1, iter, enum_declaration);
+ if (ret)
+ goto error;
+ }
+ if (name) {
+ ret = register_enum_declaration(g_quark_from_string(name),
+ enum_declaration,
+ declaration_scope);
+ assert(!ret);
+ }
+ return &enum_declaration->p;
+ }
+error:
+ enum_declaration->p.declaration_free(&enum_declaration->p);
+ return NULL;
+}
+
+static
+struct declaration *ctf_declaration_type_specifier_visit(FILE *fd, int depth,
+ struct ctf_node *type_specifier_list,