- implemented va_copy(), needed for C99
authorMichael Beck <beck@ipd.info.uni-karlsruhe.de>
Sat, 3 Jan 2009 03:56:38 +0000 (03:56 +0000)
committerMichael Beck <beck@ipd.info.uni-karlsruhe.de>
Sat, 3 Jan 2009 03:56:38 +0000 (03:56 +0000)
- add semantic to va_arg
- add walk_expression support for va_* expressions

[r25070]

ast.c
ast.h
ast2firm.c
ast_t.h
parser.c
tokens.inc
type.c
type.h
types.c
types.h
walk_statements.c

diff --git a/ast.c b/ast.c
index 13081b1..be6a25a 100644 (file)
--- a/ast.c
+++ b/ast.c
@@ -119,6 +119,7 @@ static unsigned get_expression_precedence(expression_kind_t kind)
                [EXPR_OFFSETOF]                   = PREC_PRIMARY,
                [EXPR_VA_START]                   = PREC_PRIMARY,
                [EXPR_VA_ARG]                     = PREC_PRIMARY,
+               [EXPR_VA_COPY]                    = PREC_PRIMARY,
                [EXPR_STATEMENT]                  = PREC_PRIMARY,
                [EXPR_LABEL_ADDRESS]              = PREC_PRIMARY,
 
@@ -655,6 +656,20 @@ static void print_va_arg(const va_arg_expression_t *expression)
        fputc(')', out);
 }
 
