- create an empty_statement_t and use that instead of a NULL pointer in places
like if, loop bodys, statements after labels
- eliminate target_architecture.h and replace with stuff in lang_features.h
+- redo storage classes: so we can separate real from declared storage class
Lexer:
- Add preprocessor code
compressed table) and only storing pointers to it on the AST.
Parser:
+- disallow storage class specifiers in sturct/union members
- the expect macros abort functions directly. This leads to some functions
not resetting the current context properly (parse_for); expect in expressions
suddenly return NULL which triggers asserts
{
unsigned prec = get_expression_precedence(expression->base.kind);
print_expression_prec(expression->compound, prec);
- if(expression->compound->base.type == NULL ||
- expression->compound->base.type->kind == TYPE_POINTER) {
+ if(is_type_pointer(expression->compound->base.type)) {
fputs("->", out);
} else {
fputc('.', out);
*
* @param storage_class the storage class
*/
-static void print_storage_class(unsigned storage_class)
+static void print_storage_class(storage_class_tag_t storage_class)
{
- switch((storage_class_tag_t) storage_class) {
+ switch(storage_class) {
case STORAGE_CLASS_ENUM_ENTRY:
case STORAGE_CLASS_NONE:
break;
*/
static void print_normal_declaration(const declaration_t *declaration)
{
- print_storage_class(declaration->storage_class);
+ print_storage_class((storage_class_tag_t) declaration->declared_storage_class);
if(declaration->is_inline) {
if (declaration->modifiers & DM_FORCEINLINE)
fputs("__forceinline ", out);
}
}
-static bool is_initializer_const(const initializer_t *initializer)
+bool is_constant_initializer(const initializer_t *initializer)
{
switch(initializer->kind) {
case INITIALIZER_STRING:
case INITIALIZER_LIST: {
for(size_t i = 0; i < initializer->list.len; ++i) {
initializer_t *sub_initializer = initializer->list.initializers[i];
- if(!is_initializer_const(sub_initializer))
+ if(!is_constant_initializer(sub_initializer))
return false;
}
return true;
panic("invalid initializer kind found");
}
-/**
- * Returns true if a given expression is a compile time
- * constant.
- *
- * @param expression the expression to check
- */
+static bool is_object_with_constant_address(const expression_t *expression)
+{
+ switch(expression->kind) {
+ case EXPR_UNARY_DEREFERENCE:
+ return is_address_constant(expression->unary.value);
+
+ case EXPR_SELECT: {
+ if(is_type_pointer(expression->select.compound->base.type)) {
+ /* it's a -> */
+ return is_address_constant(expression->select.compound);
+ } else {
+ return is_object_with_constant_address(expression->select.compound);
+ }
+ }
+
+ case EXPR_ARRAY_ACCESS:
+ return is_constant_expression(expression->array_access.index)
+ && is_address_constant(expression->array_access.array_ref);
+
+ case EXPR_REFERENCE: {
+ declaration_t *declaration = expression->reference.declaration;
+ switch((storage_class_tag_t) declaration->storage_class) {
+ case STORAGE_CLASS_NONE:
+ case STORAGE_CLASS_EXTERN:
+ case STORAGE_CLASS_STATIC:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ default:
+ return false;
+ }
+}
+
+bool is_address_constant(const expression_t *expression)
+{
+ switch(expression->kind) {
+ case EXPR_UNARY_TAKE_ADDRESS:
+ return is_object_with_constant_address(expression->unary.value);
+
+ case EXPR_UNARY_CAST:
+ return is_type_pointer(expression->base.type)
+ && (is_constant_expression(expression->unary.value)
+ || is_address_constant(expression->unary.value));
+
+ case EXPR_BINARY_ADD:
+ case EXPR_BINARY_SUB: {
+ expression_t *left = expression->binary.left;
+ expression_t *right = expression->binary.right;
+
+ if(is_type_pointer(left->base.type)) {
+ return is_address_constant(left) && is_constant_expression(right);
+ } else if(is_type_pointer(right->base.type)) {
+ return is_constant_expression(left) && is_address_constant(right);
+ }
+
+ return false;
+ }
+
+ case EXPR_REFERENCE: {
+ declaration_t *declaration = expression->reference.declaration;
+ type_t *type = skip_typeref(declaration->type);
+ if(is_type_function(type))
+ return true;
+ if(is_type_array(type)) {
+ return is_object_with_constant_address(expression);
+ }
+ return false;
+ }
+
+ default:
+ return false;
+ }
+}
+
bool is_constant_expression(const expression_t *expression)
{
switch(expression->kind) {
case EXPR_UNARY_PREFIX_DECREMENT:
case EXPR_UNARY_BITFIELD_EXTRACT:
case EXPR_UNARY_ASSUME: /* has VOID type */
+ case EXPR_UNARY_DEREFERENCE:
+ case EXPR_UNARY_TAKE_ADDRESS:
case EXPR_BINARY_ASSIGN:
case EXPR_BINARY_MUL_ASSIGN:
case EXPR_BINARY_DIV_ASSIGN:
case EXPR_UNARY_PLUS:
case EXPR_UNARY_BITWISE_NEGATE:
case EXPR_UNARY_NOT:
- case EXPR_UNARY_DEREFERENCE:
- case EXPR_UNARY_TAKE_ADDRESS:
+ return is_constant_expression(expression->unary.value);
+
case EXPR_UNARY_CAST:
case EXPR_UNARY_CAST_IMPLICIT:
- return is_constant_expression(expression->unary.value);
+ return is_type_arithmetic(expression->base.type)
+ && is_constant_expression(expression->unary.value);
case EXPR_BINARY_ADD:
case EXPR_BINARY_SUB:
&& is_constant_expression(expression->binary.right);
case EXPR_COMPOUND_LITERAL:
- return is_initializer_const(expression->compound_literal.initializer);
+ return is_constant_initializer(expression->compound_literal.initializer);
case EXPR_CONDITIONAL:
/* TODO: not correct, we only have to test expressions which are
void change_indent(int delta);
void *allocate_ast(size_t size);
+/**
+ * Returns true if a given expression is a compile time
+ * constant.
+ *
+ * @param expression the expression to check
+ */
+bool is_constant_initializer(const initializer_t *initializer);
+
+/**
+ * Returns true if a given expression is a compile time
+ * constant.
+ *
+ * @param expression the expression to check
+ */
bool is_constant_expression(const expression_t *expression);
+bool is_address_constant(const expression_t *expression);
+
long fold_constant(const expression_t *expression);
#endif
#include <config.h>
-#define _GNU_SOURCE
-
#include <assert.h>
#include <string.h>
#include <stdbool.h>
create_local_initializer(initializer, dbgi, entity, type);
/* create a sel for the compound literal address */
- ir_node *frame = get_local_frame(entity);
- ir_node *sel = new_d_simpleSel(dbgi, new_NoMem(), frame, entity);
+ ir_node *frame = get_local_frame(entity);
+ ir_node *sel = new_d_simpleSel(dbgi, new_NoMem(), frame, entity);
return sel;
}
panic("unknown initializer");
}
+static void create_dynamic_initializer_sub(ir_initializer_t *initializer,
+ ir_type *type, dbg_info *dbgi, ir_node *base_addr)
+{
+ switch(get_initializer_kind(initializer)) {
+ case IR_INITIALIZER_NULL: {
+ ir_mode *mode = get_type_mode(type);
+ /* TODO: implement this for compound types... */
+ assert(type != NULL);
+ tarval *zero = get_mode_null(mode);
+ ir_node *cnst = new_d_Const(dbgi, mode, zero);
+
+ /* TODO: bitfields */
+ ir_node *mem = get_store();
+ ir_node *store = new_d_Store(dbgi, mem, base_addr, cnst);
+ ir_node *proj_m = new_Proj(store, mode_M, pn_Store_M);
+ set_store(proj_m);
+ return;
+ }
+ case IR_INITIALIZER_CONST: {
+ ir_node *node = get_initializer_const_value(initializer);
+ ir_mode *mode = get_irn_mode(node);
+ assert(get_type_mode(type) == mode);
+
+ /* TODO: bitfields... */
+ ir_node *mem = get_store();
+ ir_node *store = new_d_Store(dbgi, mem, base_addr, node);
+ ir_node *proj_m = new_Proj(store, mode_M, pn_Store_M);
+ set_store(proj_m);
+ return;
+ }
+ case IR_INITIALIZER_TARVAL: {
+ tarval *tv = get_initializer_tarval_value(initializer);
+ ir_mode *mode = get_tarval_mode(tv);
+ ir_node *cnst = new_d_Const(dbgi, mode, tv);
+ assert(get_type_mode(type) == mode);
+
+ /* TODO: bitfields... */
+ ir_node *mem = get_store();
+ ir_node *store = new_d_Store(dbgi, mem, base_addr, cnst);
+ ir_node *proj_m = new_Proj(store, mode_M, pn_Store_M);
+ set_store(proj_m);
+ return;
+ }
+ case IR_INITIALIZER_COMPOUND: {
+ assert(is_compound_type(type));
+ int n_members;
+ if(is_Array_type(type)) {
+ assert(has_array_upper_bound(type, 0));
+ n_members = get_array_upper_bound_int(type, 0);
+ } else {
+ n_members = get_compound_n_members(type);
+ }
+
+ if(get_initializer_compound_n_entries(initializer)
+ != (unsigned) n_members)
+ panic("initializer doesn't match compound type");
+
+ for(int i = 0; i < n_members; ++i) {
+ ir_node *addr;
+ ir_type *irtype;
+ if(is_Array_type(type)) {
+ ir_entity *entity = get_array_element_entity(type);
+ tarval *index_tv = new_tarval_from_long(i, mode_uint);
+ ir_node *cnst = new_d_Const(dbgi, mode_uint, index_tv);
+ ir_node *in[1] = { cnst };
+ irtype = get_array_element_type(type);
+ addr = new_d_Sel(dbgi, new_NoMem(), base_addr, 1, in, entity);
+ } else {
+ ir_entity *member = get_compound_member(type, i);
+
+ irtype = get_entity_type(member);
+ addr = new_d_simpleSel(dbgi, new_NoMem(), base_addr, member);
+ }
+
+ ir_initializer_t *sub_init
+ = get_initializer_compound_value(initializer, i);
+
+ create_dynamic_initializer_sub(sub_init, irtype, dbgi, addr);
+ }
+ return;
+ }
+ }
+
+ panic("invalid IR_INITIALIZER found");
+}
+
+static void create_dynamic_initializer(ir_initializer_t *initializer,
+ dbg_info *dbgi, ir_entity *entity)
+{
+ ir_node *frame = get_local_frame(entity);
+ ir_node *base_addr = new_d_simpleSel(dbgi, new_NoMem(), frame, entity);
+ ir_type *type = get_entity_type(entity);
+
+ create_dynamic_initializer_sub(initializer, type, dbgi, base_addr);
+}
static void create_local_initializer(initializer_t *initializer, dbg_info *dbgi,
ir_entity *entity, type_t *type)
return;
}
+ if(!is_constant_initializer(initializer)) {
+ ir_initializer_t *irinitializer
+ = create_ir_initializer(initializer, type);
+
+ create_dynamic_initializer(irinitializer, dbgi, entity);
+ return;
+ }
+
+ /* create the ir_initializer */
+ ir_graph *const old_current_ir_graph = current_ir_graph;
+ current_ir_graph = get_const_code_irg();
+
+ ir_initializer_t *irinitializer = create_ir_initializer(initializer, type);
+
+ assert(current_ir_graph == get_const_code_irg());
+ current_ir_graph = old_current_ir_graph;
+
/* create a "template" entity which is copied to the entity on the stack */
ident *const id = unique_ident("initializer");
ir_type *const irtype = get_ir_type(type);
set_entity_visibility(init_entity, visibility_local);
set_entity_allocation(init_entity, allocation_static);
- ir_graph *const old_current_ir_graph = current_ir_graph;
- current_ir_graph = get_const_code_irg();
-
- ir_initializer_t *irinitializer = create_ir_initializer(initializer, type);
set_entity_initializer(init_entity, irinitializer);
- assert(current_ir_graph == get_const_code_irg());
- current_ir_graph = old_current_ir_graph;
-
- ir_node *const src_addr = create_symconst(dbgi, mode_P_data, init_entity);
- ir_node *const copyb = new_d_CopyB(dbgi, memory, addr, src_addr, irtype);
+ ir_node *const src_addr = create_symconst(dbgi, mode_P_data, init_entity);
+ ir_node *const copyb = new_d_CopyB(dbgi, memory, addr, src_addr, irtype);
ir_node *const copyb_mem = new_Proj(copyb, mode_M, pn_CopyB_M_regular);
set_store(copyb_mem);
typedef enum {
STORAGE_CLASS_NONE,
- STORAGE_CLASS_TYPEDEF,
STORAGE_CLASS_EXTERN,
STORAGE_CLASS_STATIC,
+ STORAGE_CLASS_TYPEDEF,
STORAGE_CLASS_AUTO,
STORAGE_CLASS_REGISTER,
STORAGE_CLASS_ENUM_ENTRY,
STORAGE_CLASS_THREAD,
STORAGE_CLASS_THREAD_EXTERN,
- STORAGE_CLASS_THREAD_STATIC
+ STORAGE_CLASS_THREAD_STATIC,
} storage_class_tag_t;
typedef enum {
struct declaration_t {
unsigned char namespc;
+ unsigned char declared_storage_class;
unsigned char storage_class;
decl_modifiers_t modifiers;
unsigned int address_taken : 1;
typedef struct declaration_specifiers_t declaration_specifiers_t;
struct declaration_specifiers_t {
source_position_t source_position;
- unsigned char storage_class;
+ unsigned char declared_storage_class;
bool is_inline;
decl_modifiers_t decl_modifiers;
type_t *type;
symbol_t *const symbol = symbol_table_insert(name);
declaration_t *const declaration = allocate_declaration_zero();
- declaration->namespc = NAMESPACE_NORMAL;
- declaration->storage_class = STORAGE_CLASS_TYPEDEF;
- declaration->type = type;
- declaration->symbol = symbol;
- declaration->source_position = builtin_source_position;
+ declaration->namespc = NAMESPACE_NORMAL;
+ declaration->storage_class = STORAGE_CLASS_TYPEDEF;
+ declaration->declared_storage_class = STORAGE_CLASS_TYPEDEF;
+ declaration->type = type;
+ declaration->symbol = symbol;
+ declaration->source_position = builtin_source_position;
record_declaration(declaration);
return result;
}
+static bool is_initializer_constant(const expression_t *expression)
+{
+ return is_constant_expression(expression)
+ || is_address_constant(expression);
+}
+
static initializer_t *parse_scalar_initializer(type_t *type,
bool must_be_constant)
{
}
expression_t *expression = parse_assignment_expression();
- if(must_be_constant && !is_constant_expression(expression)) {
+ if(must_be_constant && !is_initializer_constant(expression)) {
errorf(expression->base.source_position,
"Initialisation expression '%E' is not constant\n",
expression);
/* must be an expression */
expression_t *expression = parse_assignment_expression();
- if(must_be_constant && !is_constant_expression(expression)) {
+ if(must_be_constant && !is_initializer_constant(expression)) {
errorf(expression->base.source_position,
"Initialisation expression '%E' is not constant\n",
expression);
initializer_t *result = NULL;
size_t max_index;
- if(token.type != '{') {
- expression_t *expression = parse_assignment_expression();
-
- result = initializer_from_expression(type, expression);
- if(result == NULL) {
- errorf(HERE,
- "initializer expression '%E' of type '%T' is incompatible with type '%T'",
- expression, expression->base.type, env->type);
- }
- } else if(is_type_scalar(type)) {
+ if(is_type_scalar(type)) {
/* TODO: § 6.7.8.11; eat {} without warning */
result = parse_scalar_initializer(type, env->must_be_constant);
-
- if(token.type == ',')
- next_token();
} else if(token.type == '{') {
- next_token();
+ eat('{');
type_path_t path;
memset(&path, 0, sizeof(path));
expect_void('}');
} else {
- /* TODO: can this even happen? */
- panic("TODO");
+ /* parse_scalar_initializer also works in this case: we simply
+ * have an expression without {} around it */
+ result = parse_scalar_initializer(type, env->must_be_constant);
}
/* § 6.7.5 (22) array initializers for arrays with unknown size determine
switch(token.type) {
/* storage class */
-#define MATCH_STORAGE_CLASS(token, class) \
- case token: \
- if(specifiers->storage_class != STORAGE_CLASS_NONE) { \
+#define MATCH_STORAGE_CLASS(token, class) \
+ case token: \
+ if(specifiers->declared_storage_class != STORAGE_CLASS_NONE) { \
errorf(HERE, "multiple storage classes in declaration specifiers"); \
- } \
- specifiers->storage_class = class; \
- next_token(); \
+ } \
+ specifiers->declared_storage_class = class; \
+ next_token(); \
break;
MATCH_STORAGE_CLASS(T_typedef, STORAGE_CLASS_TYPEDEF)
MATCH_STORAGE_CLASS(T_register, STORAGE_CLASS_REGISTER)
case T___thread:
- switch (specifiers->storage_class) {
- case STORAGE_CLASS_NONE:
- specifiers->storage_class = STORAGE_CLASS_THREAD;
- break;
+ switch (specifiers->declared_storage_class) {
+ case STORAGE_CLASS_NONE:
+ specifiers->declared_storage_class = STORAGE_CLASS_THREAD;
+ break;
- case STORAGE_CLASS_EXTERN:
- specifiers->storage_class = STORAGE_CLASS_THREAD_EXTERN;
- break;
+ case STORAGE_CLASS_EXTERN:
+ specifiers->declared_storage_class = STORAGE_CLASS_THREAD_EXTERN;
+ break;
- case STORAGE_CLASS_STATIC:
- specifiers->storage_class = STORAGE_CLASS_THREAD_STATIC;
- break;
+ case STORAGE_CLASS_STATIC:
+ specifiers->declared_storage_class = STORAGE_CLASS_THREAD_STATIC;
+ break;
- default:
- errorf(HERE, "multiple storage classes in declaration specifiers");
- break;
+ default:
+ errorf(HERE, "multiple storage classes in declaration specifiers");
+ break;
}
next_token();
break;
{
/* TODO: improve error messages */
- if(declaration->storage_class == STORAGE_CLASS_TYPEDEF) {
+ if(declaration->declared_storage_class == STORAGE_CLASS_TYPEDEF) {
errorf(HERE, "typedef not allowed in parameter list");
- } else if(declaration->storage_class != STORAGE_CLASS_NONE
- && declaration->storage_class != STORAGE_CLASS_REGISTER) {
+ } else if(declaration->declared_storage_class != STORAGE_CLASS_NONE
+ && declaration->declared_storage_class != STORAGE_CLASS_REGISTER) {
errorf(HERE, "parameter may only have none or register storage class");
}
static declaration_t *parse_declarator(
const declaration_specifiers_t *specifiers, bool may_be_abstract)
{
- declaration_t *const declaration = allocate_declaration_zero();
- declaration->storage_class = specifiers->storage_class;
- declaration->modifiers = specifiers->decl_modifiers;
- declaration->is_inline = specifiers->is_inline;
+ declaration_t *const declaration = allocate_declaration_zero();
+ declaration->declared_storage_class = specifiers->declared_storage_class;
+ declaration->modifiers = specifiers->decl_modifiers;
+ declaration->is_inline = specifiers->is_inline;
+
+ declaration->storage_class = specifiers->declared_storage_class;
+ if(declaration->storage_class == STORAGE_CLASS_NONE
+ && scope != global_scope) {
+ declaration->storage_class = STORAGE_CLASS_AUTO;
+ }
construct_type_t *construct_type
= parse_inner_declarator(declaration, may_be_abstract);
}
if (new_storage_class == STORAGE_CLASS_NONE) {
previous_declaration->storage_class = STORAGE_CLASS_NONE;
+ previous_declaration->declared_storage_class = STORAGE_CLASS_NONE;
}
}
} else {
{
eat(';');
- declaration_t *const declaration = allocate_declaration_zero();
- declaration->type = specifiers->type;
- declaration->storage_class = specifiers->storage_class;
- declaration->source_position = specifiers->source_position;
+ declaration_t *const declaration = allocate_declaration_zero();
+ declaration->type = specifiers->type;
+ declaration->declared_storage_class = specifiers->declared_storage_class;
+ declaration->source_position = specifiers->source_position;
- if (declaration->storage_class != STORAGE_CLASS_NONE) {
+ if (declaration->declared_storage_class != STORAGE_CLASS_NONE) {
warningf(declaration->source_position, "useless storage class in empty declaration");
}
+ declaration->storage_class = STORAGE_CLASS_NONE;
type_t *type = declaration->type;
switch (type->kind) {
if(previous_declaration->type == NULL) {
previous_declaration->type = declaration->type;
+ previous_declaration->declared_storage_class = declaration->declared_storage_class;
previous_declaration->storage_class = declaration->storage_class;
previous_declaration->parent_scope = scope;
return previous_declaration;
type_t *type = make_bitfield_type(base_type, size, source_position);
- declaration = allocate_declaration_zero();
- declaration->namespc = NAMESPACE_NORMAL;
- declaration->storage_class = STORAGE_CLASS_NONE;
- declaration->source_position = source_position;
- declaration->modifiers = specifiers->decl_modifiers;
- declaration->type = type;
+ declaration = allocate_declaration_zero();
+ declaration->namespc = NAMESPACE_NORMAL;
+ declaration->declared_storage_class = STORAGE_CLASS_NONE;
+ declaration->storage_class = STORAGE_CLASS_NONE;
+ declaration->source_position = source_position;
+ declaration->modifiers = specifiers->decl_modifiers;
+ declaration->type = type;
} else {
declaration = parse_declarator(specifiers,/*may_be_abstract=*/true);
declaration_specifiers_t specifiers;
memset(&specifiers, 0, sizeof(specifiers));
parse_declaration_specifiers(&specifiers);
- if(specifiers.storage_class != STORAGE_CLASS_NONE) {
+ if(specifiers.declared_storage_class != STORAGE_CLASS_NONE) {
/* TODO: improve error message, user does probably not know what a
* storage class is...
*/
free_type(ntype);
}
- declaration_t *const declaration = allocate_declaration_zero();
- declaration->storage_class = STORAGE_CLASS_EXTERN;
- declaration->type = type;
- declaration->symbol = symbol;
- declaration->source_position = source_position;
- declaration->parent_scope = global_scope;
+ declaration_t *const declaration = allocate_declaration_zero();
+ declaration->storage_class = STORAGE_CLASS_EXTERN;
+ declaration->declared_storage_class = STORAGE_CLASS_EXTERN;
+ declaration->type = type;
+ declaration->symbol = symbol;
+ declaration->source_position = source_position;
+ declaration->parent_scope = global_scope;
scope_t *old_scope = scope;
set_scope(global_scope);
*/
static bool is_local_var_declaration(const declaration_t *declaration) {
switch ((storage_class_tag_t) declaration->storage_class) {
- case STORAGE_CLASS_NONE:
case STORAGE_CLASS_AUTO:
case STORAGE_CLASS_REGISTER: {
const type_t *type = skip_typeref(declaration->type);
* Check if a given declaration represents a variable.
*/
static bool is_var_declaration(const declaration_t *declaration) {
- switch ((storage_class_tag_t) declaration->storage_class) {
- case STORAGE_CLASS_NONE:
- case STORAGE_CLASS_EXTERN:
- case STORAGE_CLASS_STATIC:
- case STORAGE_CLASS_AUTO:
- case STORAGE_CLASS_REGISTER:
- case STORAGE_CLASS_THREAD:
- case STORAGE_CLASS_THREAD_EXTERN:
- case STORAGE_CLASS_THREAD_STATIC: {
- const type_t *type = skip_typeref(declaration->type);
- if(is_type_function(type)) {
- return false;
- } else {
- return true;
- }
- }
- default:
+ if(declaration->storage_class == STORAGE_CLASS_TYPEDEF)
return false;
- }
+
+ const type_t *type = skip_typeref(declaration->type);
+ return !is_type_function(type);
}
/**
--- /dev/null
+int a, b, c;
+
+typedef struct S {
+ int k[3];
+ struct lku {
+ double d, e;
+ } elem;
+} S;
+S kg;
+
+int main(void) {
+ S k = { a, b };
+
+ kg = k;
+
+ return 0;
+}
--- /dev/null
+
+int main(void) {
+ int arr[] = { [4] = 2, };
+
+ return 0;
+}
--- /dev/null
+struct S {
+ int a, b;
+} glob;
+
+struct S *globptr = &glob;
+struct S *globptr2 = &*&glob;
+int *intptr = &*&glob.b;
+int *intp2 = &(&glob + 3)->b;
+
+int arr[10];
+int *p = arr + 4;
+
+int main(void)
+{
+ return 0;
+}
--- /dev/null
+struct S {
+ int a, b;
+} glob;
+
+struct S *globptr = &glob;
+struct S *globptr2 = &*&glob;
+int *intptr = &*&glob.b;
+int *intp2 = ((int*) ((short) &intptr));
+
+int main(void)
+{
+ return 0;
+}