+ entity_t *entity;
+ if (specifiers->storage_class == STORAGE_CLASS_TYPEDEF) {
+ entity = allocate_entity_zero(ENTITY_TYPEDEF);
+ entity->base.symbol = env.symbol;
+ entity->base.source_position = env.source_position;
+ entity->typedefe.type = orig_type;
+
+ if (anonymous_entity != NULL) {
+ if (is_type_compound(type)) {
+ assert(anonymous_entity->compound.alias == NULL);
+ assert(anonymous_entity->kind == ENTITY_STRUCT ||
+ anonymous_entity->kind == ENTITY_UNION);
+ anonymous_entity->compound.alias = entity;
+ anonymous_entity = NULL;
+ } else if (is_type_enum(type)) {
+ assert(anonymous_entity->enume.alias == NULL);
+ assert(anonymous_entity->kind == ENTITY_ENUM);
+ anonymous_entity->enume.alias = entity;
+ anonymous_entity = NULL;
+ }
+ }
+ } else {
+ /* create a declaration type entity */
+ if (flags & DECL_CREATE_COMPOUND_MEMBER) {
+ entity = allocate_entity_zero(ENTITY_COMPOUND_MEMBER);
+
+ if (env.symbol != NULL) {
+ if (specifiers->is_inline && is_type_valid(type)) {
+ errorf(&env.source_position,
+ "compound member '%Y' declared 'inline'", env.symbol);
+ }
+
+ if (specifiers->thread_local ||
+ specifiers->storage_class != STORAGE_CLASS_NONE) {
+ errorf(&env.source_position,
+ "compound member '%Y' must have no storage class",
+ env.symbol);
+ }
+ }
+ } else if (flags & DECL_IS_PARAMETER) {
+ orig_type = semantic_parameter(&env.source_position, orig_type,
+ specifiers, env.symbol);
+
+ entity = allocate_entity_zero(ENTITY_PARAMETER);
+ } else if (is_type_function(type)) {
+ entity = allocate_entity_zero(ENTITY_FUNCTION);
+
+ entity->function.is_inline = specifiers->is_inline;
+ entity->function.parameters = env.parameters;
+
+ if (env.symbol != NULL) {
+ if (specifiers->thread_local || (
+ specifiers->storage_class != STORAGE_CLASS_EXTERN &&
+ specifiers->storage_class != STORAGE_CLASS_NONE &&
+ specifiers->storage_class != STORAGE_CLASS_STATIC
+ )) {
+ errorf(&env.source_position,
+ "invalid storage class for function '%Y'", env.symbol);
+ }
+ }
+ } else {
+ entity = allocate_entity_zero(ENTITY_VARIABLE);
+
+ entity->variable.get_property_sym = specifiers->get_property_sym;
+ entity->variable.put_property_sym = specifiers->put_property_sym;
+
+ entity->variable.thread_local = specifiers->thread_local;
+
+ if (env.symbol != NULL) {
+ if (specifiers->is_inline && is_type_valid(type)) {
+ errorf(&env.source_position,
+ "variable '%Y' declared 'inline'", env.symbol);
+ }
+
+ bool invalid_storage_class = false;
+ if (current_scope == file_scope) {
+ if (specifiers->storage_class != STORAGE_CLASS_EXTERN &&
+ specifiers->storage_class != STORAGE_CLASS_NONE &&
+ specifiers->storage_class != STORAGE_CLASS_STATIC) {
+ invalid_storage_class = true;
+ }
+ } else {
+ if (specifiers->thread_local &&
+ specifiers->storage_class == STORAGE_CLASS_NONE) {
+ invalid_storage_class = true;
+ }
+ }
+ if (invalid_storage_class) {
+ errorf(&env.source_position,
+ "invalid storage class for variable '%Y'", env.symbol);
+ }
+ }
+ }
+
+ if (env.symbol != NULL) {
+ entity->base.symbol = env.symbol;
+ entity->base.source_position = env.source_position;
+ } else {
+ entity->base.source_position = specifiers->source_position;
+ }
+ entity->base.namespc = NAMESPACE_NORMAL;
+ entity->declaration.type = orig_type;
+ entity->declaration.modifiers = env.modifiers;
+ entity->declaration.deprecated_string = specifiers->deprecated_string;
+
+ storage_class_t storage_class = specifiers->storage_class;
+ entity->declaration.declared_storage_class = storage_class;
+
+ if (storage_class == STORAGE_CLASS_NONE && current_scope != file_scope)
+ storage_class = STORAGE_CLASS_AUTO;
+ entity->declaration.storage_class = storage_class;
+ }
+
+ parse_declaration_attributes(entity);
+
+ return entity;