示例#1
0
const struct RFstring *type_callable_category_str(const struct type *t)
{
    RF_ASSERT(type_is_callable(t), "Non callable type detected");
    if (type_is_function(t)) {
        return &s_function_;
    }
    return &s_ctor_;
}
示例#2
0
void fold_expr_funcall(expr *e, symtable *stab)
{
	type *func_ty;
	funcargs *args_from_decl;
	char *sp = NULL;
	unsigned count_decl;

	check_implicit_funcall(e, stab, &sp);

	FOLD_EXPR(e->expr, stab);
	func_ty = e->expr->tree_type;

	if(!type_is_callable(func_ty)){
		warn_at_print_error(&e->expr->where,
				"%s-expression (type '%s') not callable",
				expr_str_friendly(e->expr, 0),
				type_to_str(func_ty));

		fold_had_error = 1;

		e->tree_type = type_nav_btype(cc1_type_nav, type_int);
		return;
	}

	e->tree_type = type_func_call(func_ty, &args_from_decl);

	/* func count comparison, only if the func has arg-decls, or the func is f(void) */
	UCC_ASSERT(args_from_decl, "no funcargs for decl %s", sp);

	count_decl = dynarray_count(args_from_decl->arglist);

	if(check_arg_counts(args_from_decl, count_decl, e->funcargs, e, sp))
		return;

	if(e->funcargs){
		check_arg_voidness_and_nonnulls(
				e, stab,
				args_from_decl, count_decl,
				e->funcargs, sp);
	}

	if(!FUNCARGS_EMPTY_NOVOID(args_from_decl))
		check_arg_types(args_from_decl, e->funcargs, stab, sp, &e->where);

	if(e->funcargs)
		default_promote_args(e->funcargs, count_decl, stab);

	if(type_is_s_or_u(e->tree_type)){
		/* handled transparently by the backend */
		e->f_islval = expr_is_lval_struct;

		cc1_warn_at(&e->expr->where,
				aggregate_return,
				"called function returns aggregate (%s)",
				type_to_str(e->tree_type));
	}

	/* attr */
	{
		type *fnty = e->expr->tree_type;

		/* look through decays */
		if(expr_kind(e->expr, cast) && expr_cast_is_lval2rval(e->expr))
			fnty = expr_cast_child(e->expr)->tree_type;

		format_check_call(fnty, e->funcargs, args_from_decl->variadic);

		sentinel_check(
				&e->where, e,
				e->funcargs, args_from_decl->variadic,
				count_decl, stab);
	}

	/* check the subexp tree type to get the funcall attributes */
	if(func_or_builtin_attr_present(e, attr_warn_unused))
		e->freestanding = 0; /* needs use */

	if(sp && !cc1_fopt.freestanding)
		check_standard_funcs(sp, e->funcargs);
}
示例#3
0
enum traversal_cb_res typecheck_function_call(
    struct ast_node *n,
    struct analyzer_traversal_ctx *ctx)
{
    const struct RFstring *fn_name;
    const struct type *fn_type;
    const struct type *fn_declared_args_type;
    const struct type *fn_found_args_type;
    struct ast_node *fn_call_args = ast_fncall_args(n);

    // check for existence of function
    fn_name = ast_fncall_name(n);
    fn_type = type_lookup_identifier_string(fn_name, ctx->current_st);

    if (!fn_type || !type_is_callable(fn_type)) {
        analyzer_err(ctx->m, ast_node_startmark(n),
                     ast_node_endmark(n),
                     "Undefined function call \""RFS_PF"\" detected",
                     RFS_PA(fn_name));
        goto fail;
    }

    // create the arguments ast node array
    ast_fncall_arguments(n);

    // also check the ast node of the function declaration to get more
    // information if it's not a conversion
    if (!type_is_explicitly_convertable_elementary(fn_type)) {
        const struct ast_node *fndecl = symbol_table_lookup_node(
            ctx->current_st,
            fn_name,
            NULL
        );
        RF_ASSERT(fndecl, "Since fn_type was found so should fndecl be found here");
        if (fndecl->fndecl.position == FNDECL_PARTOF_FOREIGN_IMPORT) {
            n->fncall.type = AST_FNCALL_FOREIGN;
        }
    }

    fn_found_args_type = (fn_call_args)
        ? ast_node_get_type(fn_call_args)
        : type_elementary_get_type(ELEMENTARY_TYPE_NIL);

    if (!fn_found_args_type) { // argument typechecking failed
        goto fail;
    }

    if (type_is_explicitly_convertable_elementary(fn_type)) {
        // silly way to check if it's only 1 argument. Maybe figure out safer way?
        if (!fn_call_args || fn_found_args_type->category == TYPE_CATEGORY_OPERATOR) {
            analyzer_err(
                ctx->m,
                ast_node_startmark(n),
                ast_node_endmark(n),
                "Invalid arguments for explicit conversion to \""
                RFS_PF"\".",
                RFS_PA(fn_name)
            );
            goto fail;
        }

        // check if the explicit conversion is valid
        if (!type_compare(fn_found_args_type, fn_type, TYPECMP_EXPLICIT_CONVERSION)) {
            analyzer_err(ctx->m, ast_node_startmark(n), ast_node_endmark(n),
                         "Invalid explicit conversion. "RFS_PF".",
                         RFS_PA(typecmp_ctx_get_error()));
            goto fail;
        }
        n->fncall.type = AST_FNCALL_EXPLICIT_CONVERSION;
    } else {
        //check that the types of its arguments do indeed match
        fn_declared_args_type = type_callable_get_argtype(fn_type);
        n->fncall.declared_type = fn_declared_args_type;
        if (type_is_sumop(fn_declared_args_type)) {
            n->fncall.type = AST_FNCALL_SUM;
        }
        typecmp_ctx_set_flags(TYPECMP_FLAG_FUNCTION_CALL);
        if (!type_compare(
                fn_found_args_type,
                fn_declared_args_type,
                n->fncall.type == AST_FNCALL_SUM
                    ? TYPECMP_PATTERN_MATCHING :
                    TYPECMP_IMPLICIT_CONVERSION)) {
            RFS_PUSH();
            analyzer_err(
                ctx->m, ast_node_startmark(n), ast_node_endmark(n),
                RFS_PF" "RFS_PF"() is called with argument type of \""RFS_PF
                "\" which does not match the expected "
                "type of \""RFS_PF"\"%s"RFS_PF".",
                RFS_PA(type_callable_category_str(fn_type)),
                RFS_PA(fn_name),
                RFS_PA(type_str_or_die(fn_found_args_type, TSTR_DEFAULT)),
                RFS_PA(type_str_or_die(fn_declared_args_type, TSTR_DEFINED_ONLY_CONTENTS)),
                typecmp_ctx_have_error() ? ". " : "",
                RFS_PA(typecmp_ctx_get_error())
            );
            RFS_POP();
            goto fail;
        }
        // the function call's matched type should be either a specific sum type
        // that may have matched or the entirety of the called arguments
        if (!(n->fncall.params_type = typemp_ctx_get_matched_type())) {
            n->fncall.params_type = fn_found_args_type;
        }
    }

    traversal_node_set_type(n, type_callable_get_rettype(fn_type), ctx);
    return TRAVERSAL_CB_OK;

fail:
    traversal_node_set_type(n, NULL, ctx);
    return TRAVERSAL_CB_ERROR;
}