[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,
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 ->).
*
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;
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:
/** 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);
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,
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: \
[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),
};
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))
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);
}
/**
- * Parses a _builtin_va_arg() expression.
+ * Parses a __builtin_va_arg() expression.
*/
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);
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.
*/
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:
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;
}
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") */
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) {
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;