+/**
+ * Prints a va_copy expression.
+ *
+ * @param expression   the va_copy expression
+ */
+static void print_va_copy(const va_copy_expression_t *expression)
+{
+       fputs("__builtin_va_copy(", out);
+       print_assignment_expression(expression->dst);
+       fputs(", ", out);
+       print_assignment_expression(expression->src);
+       fputc(')', out);
+}
+
 /**
  * Prints a select expression (. or ->).
  *
@@ -813,6 +828,9 @@ static void print_expression_prec(const expression_t *expression, unsigned top_p
        case EXPR_VA_ARG:
                print_va_arg(&expression->va_arge);
                break;
+       case EXPR_VA_COPY:
+               print_va_copy(&expression->va_copye);
+               break;
        case EXPR_SELECT:
                print_select(&expression->select);
                break;
@@ -1845,6 +1863,7 @@ bool is_constant_expression(const expression_t *expression)
        case EXPR_SELECT:
        case EXPR_VA_START:
        case EXPR_VA_ARG:
+       case EXPR_VA_COPY:
        case EXPR_STATEMENT:
        case EXPR_REFERENCE:
        case EXPR_UNARY_POSTFIX_INCREMENT:
diff --git a/ast.h b/ast.h
index e13e601..4813746 100644 (file)
--- a/ast.h
+++ b/ast.h
@@ -48,6 +48,7 @@ typedef struct designator_t                          designator_t;
 typedef struct offsetof_expression_t                 offsetof_expression_t;
 typedef struct va_start_expression_t                 va_start_expression_t;
 typedef struct va_arg_expression_t                   va_arg_expression_t;
+typedef struct va_copy_expression_t                  va_copy_expression_t;
 typedef struct builtin_constant_expression_t         builtin_constant_expression_t;
 typedef struct builtin_types_compatible_expression_t builtin_types_compatible_expression_t;
 typedef struct classify_type_expression_t            classify_type_expression_t;
index b679fc8..7f17d0a 100644 (file)
@@ -3263,6 +3263,17 @@ static ir_node *va_arg_expression_to_firm(const va_arg_expression_t *const expr)
        return res;
 }
 
+/**
+ * Generate Firm for a va_copy expression.
+ */
+static ir_node *va_copy_expression_to_firm(const va_copy_expression_t *const expr)
+{
+       dbg_info *const dbgi = get_dbg_info(&expr->base.source_position);
+       ir_node  *const src  = expression_to_firm(expr->src);
+       set_value_for_expression(expr->dst, src);
+       return NULL;
+}
+
 static ir_node *dereference_addr(const unary_expression_t *const expression)
 {
        assert(expression->base.kind == EXPR_UNARY_DEREFERENCE);
@@ -3411,6 +3422,8 @@ static ir_node *_expression_to_firm(const expression_t *expression)
                return va_start_expression_to_firm(&expression->va_starte);
        case EXPR_VA_ARG:
                return va_arg_expression_to_firm(&expression->va_arge);
+       case EXPR_VA_COPY:
+               return va_copy_expression_to_firm(&expression->va_copye);
        case EXPR_BUILTIN_CONSTANT_P:
                return builtin_constant_to_firm(&expression->builtin_constant);
        case EXPR_BUILTIN_TYPES_COMPATIBLE_P:
diff --git a/ast_t.h b/ast_t.h
index c9e2b4f..af807be 100644 (file)
--- a/ast_t.h
+++ b/ast_t.h
@@ -86,6 +86,7 @@ typedef enum expression_kind_t {
        EXPR_OFFSETOF,
        EXPR_VA_START,
        EXPR_VA_ARG,
+       EXPR_VA_COPY,
        EXPR_STATEMENT,
        EXPR_LABEL_ADDRESS, /**< GCC extension &&label operator */
 
@@ -361,6 +362,12 @@ struct va_arg_expression_t {
        expression_t      *ap;
 };
 
+struct va_copy_expression_t {
+       expression_base_t  base;
+       expression_t      *dst;    /**< destination argument */
+       expression_t      *src;    /**< source argument */
+};
+
 struct conditional_expression_t {
        expression_base_t  base;
        expression_t      *condition;
@@ -403,6 +410,7 @@ union expression_t {
        offsetof_expression_t                 offsetofe;
        va_start_expression_t                 va_starte;
        va_arg_expression_t                   va_arge;
+       va_copy_expression_t                  va_copye;
        conditional_expression_t              conditional;
        statement_expression_t                statement;
        classify_type_expression_t            classify_type;
index 801acc3..b4264ed 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -171,8 +171,6 @@ static unsigned char token_anchor_set[T_LAST_TOKEN];
 /** true if we are in GCC mode. */
 #define GNU_MODE ((c_mode & _GNUC) || in_gcc_extension)
 
-static type_t *type_valist;
-
 static statement_t *parse_compound_statement(bool inside_expression_statement);
 static statement_t *parse_statement(void);
 
@@ -184,6 +182,9 @@ static void          parse_external(void);
 
 static void parse_compound_type_entries(compound_t *compound_declaration);
 
+static void check_call_argument(type_t          *expected_type,
+                                                               call_argument_t *argument, unsigned pos);
+
 typedef enum declarator_flags_t {
        DECL_FLAGS_NONE             = 0,
        DECL_MAY_BE_ABSTRACT        = 1U << 0,
@@ -294,6 +295,7 @@ static void create_microsoft_intrinsics(void);
        case T___builtin_offsetof:       \
        case T___builtin_va_arg:         \
        case T___builtin_va_start:       \
+       case T___builtin_va_copy:        \
        case T___func__:                 \
        case T___noop:                   \
        case T__assume:                  \
@@ -419,6 +421,7 @@ static size_t get_expression_struct_size(expression_kind_t kind)
                [EXPR_OFFSETOF]                   = sizeof(offsetof_expression_t),
                [EXPR_VA_START]                   = sizeof(va_start_expression_t),
                [EXPR_VA_ARG]                     = sizeof(va_arg_expression_t),
+               [EXPR_VA_COPY]                    = sizeof(va_copy_expression_t),
                [EXPR_STATEMENT]                  = sizeof(statement_expression_t),
                [EXPR_LABEL_ADDRESS]              = sizeof(label_address_expression_t),
        };
@@ -2037,6 +2040,10 @@ static void mark_vars_read(expression_t *const expr, entity_t *lhs_ent)
                        mark_vars_read(expr->va_arge.ap, lhs_ent);
                        return;
 
+               case EXPR_VA_COPY:
+                       mark_vars_read(expr->va_copye.src, lhs_ent);
+                       return;
+
                case EXPR_UNARY_CAST:
                        /* Special case: Use void cast to mark a variable as "read" */
                        if (is_type_atomic(skip_typeref(expr->base.type), ATOMIC_TYPE_VOID))
@@ -5776,6 +5783,9 @@ static bool expression_returns(expression_t const *const expr)
                case EXPR_VA_ARG:
                        return expression_returns(expr->va_arge.ap);
 
+               case EXPR_VA_COPY:
+                       return expression_returns(expr->va_copye.src);
+
                EXPR_UNARY_CASES_MANDATORY
                        return expression_returns(expr->unary.value);
 
@@ -7456,7 +7466,7 @@ end_error:
 }
 
 /**
- * Parses a _builtin_va_arg() expression.
+ * Parses a __builtin_va_arg() expression.
  */
 static expression_t *parse_va_arg(void)
 {
@@ -7465,7 +7475,11 @@ static expression_t *parse_va_arg(void)
        eat(T___builtin_va_arg);
 
        expect('(', end_error);
-       expression->va_arge.ap = parse_assignment_expression();
+       call_argument_t ap;
+       ap.expression = parse_assignment_expression();
+       expression->va_arge.ap = ap.expression;
+       check_call_argument(type_valist, &ap, 1);
+
        expect(',', end_error);
        expression->base.type = parse_typename();
        expect(')', end_error);
@@ -7475,6 +7489,35 @@ end_error:
        return create_invalid_expression();
 }
 
+/**
+ * Parses a __builtin_va_copy() expression.
+ */
+static expression_t *parse_va_copy(void)
+{
+       expression_t *expression = allocate_expression_zero(EXPR_VA_COPY);
+
+       eat(T___builtin_va_copy);
+
+       expect('(', end_error);
+       expression_t *dst = parse_assignment_expression();
+       assign_error_t error = semantic_assign(type_valist, dst);
+       report_assign_error(error, type_valist, dst, "call argument 1",
+                           &dst->base.source_position);
+       expression->va_copye.dst = dst;
+
+       expect(',', end_error);
+
+       call_argument_t src;
+       src.expression = parse_assignment_expression();
+       check_call_argument(type_valist, &src, 2);
+       expression->va_copye.src = src.expression;
+       expect(')', end_error);
+
+       return expression;
+end_error:
+       return create_invalid_expression();
+}
+
 /**
  * Parses a __builtin_constant_p() expression.
  */
@@ -7750,6 +7793,7 @@ static expression_t *parse_primary_expression(void)
                case T___builtin_offsetof:           return parse_offsetof();
                case T___builtin_va_start:           return parse_va_start();
                case T___builtin_va_arg:             return parse_va_arg();
+               case T___builtin_va_copy:            return parse_va_copy();
                case T___builtin_isgreater:
                case T___builtin_isgreaterequal:
                case T___builtin_isless:
@@ -7982,10 +8026,9 @@ create_error_entry:
        return select;
 }
 
-static void check_call_argument(const function_parameter_t *parameter,
+static void check_call_argument(type_t          *expected_type,
                                 call_argument_t *argument, unsigned pos)
 {
-       type_t         *expected_type      = parameter->type;
        type_t         *expected_type_skip = skip_typeref(expected_type);
        assign_error_t  error              = ASSIGN_ERROR_INCOMPATIBLE;
        expression_t   *arg_expr           = argument->expression;
@@ -8019,8 +8062,7 @@ static void check_call_argument(const function_parameter_t *parameter,
        }
 
        error                = semantic_assign(expected_type, arg_expr);
-       argument->expression = create_implicit_cast(argument->expression,
-                                                   expected_type);
+       argument->expression = create_implicit_cast(arg_expr, expected_type);
 
        if (error != ASSIGN_SUCCESS) {
                /* report exact scope in error messages (like "in argument 3") */
@@ -8145,7 +8187,7 @@ static expression_t *parse_call_expression(expression_t *expression)
        if (!function_type->unspecified_parameters) {
                for (unsigned pos = 0; parameter != NULL && argument != NULL;
                                parameter = parameter->next, argument = argument->next) {
-                       check_call_argument(parameter, argument, ++pos);
+                       check_call_argument(parameter->type, argument, ++pos);
                }
 
                if (parameter != NULL) {
@@ -9353,6 +9395,7 @@ static bool expression_has_effect(const expression_t *const expr)
                case EXPR_OFFSETOF:                   return false;
                case EXPR_VA_START:                   return true;
                case EXPR_VA_ARG:                     return true;
+               case EXPR_VA_COPY:                    return true;
                case EXPR_STATEMENT:                  return true; // TODO
                case EXPR_COMPOUND_LITERAL:           return false;
 
index d4741e4..a379dc7 100644 (file)
@@ -89,8 +89,9 @@ S(_ALL, __thread)
 S(_ALL, __extension__)
 S(_ALL, __builtin_classify_type)
 S(_ALL, __builtin_va_list)
-S(_ALL, __builtin_offsetof)
 S(_ALL, __builtin_va_arg)
+S(_ALL, __builtin_va_copy)
+S(_ALL, __builtin_offsetof)
 S(_ALL, __builtin_constant_p)
 S(_ALL, __builtin_types_compatible_p)
 S(_ALL, __builtin_isgreater)
diff --git a/type.c b/type.c
index 6fb1528..cd6f559 100644 (file)
--- a/type.c
+++ b/type.c
@@ -23,6 +23,7 @@
 #include <assert.h>
 
 #include "type_t.h"
+#include "types.h"
 #include "entity_t.h"
 #include "symbol_t.h"
 #include "type_hash.h"
@@ -1076,6 +1077,14 @@ bool is_type_object(const type_t *type)
        return !is_type_function(type) && !is_type_incomplete(type);
 }
 
+bool is_builtin_va_list(type_t *type)
+{
+       type_t *tp = skip_typeref(type);
+
+       return tp->kind == type_valist->kind &&
+              tp->builtin.symbol == type_valist->builtin.symbol;
+}
+
 /**
  * Check if two function types are compatible.
  */
diff --git a/type.h b/type.h
index 751d658..6bf52cf 100644 (file)
--- a/type.h
+++ b/type.h
@@ -165,6 +165,11 @@ bool is_type_incomplete(const type_t *type);
 
 bool is_type_object(const type_t *type);
 
+/**
+ * returns true if teh type is the builtin va_list type.
+ */
+bool is_builtin_va_list(type_t *type);
+
 bool types_compatible(const type_t *type1, const type_t *type2);
 
 type_t *get_unqualified_type(type_t *type);
diff --git a/types.c b/types.c
index 812dc68..98fd054 100644 (file)
--- a/types.c
+++ b/types.c
@@ -71,6 +71,8 @@ type_t *type_ssize_t_ptr;
 type_t *type_wchar_t_ptr;
 type_t *type_const_wchar_t_ptr;
 
+type_t *type_valist;
+
 /* microsoft types */
 atomic_type_kind_t int8_type_kind            = ATOMIC_TYPE_INVALID;
 atomic_type_kind_t int16_type_kind           = ATOMIC_TYPE_INVALID;
diff --git a/types.h b/types.h
index 08142c3..26ffe3a 100644 (file)
--- a/types.h
+++ b/types.h
@@ -71,6 +71,8 @@ extern type_t *type_ssize_t_ptr;
 extern type_t *type_wchar_t_ptr;
 extern type_t *type_const_wchar_t_ptr;
 
+extern type_t *type_valist;
+
 /* microsoft types */
 extern atomic_type_kind_t int8_type_kind;
 extern atomic_type_kind_t int16_type_kind;
index 1201dd7..4e1d511 100644 (file)
@@ -75,6 +75,19 @@ static void walk_expression(expression_t const *const expr,
                return;
        }
 
+       case EXPR_VA_START:
+               walk_expression(expr->va_starte.ap, callback, env);
+               return;
+
+       case EXPR_VA_ARG:
+               walk_expression(expr->va_arge.ap, callback, env);
+               return;
+
+       case EXPR_VA_COPY:
+               walk_expression(expr->va_copye.src, callback, env);
+               walk_expression(expr->va_copye.dst, callback, env);
+               return;
+
        case EXPR_INVALID:
        case EXPR_OFFSETOF:
        case EXPR_REFERENCE:
@@ -85,8 +98,6 @@ static void walk_expression(expression_t const *const expr,
        case EXPR_STRING_LITERAL:
        case EXPR_WIDE_STRING_LITERAL:
        case EXPR_FUNCNAME:
-       case EXPR_VA_START:
-       case EXPR_VA_ARG:
        case EXPR_LABEL_ADDRESS:
        case EXPR_BUILTIN_TYPES_COMPATIBLE_P:
                break;