static void semantic_comparison(binary_expression_t *expression);
+static void create_gnu_builtins(void);
+static void create_microsoft_intrinsics(void);
+
#define STORAGE_CLASSES \
STORAGE_CLASSES_NO_EXTERN \
case T_extern:
case T___FUNCTION__: \
case T___PRETTY_FUNCTION__: \
case T___alignof__: \
- case T___builtin_alloca: \
case T___builtin_classify_type: \
case T___builtin_constant_p: \
- case T___builtin_expect: \
- case T___builtin_huge_val: \
- case T___builtin_inf: \
- case T___builtin_inff: \
- case T___builtin_infl: \
case T___builtin_isgreater: \
case T___builtin_isgreaterequal: \
case T___builtin_isless: \
case T___builtin_islessequal: \
case T___builtin_islessgreater: \
case T___builtin_isunordered: \
- case T___builtin_nan: \
- case T___builtin_nanf: \
- case T___builtin_nanl: \
case T___builtin_offsetof: \
- case T___builtin_prefetch: \
case T___builtin_va_arg: \
- case T___builtin_va_end: \
case T___builtin_va_start: \
case T___func__: \
case T___noop: \
[EXPR_ALIGNOF] = sizeof(typeprop_expression_t),
[EXPR_CLASSIFY_TYPE] = sizeof(classify_type_expression_t),
[EXPR_FUNCNAME] = sizeof(funcname_expression_t),
- [EXPR_BUILTIN_SYMBOL] = sizeof(builtin_symbol_expression_t),
[EXPR_BUILTIN_CONSTANT_P] = sizeof(builtin_constant_expression_t),
[EXPR_BUILTIN_TYPES_COMPATIBLE_P] = sizeof(builtin_types_compatible_expression_t),
- [EXPR_BUILTIN_PREFETCH] = sizeof(builtin_prefetch_expression_t),
[EXPR_OFFSETOF] = sizeof(offsetof_expression_t),
[EXPR_VA_START] = sizeof(va_start_expression_t),
[EXPR_VA_ARG] = sizeof(va_arg_expression_t),
}
}
-/** Implements the rules from § 6.5.16.1 */
+/** Implements the rules from §6.5.16.1 */
static assign_error_t semantic_assign(type_t *orig_type_left,
const expression_t *const right)
{
case EXPR_CLASSIFY_TYPE:
case EXPR_ALIGNOF:
case EXPR_FUNCNAME:
- case EXPR_BUILTIN_SYMBOL:
case EXPR_BUILTIN_CONSTANT_P:
case EXPR_BUILTIN_TYPES_COMPATIBLE_P:
- case EXPR_BUILTIN_PREFETCH:
case EXPR_OFFSETOF:
case EXPR_STATEMENT: // TODO
case EXPR_LABEL_ADDRESS:
{
/* TODO check that expression is a constant expression */
- /* § 6.7.8.14/15 char array may be initialized by string literals */
+ /* §6.7.8.14/15 char array may be initialized by string literals */
type_t *type = skip_typeref(orig_type);
type_t *expr_type_orig = expression->base.type;
type_t *expr_type = skip_typeref(expr_type_orig);
/**
* Parses an scalar initializer.
*
- * § 6.7.8.11; eat {} without warning
+ * §6.7.8.11; eat {} without warning
*/
static initializer_t *parse_scalar_initializer(type_t *type,
bool must_be_constant)
result = parse_scalar_initializer(type, env->must_be_constant);
}
- /* § 6.7.8:22 array initializers for arrays with unknown size determine
+ /* §6.7.8:22 array initializers for arrays with unknown size determine
* the array type size */
if (is_type_array(type) && type->array.size_expression == NULL
&& result != NULL) {
type = parse_typename();
} else {
expression = parse_expression();
- type = expression->base.type;
+ type = revert_automatic_type_conversion(expression);
}
break;
if (symbol == NULL)
return entity;
- entity_t *previous_entity = get_entity(symbol, namespc);
+ entity_t *const previous_entity = get_entity(symbol, namespc);
/* pushing the same entity twice will break the stack structure */
assert(previous_entity != entity);
entity->declaration.type, symbol);
}
- if (previous_entity != NULL &&
- previous_entity->base.parent_scope == ¤t_function->parameters &&
- previous_entity->base.parent_scope->depth + 1 == current_scope->depth) {
- assert(previous_entity->kind == ENTITY_PARAMETER);
- errorf(pos,
- "declaration '%#T' redeclares the parameter '%#T' (declared %P)",
- entity->declaration.type, symbol,
- previous_entity->declaration.type, symbol,
- &previous_entity->base.source_position);
- goto finish;
- }
-
- if (previous_entity != NULL &&
- previous_entity->base.parent_scope == current_scope) {
- if (previous_entity->kind != entity->kind) {
- if (!is_error_entity(previous_entity) && !is_error_entity(entity)) {
- error_redefined_as_different_kind(pos, previous_entity,
- entity->kind);
- }
- goto finish;
- }
- if (previous_entity->kind == ENTITY_ENUM_VALUE) {
- errorf(pos, "redeclaration of enum entry '%Y' (declared %P)",
- symbol, &previous_entity->base.source_position);
- goto finish;
- }
- if (previous_entity->kind == ENTITY_TYPEDEF) {
- /* TODO: C++ allows this for exactly the same type */
- errorf(pos, "redefinition of typedef '%Y' (declared %P)",
- symbol, &previous_entity->base.source_position);
+ if (previous_entity != NULL) {
+ if (previous_entity->base.parent_scope == ¤t_function->parameters &&
+ previous_entity->base.parent_scope->depth + 1 == current_scope->depth) {
+ assert(previous_entity->kind == ENTITY_PARAMETER);
+ errorf(pos,
+ "declaration '%#T' redeclares the parameter '%#T' (declared %P)",
+ entity->declaration.type, symbol,
+ previous_entity->declaration.type, symbol,
+ &previous_entity->base.source_position);
goto finish;
}
- /* at this point we should have only VARIABLES or FUNCTIONS */
- assert(is_declaration(previous_entity) && is_declaration(entity));
+ if (previous_entity->base.parent_scope == current_scope) {
+ if (previous_entity->kind != entity->kind) {
+ if (!is_error_entity(previous_entity) && !is_error_entity(entity)) {
+ error_redefined_as_different_kind(pos, previous_entity,
+ entity->kind);
+ }
+ goto finish;
+ }
+ if (previous_entity->kind == ENTITY_ENUM_VALUE) {
+ errorf(pos, "redeclaration of enum entry '%Y' (declared %P)",
+ symbol, &previous_entity->base.source_position);
+ goto finish;
+ }
+ if (previous_entity->kind == ENTITY_TYPEDEF) {
+ /* TODO: C++ allows this for exactly the same type */
+ errorf(pos, "redefinition of typedef '%Y' (declared %P)",
+ symbol, &previous_entity->base.source_position);
+ goto finish;
+ }
- declaration_t *const prev_decl = &previous_entity->declaration;
- declaration_t *const decl = &entity->declaration;
+ /* at this point we should have only VARIABLES or FUNCTIONS */
+ assert(is_declaration(previous_entity) && is_declaration(entity));
+
+ declaration_t *const prev_decl = &previous_entity->declaration;
+ declaration_t *const decl = &entity->declaration;
+
+ /* can happen for K&R style declarations */
+ if (prev_decl->type == NULL &&
+ previous_entity->kind == ENTITY_PARAMETER &&
+ entity->kind == ENTITY_PARAMETER) {
+ prev_decl->type = decl->type;
+ prev_decl->storage_class = decl->storage_class;
+ prev_decl->declared_storage_class = decl->declared_storage_class;
+ prev_decl->modifiers = decl->modifiers;
+ prev_decl->deprecated_string = decl->deprecated_string;
+ return previous_entity;
+ }
- /* can happen for K&R style declarations */
- if (prev_decl->type == NULL &&
- previous_entity->kind == ENTITY_PARAMETER &&
- entity->kind == ENTITY_PARAMETER) {
- prev_decl->type = decl->type;
- prev_decl->storage_class = decl->storage_class;
- prev_decl->declared_storage_class = decl->declared_storage_class;
- prev_decl->modifiers = decl->modifiers;
- prev_decl->deprecated_string = decl->deprecated_string;
- return previous_entity;
- }
+ type_t *const orig_type = decl->type;
+ assert(orig_type != NULL);
+ type_t *const type = skip_typeref(orig_type);
+ type_t *const prev_type = skip_typeref(prev_decl->type);
- type_t *const orig_type = decl->type;
- assert(orig_type != NULL);
- type_t *const type = skip_typeref(orig_type);
- type_t *const prev_type = skip_typeref(prev_decl->type);
+ if (!types_compatible(type, prev_type)) {
+ errorf(pos,
+ "declaration '%#T' is incompatible with '%#T' (declared %P)",
+ orig_type, symbol, prev_decl->type, symbol,
+ &previous_entity->base.source_position);
+ } else {
+ unsigned old_storage_class = prev_decl->storage_class;
+ if (warning.redundant_decls &&
+ is_definition &&
+ !prev_decl->used &&
+ !(prev_decl->modifiers & DM_USED) &&
+ prev_decl->storage_class == STORAGE_CLASS_STATIC) {
+ warningf(&previous_entity->base.source_position,
+ "unnecessary static forward declaration for '%#T'",
+ prev_decl->type, symbol);
+ }
- if (!types_compatible(type, prev_type)) {
- errorf(pos,
- "declaration '%#T' is incompatible with '%#T' (declared %P)",
- orig_type, symbol, prev_decl->type, symbol,
- &previous_entity->base.source_position);
- } else {
- unsigned old_storage_class = prev_decl->storage_class;
- if (warning.redundant_decls &&
- is_definition &&
- !prev_decl->used &&
- !(prev_decl->modifiers & DM_USED) &&
- prev_decl->storage_class == STORAGE_CLASS_STATIC) {
- warningf(&previous_entity->base.source_position,
- "unnecessary static forward declaration for '%#T'",
- prev_decl->type, symbol);
- }
-
- storage_class_t new_storage_class = decl->storage_class;
-
- /* pretend no storage class means extern for function
- * declarations (except if the previous declaration is neither
- * none nor extern) */
- if (entity->kind == ENTITY_FUNCTION) {
- /* the previous declaration could have unspecified parameters or
- * be a typedef, so use the new type */
- if (prev_type->function.unspecified_parameters || is_definition)
- prev_decl->type = type;
+ storage_class_t new_storage_class = decl->storage_class;
+
+ /* pretend no storage class means extern for function
+ * declarations (except if the previous declaration is neither
+ * none nor extern) */
+ if (entity->kind == ENTITY_FUNCTION) {
+ /* the previous declaration could have unspecified parameters or
+ * be a typedef, so use the new type */
+ if (prev_type->function.unspecified_parameters || is_definition)
+ prev_decl->type = type;
+
+ switch (old_storage_class) {
+ case STORAGE_CLASS_NONE:
+ old_storage_class = STORAGE_CLASS_EXTERN;
+ /* FALLTHROUGH */
+
+ case STORAGE_CLASS_EXTERN:
+ if (is_definition) {
+ if (warning.missing_prototypes &&
+ prev_type->function.unspecified_parameters &&
+ !is_sym_main(symbol)) {
+ warningf(pos, "no previous prototype for '%#T'",
+ orig_type, symbol);
+ }
+ } else if (new_storage_class == STORAGE_CLASS_NONE) {
+ new_storage_class = STORAGE_CLASS_EXTERN;
+ }
+ break;
- switch (old_storage_class) {
- case STORAGE_CLASS_NONE:
- old_storage_class = STORAGE_CLASS_EXTERN;
- /* FALLTHROUGH */
-
- case STORAGE_CLASS_EXTERN:
- if (is_definition) {
- if (warning.missing_prototypes &&
- prev_type->function.unspecified_parameters &&
- !is_sym_main(symbol)) {
- warningf(pos, "no previous prototype for '%#T'",
- orig_type, symbol);
- }
- } else if (new_storage_class == STORAGE_CLASS_NONE) {
- new_storage_class = STORAGE_CLASS_EXTERN;
+ default:
+ break;
}
- break;
-
- default:
- break;
+ } else if (is_type_incomplete(prev_type)) {
+ prev_decl->type = type;
}
- } else if (is_type_incomplete(prev_type)) {
- prev_decl->type = type;
- }
- if (old_storage_class == STORAGE_CLASS_EXTERN &&
- new_storage_class == STORAGE_CLASS_EXTERN) {
+ if (old_storage_class == STORAGE_CLASS_EXTERN &&
+ new_storage_class == STORAGE_CLASS_EXTERN) {
warn_redundant_declaration:
- if (!is_definition &&
- warning.redundant_decls &&
- is_type_valid(prev_type) &&
- strcmp(previous_entity->base.source_position.input_name,
- "<builtin>") != 0) {
- warningf(pos,
- "redundant declaration for '%Y' (declared %P)",
- symbol, &previous_entity->base.source_position);
- }
- } else if (current_function == NULL) {
- if (old_storage_class != STORAGE_CLASS_STATIC &&
- new_storage_class == STORAGE_CLASS_STATIC) {
- errorf(pos,
- "static declaration of '%Y' follows non-static declaration (declared %P)",
- symbol, &previous_entity->base.source_position);
- } else if (old_storage_class == STORAGE_CLASS_EXTERN) {
- prev_decl->storage_class = STORAGE_CLASS_NONE;
- prev_decl->declared_storage_class = STORAGE_CLASS_NONE;
- } else {
- /* ISO/IEC 14882:1998(E) §C.1.2:1 */
- if (c_mode & _CXX)
- goto error_redeclaration;
- goto warn_redundant_declaration;
- }
- } else if (is_type_valid(prev_type)) {
- if (old_storage_class == new_storage_class) {
+ if (!is_definition &&
+ warning.redundant_decls &&
+ is_type_valid(prev_type) &&
+ strcmp(previous_entity->base.source_position.input_name,
+ "<builtin>") != 0) {
+ warningf(pos,
+ "redundant declaration for '%Y' (declared %P)",
+ symbol, &previous_entity->base.source_position);
+ }
+ } else if (current_function == NULL) {
+ if (old_storage_class != STORAGE_CLASS_STATIC &&
+ new_storage_class == STORAGE_CLASS_STATIC) {
+ errorf(pos,
+ "static declaration of '%Y' follows non-static declaration (declared %P)",
+ symbol, &previous_entity->base.source_position);
+ } else if (old_storage_class == STORAGE_CLASS_EXTERN) {
+ prev_decl->storage_class = STORAGE_CLASS_NONE;
+ prev_decl->declared_storage_class = STORAGE_CLASS_NONE;
+ } else {
+ /* ISO/IEC 14882:1998(E) §C.1.2:1 */
+ if (c_mode & _CXX)
+ goto error_redeclaration;
+ goto warn_redundant_declaration;
+ }
+ } else if (is_type_valid(prev_type)) {
+ if (old_storage_class == new_storage_class) {
error_redeclaration:
- errorf(pos, "redeclaration of '%Y' (declared %P)",
- symbol, &previous_entity->base.source_position);
- } else {
- errorf(pos,
- "redeclaration of '%Y' with different linkage (declared %P)",
- symbol, &previous_entity->base.source_position);
+ errorf(pos, "redeclaration of '%Y' (declared %P)",
+ symbol, &previous_entity->base.source_position);
+ } else {
+ errorf(pos,
+ "redeclaration of '%Y' with different linkage (declared %P)",
+ symbol, &previous_entity->base.source_position);
+ }
}
}
+
+ prev_decl->modifiers |= decl->modifiers;
+ if (entity->kind == ENTITY_FUNCTION) {
+ previous_entity->function.is_inline |= entity->function.is_inline;
+ }
+ return previous_entity;
}
- prev_decl->modifiers |= decl->modifiers;
- if (entity->kind == ENTITY_FUNCTION) {
- previous_entity->function.is_inline |= entity->function.is_inline;
+ if (warning.shadow) {
+ warningf(pos, "%s '%Y' shadows %s (declared %P)",
+ get_entity_kind_name(entity->kind), symbol,
+ get_entity_kind_name(previous_entity->kind),
+ &previous_entity->base.source_position);
}
- return previous_entity;
}
if (entity->kind == ENTITY_FUNCTION) {
current_init_decl = NULL;
if (entity->kind == ENTITY_VARIABLE) {
- /* § 6.7.5:22 array initializers for arrays with unknown size
+ /* §6.7.5:22 array initializers for arrays with unknown size
* determine the array type size */
declaration->type = env.type;
entity->variable.initializer = initializer;
type_t *type = skip_typeref(orig_type);
if (is_type_integer(type)) {
result = promote_integer(type);
- } else if (type == type_float) {
+ } else if (is_type_atomic(type, ATOMIC_TYPE_FLOAT)) {
result = type_double;
}
last_parameter = function_parameter;
}
- /* § 6.9.1.7: A K&R style parameter list does NOT act as a function
+ /* §6.9.1.7: A K&R style parameter list does NOT act as a function
* prototype */
new_type->function.parameters = parameters;
new_type->function.unspecified_parameters = true;
case EXPR_SIZEOF: // TODO handle obscure VLA case
case EXPR_ALIGNOF:
case EXPR_FUNCNAME:
- case EXPR_BUILTIN_SYMBOL:
case EXPR_BUILTIN_CONSTANT_P:
case EXPR_BUILTIN_TYPES_COMPATIBLE_P:
- case EXPR_BUILTIN_PREFETCH:
case EXPR_OFFSETOF:
case EXPR_INVALID:
return true;
ndeclaration->base.symbol);
}
- /* § 6.7.5.3:14 a function definition with () means no
+ /* §6.7.5.3:14 a function definition with () means no
* parameters (and not unspecified parameters) */
if (type->function.unspecified_parameters &&
type->function.parameters == NULL &&
return identify_new_type(type);
}
+static type_t *make_function_1_type_variadic(type_t *return_type, type_t *argument_type)
+{
+ type_t *res = make_function_1_type(return_type, argument_type);
+ res->function.variadic = 1;
+ return res;
+}
+
+/**
+ * Creates a return_type (func)(void) function type if not
+ * already exists.
+ *
+ * @param return_type the return type
+ */
static type_t *make_function_0_type(type_t *return_type)
{
type_t *type = allocate_type_zero(TYPE_FUNCTION);
}
/**
- * Creates a function type for some function like builtins.
+ * Creates a NO_RETURN return_type (func)(void) function type if not
+ * already exists.
*
- * @param symbol the symbol describing the builtin
- */
-static type_t *get_builtin_symbol_type(symbol_t *symbol)
-{
- switch (symbol->ID) {
- case T___builtin_alloca:
- return make_function_1_type(type_void_ptr, type_size_t);
- case T___builtin_huge_val:
- return make_function_0_type(type_double);
- case T___builtin_inf:
- return make_function_0_type(type_double);
- case T___builtin_inff:
- return make_function_0_type(type_float);
- case T___builtin_infl:
- return make_function_0_type(type_long_double);
- case T___builtin_nan:
- return make_function_1_type(type_double, type_char_ptr);
- case T___builtin_nanf:
- return make_function_1_type(type_float, type_char_ptr);
- case T___builtin_nanl:
- return make_function_1_type(type_long_double, type_char_ptr);
- case T___builtin_va_end:
- return make_function_1_type(type_void, type_valist);
- case T___builtin_expect:
- return make_function_2_type(type_long, type_long, type_long);
- case T___builtin_return_address:
- case T___builtin_frame_address:
- return make_function_1_type(type_void_ptr, type_unsigned_int);
- default:
- internal_errorf(HERE, "not implemented builtin identifier found");
- }
+ * @param return_type the return type
+ */
+static type_t *make_function_0_type_noreturn(type_t *return_type)
+{
+ type_t *type = allocate_type_zero(TYPE_FUNCTION);
+ type->function.return_type = return_type;
+ type->function.parameters = NULL;
+ type->function.base.modifiers |= DM_NORETURN;
+ return type;
+
+ return identify_new_type(type);
}
/**
- * Performs automatic type cast as described in § 6.3.2.1.
+ * Performs automatic type cast as described in §6.3.2.1.
*
* @param orig_type the original type
*/
/**
* reverts the automatic casts of array to pointer types and function
- * to function-pointer types as defined § 6.3.2.1
+ * to function-pointer types as defined §6.3.2.1
*/
type_t *revert_automatic_type_conversion(const expression_t *expression)
{
return type->pointer.points_to;
}
- case EXPR_BUILTIN_SYMBOL:
- return get_builtin_symbol_type(expression->builtin_symbol.symbol);
-
case EXPR_ARRAY_ACCESS: {
const expression_t *array_ref = expression->array_access.array_ref;
type_t *type_left = skip_typeref(array_ref->base.type);
return create_invalid_expression();
}
-static expression_t *parse_builtin_symbol(void)
-{
- expression_t *expression = allocate_expression_zero(EXPR_BUILTIN_SYMBOL);
-
- symbol_t *symbol = token.v.symbol;
-
- expression->builtin_symbol.symbol = symbol;
- next_token();
-
- type_t *type = get_builtin_symbol_type(symbol);
- type = automatic_type_conversion(type);
-
- expression->base.type = type;
- return expression;
-}
-
/**
* Parses a __builtin_constant_p() expression.
*/
return create_invalid_expression();
}
-/**
- * Parses a __builtin_prefetch() expression.
- */
-static expression_t *parse_builtin_prefetch(void)
-{
- expression_t *expression = allocate_expression_zero(EXPR_BUILTIN_PREFETCH);
-
- eat(T___builtin_prefetch);
-
- expect('(', end_error);
- add_anchor_token(')');
- expression->builtin_prefetch.adr = parse_assignment_expression();
- if (token.type == ',') {
- next_token();
- expression->builtin_prefetch.rw = parse_assignment_expression();
- }
- if (token.type == ',') {
- next_token();
- expression->builtin_prefetch.locality = parse_assignment_expression();
- }
- rem_anchor_token(')');
- expect(')', end_error);
- expression->base.type = type_void;
-
- return expression;
-end_error:
- return create_invalid_expression();
-}
-
/**
* Parses a __builtin_is_*() compare 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_expect:
- case T___builtin_alloca:
- case T___builtin_inf:
- case T___builtin_inff:
- case T___builtin_infl:
- case T___builtin_nan:
- case T___builtin_nanf:
- case T___builtin_nanl:
- case T___builtin_huge_val:
- case T___builtin_va_end:
- case T___builtin_return_address:
- case T___builtin_frame_address: return parse_builtin_symbol();
case T___builtin_isgreater:
case T___builtin_isgreaterequal:
case T___builtin_isless:
case T___builtin_islessgreater:
case T___builtin_isunordered: return parse_compare_builtin();
case T___builtin_constant_p: return parse_builtin_constant();
- case T___builtin_prefetch: return parse_builtin_prefetch();
case T___builtin_types_compatible_p: return parse_builtin_types_compatible();
case T__assume: return parse_assume();
case T_ANDAND:
* Handle the semantic restrictions of builtin calls
*/
static void handle_builtin_argument_restrictions(call_expression_t *call) {
- switch (call->function->builtin_symbol.symbol->ID) {
- case T___builtin_return_address:
- case T___builtin_frame_address: {
+ switch (call->function->reference.entity->function.btk) {
+ case bk_gnu_builtin_return_address:
+ case bk_gnu_builtin_frame_address: {
/* argument must be constant */
call_argument_t *argument = call->arguments;
if (! is_constant_expression(argument->expression)) {
errorf(&call->base.source_position,
"argument of '%Y' must be a constant expression",
- call->function->builtin_symbol.symbol);
+ call->function->reference.entity->base.symbol);
+ }
+ break;
+ }
+ case bk_gnu_builtin_prefetch: {
+ /* second and third argument must be constant if existent */
+ call_argument_t *rw = call->arguments->next;
+ call_argument_t *locality = NULL;
+
+ if (rw != NULL) {
+ if (! is_constant_expression(rw->expression)) {
+ errorf(&call->base.source_position,
+ "second argument of '%Y' must be a constant expression",
+ call->function->reference.entity->base.symbol);
+ }
+ locality = rw->next;
+ }
+ if (locality != NULL) {
+ if (! is_constant_expression(locality->expression)) {
+ errorf(&call->base.source_position,
+ "third argument of '%Y' must be a constant expression",
+ call->function->reference.entity->base.symbol);
+ }
+ locality = rw->next;
}
break;
}
"function call has aggregate value");
}
- if (call->function->kind == EXPR_BUILTIN_SYMBOL) {
- handle_builtin_argument_restrictions(&result->call);
+ if (call->function->kind == EXPR_REFERENCE) {
+ reference_expression_t *reference = &call->function->reference;
+ if (reference->entity->kind == ENTITY_FUNCTION &&
+ reference->entity->function.btk != bk_none)
+ handle_builtin_argument_restrictions(call);
}
end_error:
type_left = get_unqualified_type(type_left);
type_right = get_unqualified_type(type_right);
- /* § 6.3.1.8 Usual arithmetic conversions */
+ /* §6.3.1.8 Usual arithmetic conversions */
if (type_left == type_long_double || type_right == type_long_double) {
return type_long_double;
} else if (type_left == type_double || type_right == type_double) {
type_t *const type_left = skip_typeref(orig_type_left);
type_t *const type_right = skip_typeref(orig_type_right);
- /* § 6.5.6 */
+ /* §6.5.6 */
if (is_type_arithmetic(type_left) && is_type_arithmetic(type_right)) {
type_t *arithmetic_type = semantic_arithmetic(type_left, type_right);
expression->left = create_implicit_cast(left, arithmetic_type);
type_t *const type_right = skip_typeref(orig_type_right);
source_position_t const *const pos = &expression->base.source_position;
- /* § 5.6.5 */
+ /* §5.6.5 */
if (is_type_arithmetic(type_left) && is_type_arithmetic(type_right)) {
type_t *arithmetic_type = semantic_arithmetic(type_left, type_right);
expression->left = create_implicit_cast(left, arithmetic_type);
case EXPR_CALL: {
const call_expression_t *const call = &expr->call;
- if (call->function->kind != EXPR_BUILTIN_SYMBOL)
+ if (call->function->kind != EXPR_REFERENCE)
return true;
- switch (call->function->builtin_symbol.symbol->ID) {
- case T___builtin_va_end: return true;
- default: return false;
+ switch (call->function->reference.entity->function.btk) {
+ case bk_gnu_builtin_prefetch:
+ case bk_gnu_builtin_va_end: return true;
+ default: return false;
}
}
case EXPR_ALIGNOF: return false;
case EXPR_FUNCNAME: return false;
- case EXPR_BUILTIN_SYMBOL: break; /* handled in EXPR_CALL */
case EXPR_BUILTIN_CONSTANT_P: return false;
case EXPR_BUILTIN_TYPES_COMPATIBLE_P: return false;
- case EXPR_BUILTIN_PREFETCH: return true;
case EXPR_OFFSETOF: return false;
case EXPR_VA_START: return true;
case EXPR_VA_ARG: return true;
assert(current_scope == NULL);
scope_push(&unit->scope);
+
+ create_gnu_builtins();
+ if (c_mode & _MS)
+ create_microsoft_intrinsics();
}
translation_unit_t *finish_parsing(void)
incomplete_arrays = NULL;
}
+/**
+ * create a builtin function.
+ */
+static entity_t *create_builtin_function(builtin_kind_t kind, const char *name, type_t *function_type)
+{
+ symbol_t *symbol = symbol_table_insert(name);
+ entity_t *entity = allocate_entity_zero(ENTITY_FUNCTION);
+ entity->declaration.storage_class = STORAGE_CLASS_EXTERN;
+ entity->declaration.declared_storage_class = STORAGE_CLASS_EXTERN;
+ entity->declaration.type = function_type;
+ entity->declaration.implicit = true;
+ entity->base.symbol = symbol;
+ entity->base.source_position = builtin_source_position;
+
+ entity->function.btk = kind;
+
+ record_entity(entity, /*is_definition=*/false);
+ return entity;
+}
+
+
+/**
+ * Create predefined gnu builtins.
+ */
+static void create_gnu_builtins(void) {
+#define _STR(a) #a
+#define STR(a) _STR(a)
+#define CONCAT(a,b) a##b
+#define GNU_BUILTIN_NAME(a) STR(CONCAT(__builtin_, a))
+#define GNU_BUILTIN(a, b) create_builtin_function(CONCAT(bk_gnu_builtin_, a), GNU_BUILTIN_NAME(a), b)
+
+ GNU_BUILTIN(alloca, make_function_1_type(type_void_ptr, type_size_t));
+ GNU_BUILTIN(huge_val, make_function_0_type(type_double));
+ GNU_BUILTIN(inf, make_function_0_type(type_double));
+ GNU_BUILTIN(inff, make_function_0_type(type_float));
+ GNU_BUILTIN(infl, make_function_0_type(type_long_double));
+ GNU_BUILTIN(nan, make_function_1_type(type_double, type_char_ptr));
+ GNU_BUILTIN(nanf, make_function_1_type(type_float, type_char_ptr));
+ GNU_BUILTIN(nanl, make_function_1_type(type_long_double, type_char_ptr));
+ GNU_BUILTIN(va_end, make_function_1_type(type_void, type_valist));
+ GNU_BUILTIN(expect, make_function_2_type(type_long, type_long, type_long));
+ GNU_BUILTIN(return_address, make_function_1_type(type_void_ptr, type_unsigned_int));
+ GNU_BUILTIN(frame_address, make_function_1_type(type_void_ptr, type_unsigned_int));
+ GNU_BUILTIN(ffs, make_function_1_type(type_int, type_unsigned_int));
+ GNU_BUILTIN(clz, make_function_1_type(type_int, type_unsigned_int));
+ GNU_BUILTIN(ctz, make_function_1_type(type_int, type_unsigned_int));
+ GNU_BUILTIN(popcount, make_function_1_type(type_int, type_unsigned_int));
+ GNU_BUILTIN(parity, make_function_1_type(type_int, type_unsigned_int));
+ GNU_BUILTIN(prefetch, make_function_1_type_variadic(type_float, type_void_ptr));
+ GNU_BUILTIN(trap, make_function_0_type_noreturn(type_void));
+
+#undef GNU_BUILTIN
+#undef GNU_BUILTIN_NAME
+#undef CONCAT
+#undef STR
+#undef _STR
+}
+
+/**
+ * Create predefined MS intrinsics.
+ */
+static void create_microsoft_intrinsics(void) {
+#define _STR(a) #a
+#define STR(a) _STR(a)
+#define CONCAT(a,b) a##b
+#define MS_BUILTIN(a, b) create_builtin_function(CONCAT(bk_ms, a), STR(a), b)
+
+ MS_BUILTIN(__debugbreak, make_function_0_type(type_void));
+ MS_BUILTIN(_ReturnAddress, make_function_0_type(type_void_ptr));
+ MS_BUILTIN(__popcount, make_function_1_type(type_unsigned_int, type_unsigned_int));
+ MS_BUILTIN(__ud2, make_function_0_type_noreturn(type_void));
+
+#undef MS_BUILTIN
+#undef CONCAT
+#undef STR
+#undef _STR
+}
+
/**
* Initialize the parser.
*/