Consistently use PUSH_PARENT()/POP_PARENT().
[cparser] / ast.c
diff --git a/ast.c b/ast.c
index a2812b8..b8f2b87 100644 (file)
--- a/ast.c
+++ b/ast.c
@@ -213,7 +213,7 @@ static void print_quoted_string(const string_t *const string, char border,
        print_char(border);
        const char *end = string->begin + string->size - skip;
        for (const char *c = string->begin; c != end; ++c) {
-               unsigned char const tc = *c;
+               const char tc = *c;
                if (tc == border) {
                        print_string("\\");
                }
@@ -233,7 +233,7 @@ static void print_quoted_string(const string_t *const string, char border,
                        }
                        /* FALLTHROUGH */
                default:
-                       if (tc < 0x80 && !isprint(tc)) {
+                       if ((unsigned)tc < 0x80 && !isprint(tc)) {
                                print_format("\\%03o", (unsigned)tc);
                        } else {
                                print_char(tc);
@@ -1559,45 +1559,54 @@ expression_classification_t is_constant_initializer(const initializer_t *initial
        panic("invalid initializer kind found");
 }
 
-static expression_classification_t is_object_with_linker_constant_address(const expression_t *expression)
+/**
+ * Checks if an expression references an object with a constant/known location
+ * to the linker. Example:
+ *  - "x", "*&x" with x being a global variable. The value of x need not be
+ *         constant but the address of x is.
+ *  - "a.b.c" when a has a constant/known location to the linker
+ */
+static expression_classification_t is_object_with_linker_constant_address(
+       const expression_t *expression)
 {
        switch (expression->kind) {
        case EXPR_UNARY_DEREFERENCE:
-               return is_address_constant(expression->unary.value);
+               return is_linker_constant(expression->unary.value);
 
        case EXPR_SELECT: {
                type_t *base_type = skip_typeref(expression->select.compound->base.type);
                if (is_type_pointer(base_type)) {
                        /* it's a -> */
-                       return is_address_constant(expression->select.compound);
+                       return is_linker_constant(expression->select.compound);
                } else {
                        return is_object_with_linker_constant_address(expression->select.compound);
                }
        }
 
        case EXPR_ARRAY_ACCESS: {
-               expression_classification_t const ref = is_address_constant(expression->array_access.array_ref);
+               expression_classification_t const ref = is_linker_constant(expression->array_access.array_ref);
                expression_classification_t const idx = is_constant_expression(expression->array_access.index);
                return ref < idx ? ref : idx;
        }
 
        case EXPR_REFERENCE: {
                entity_t *entity = expression->reference.entity;
-               if (is_declaration(entity)) {
-                       switch ((storage_class_tag_t)entity->declaration.storage_class) {
-                       case STORAGE_CLASS_NONE:
-                       case STORAGE_CLASS_EXTERN:
-                       case STORAGE_CLASS_STATIC:
-                               return
-                                       entity->kind != ENTITY_VARIABLE ||
-                                       !entity->variable.thread_local ? EXPR_CLASS_CONSTANT :
-                                       EXPR_CLASS_VARIABLE;
-
-                       case STORAGE_CLASS_REGISTER:
-                       case STORAGE_CLASS_TYPEDEF:
-                       case STORAGE_CLASS_AUTO:
-                               break;
-                       }
+               if (!is_declaration(entity))
+                       return EXPR_CLASS_VARIABLE;
+
+               switch ((storage_class_tag_t)entity->declaration.storage_class) {
+               case STORAGE_CLASS_NONE:
+               case STORAGE_CLASS_EXTERN:
+               case STORAGE_CLASS_STATIC:
+                       return
+                               entity->kind != ENTITY_VARIABLE ||
+                               !entity->variable.thread_local ? EXPR_CLASS_CONSTANT :
+                               EXPR_CLASS_VARIABLE;
+
+               case STORAGE_CLASS_REGISTER:
+               case STORAGE_CLASS_TYPEDEF:
+               case STORAGE_CLASS_AUTO:
+                       break;
                }
                return EXPR_CLASS_VARIABLE;
        }
@@ -1610,7 +1619,7 @@ static expression_classification_t is_object_with_linker_constant_address(const
        }
 }
 
-expression_classification_t is_address_constant(const expression_t *expression)
+expression_classification_t is_linker_constant(const expression_t *expression)
 {
        switch (expression->kind) {
        case EXPR_STRING_LITERAL:
@@ -1627,7 +1636,7 @@ expression_classification_t is_address_constant(const expression_t *expression)
                        = revert_automatic_type_conversion(expression->unary.value);
                /* dereferencing a function is a NOP */
                if (is_type_function(real_type)) {
-                       return is_address_constant(expression->unary.value);
+                       return is_linker_constant(expression->unary.value);
                }
                /* FALLTHROUGH */
        }
@@ -1642,7 +1651,7 @@ expression_classification_t is_address_constant(const expression_t *expression)
                        return EXPR_CLASS_VARIABLE;
 
                expression_classification_t const expr = is_constant_expression(expression->unary.value);
-               expression_classification_t const addr = is_address_constant(expression->unary.value);
+               expression_classification_t const addr = is_linker_constant(expression->unary.value);
                return expr > addr ? expr : addr;
        }
 
@@ -1654,12 +1663,12 @@ expression_classification_t is_address_constant(const expression_t *expression)
                type_t       *const rtype = skip_typeref(right->base.type);
 
                if (is_type_pointer(ltype)) {
-                       expression_classification_t const l = is_address_constant(left);
+                       expression_classification_t const l = is_linker_constant(left);
                        expression_classification_t const r = is_constant_expression(right);
                        return l < r ? l : r;
                } else if (is_type_pointer(rtype)) {
                        expression_classification_t const l = is_constant_expression(left);
-                       expression_classification_t const r = is_address_constant(right);
+                       expression_classification_t const r = is_linker_constant(right);
                        return l < r ? l : r;
                } else if (!is_type_valid(ltype) || !is_type_valid(rtype)) {
                        return EXPR_CLASS_ERROR;
@@ -1690,7 +1699,7 @@ expression_classification_t is_address_constant(const expression_t *expression)
                        skip_typeref(revert_automatic_type_conversion(expression));
                if (!is_type_array(type))
                        return EXPR_CLASS_VARIABLE;
-               expression_classification_t const ref = is_address_constant(expression->array_access.array_ref);
+               expression_classification_t const ref = is_linker_constant(expression->array_access.array_ref);
                expression_classification_t const idx = is_constant_expression(expression->array_access.index);
                return ref < idx ? ref : idx;
        }
@@ -1703,10 +1712,29 @@ expression_classification_t is_address_constant(const expression_t *expression)
 
                if (fold_constant_to_bool(c)) {
                        expression_t const *const t = expression->conditional.true_expression;
-                       return is_address_constant(t != NULL ? t : c);
+                       return is_linker_constant(t != NULL ? t : c);
                } else {
-                       return is_address_constant(expression->conditional.false_expression);
+                       return is_linker_constant(expression->conditional.false_expression);
+               }
+       }
+
+       case EXPR_SELECT: {
+               entity_t *entity = expression->select.compound_entry;
+               if (!is_declaration(entity))
+                       return EXPR_CLASS_VARIABLE;
+               type_t *type = skip_typeref(entity->declaration.type);
+               if (is_type_array(type)) {
+                       /* arrays automatically convert to their address */
+                       expression_t *compound  = expression->select.compound;
+                       type_t       *base_type = skip_typeref(compound->base.type);
+                       if (is_type_pointer(base_type)) {
+                               /* it's a -> */
+                               return is_linker_constant(compound);
+                       } else {
+                               return is_object_with_linker_constant_address(compound);
+                       }
                }
+               return EXPR_CLASS_VARIABLE;
        }
 
        case EXPR_INVALID: