diff options
Diffstat (limited to 'gcc/c')
-rw-r--r-- | gcc/c/ChangeLog | 16 | ||||
-rw-r--r-- | gcc/c/c-decl.c | 54 | ||||
-rw-r--r-- | gcc/c/c-typeck.c | 724 |
3 files changed, 544 insertions, 250 deletions
diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog index 6620bd0..706839c 100644 --- a/gcc/c/ChangeLog +++ b/gcc/c/ChangeLog @@ -1,3 +1,19 @@ +2018-11-15 Martin Sebor <msebor@redhat.com> + + PR c/83656 + * c-decl.c (header_for_builtin_fn): Declare. + (diagnose_mismatched_decls): Diagnose declarations of built-in + functions without a prototype. + * c-typeck.c (maybe_warn_builtin_no_proto_arg): New function. + (convert_argument): Same. + (convert_arguments): Factor code out into convert_argument. + Detect mismatches between built-in formal arguments in calls + to built-in without prototype. + (build_conditional_expr): Same. + (type_or_builtin_type): New function. + (convert_for_assignment): Add argument. Conditionally issue + warnings instead of errors for mismatches. + 2018-11-13 David Malcolm <dmalcolm@redhat.com> * c-decl.c: Replace "source_location" with "location_t". diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c index 4a62b1e..cdd10ab 100644 --- a/gcc/c/c-decl.c +++ b/gcc/c/c-decl.c @@ -604,6 +604,7 @@ static tree grokparms (struct c_arg_info *, bool); static void layout_array_type (tree); static void warn_defaults_to (location_t, int, const char *, ...) ATTRIBUTE_GCC_DIAG(3,4); +static const char *header_for_builtin_fn (enum built_in_function); /* T is a statement. Add it to the statement-tree. This is the C/ObjC version--C++ has a slightly different version of this @@ -1887,12 +1888,25 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl, *oldtypep = oldtype = trytype; else { + const char *header + = header_for_builtin_fn (DECL_FUNCTION_CODE (olddecl)); + location_t loc = DECL_SOURCE_LOCATION (newdecl); + if (warning_at (loc, OPT_Wbuiltin_declaration_mismatch, + "conflicting types for built-in function %q+D; " + "expected %qT", + newdecl, oldtype) + && header) + { + /* Suggest the right header to include as the preferred + solution rather than the spelling of the declaration. */ + rich_location richloc (line_table, loc); + maybe_add_include_fixit (&richloc, header, true); + inform (&richloc, + "%qD is declared in header %qs", olddecl, header); + } /* If types don't match for a built-in, throw away the built-in. No point in calling locate_old_decl here, it won't print anything. */ - warning (OPT_Wbuiltin_declaration_mismatch, - "conflicting types for built-in function %q+D", - newdecl); return false; } } @@ -2026,15 +2040,33 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl, can't validate the argument list) the built-in definition is overridden, but optionally warn this was a bad choice of name. */ if (fndecl_built_in_p (olddecl) - && !C_DECL_DECLARED_BUILTIN (olddecl) - && (!TREE_PUBLIC (newdecl) - || (DECL_INITIAL (newdecl) - && !prototype_p (TREE_TYPE (newdecl))))) + && !C_DECL_DECLARED_BUILTIN (olddecl)) { - warning (OPT_Wshadow, "declaration of %q+D shadows " - "a built-in function", newdecl); - /* Discard the old built-in function. */ - return false; + if (!TREE_PUBLIC (newdecl) + || (DECL_INITIAL (newdecl) + && !prototype_p (TREE_TYPE (newdecl)))) + { + warning_at (DECL_SOURCE_LOCATION (newdecl), + OPT_Wshadow, "declaration of %qD shadows " + "a built-in function", newdecl); + /* Discard the old built-in function. */ + return false; + } + + if (!prototype_p (TREE_TYPE (newdecl))) + { + /* Set for built-ins that take no arguments. */ + bool func_void_args = false; + if (tree at = TYPE_ARG_TYPES (oldtype)) + func_void_args = VOID_TYPE_P (TREE_VALUE (at)); + + if (extra_warnings && !func_void_args) + warning_at (DECL_SOURCE_LOCATION (newdecl), + OPT_Wbuiltin_declaration_mismatch, + "declaration of built-in function %qD without " + "a prototype; expected %qT", + newdecl, TREE_TYPE (olddecl)); + } } if (DECL_INITIAL (newdecl)) diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c index 5d4e973..bdfcb53 100644 --- a/gcc/c/c-typeck.c +++ b/gcc/c/c-typeck.c @@ -97,7 +97,8 @@ static int convert_arguments (location_t, vec<location_t>, tree, tree); static tree pointer_diff (location_t, tree, tree, tree *); static tree convert_for_assignment (location_t, location_t, tree, tree, tree, - enum impl_conv, bool, tree, tree, int); + enum impl_conv, bool, tree, tree, int, + int = 0); static tree valid_compound_expr_initializer (tree, tree); static void push_string (const char *); static void push_member_name (tree); @@ -3183,6 +3184,188 @@ c_build_function_call_vec (location_t loc, vec<location_t> arg_loc, return build_function_call_vec (loc, arg_loc, function, params, origtypes); } +/* Helper for convert_arguments called to convert the VALue of argument + number ARGNUM from ORIGTYPE to the corresponding parameter number + PARMNUL and TYPE. */ + +static tree +convert_argument (location_t ploc, tree function, tree fundecl, + tree type, tree origtype, tree val, bool npc, + tree rname, int parmnum, int argnum, + bool excess_precision, int warnopt) +{ + tree valtype = TREE_TYPE (val); + + tree parmval; + + /* Formal parm type is specified by a function prototype. */ + + if (type == error_mark_node || !COMPLETE_TYPE_P (type)) + { + error_at (ploc, "type of formal parameter %d is incomplete", + parmnum + 1); + parmval = val; + } + else + { + /* Optionally warn about conversions that differ from the default + conversions. */ + if (warn_traditional_conversion || warn_traditional) + { + unsigned int formal_prec = TYPE_PRECISION (type); + + if (INTEGRAL_TYPE_P (type) + && TREE_CODE (valtype) == REAL_TYPE) + warning_at (ploc, OPT_Wtraditional_conversion, + "passing argument %d of %qE as integer rather " + "than floating due to prototype", + argnum, rname); + if (INTEGRAL_TYPE_P (type) + && TREE_CODE (valtype) == COMPLEX_TYPE) + warning_at (ploc, OPT_Wtraditional_conversion, + "passing argument %d of %qE as integer rather " + "than complex due to prototype", + argnum, rname); + else if (TREE_CODE (type) == COMPLEX_TYPE + && TREE_CODE (valtype) == REAL_TYPE) + warning_at (ploc, OPT_Wtraditional_conversion, + "passing argument %d of %qE as complex rather " + "than floating due to prototype", + argnum, rname); + else if (TREE_CODE (type) == REAL_TYPE + && INTEGRAL_TYPE_P (valtype)) + warning_at (ploc, OPT_Wtraditional_conversion, + "passing argument %d of %qE as floating rather " + "than integer due to prototype", + argnum, rname); + else if (TREE_CODE (type) == COMPLEX_TYPE + && INTEGRAL_TYPE_P (valtype)) + warning_at (ploc, OPT_Wtraditional_conversion, + "passing argument %d of %qE as complex rather " + "than integer due to prototype", + argnum, rname); + else if (TREE_CODE (type) == REAL_TYPE + && TREE_CODE (valtype) == COMPLEX_TYPE) + warning_at (ploc, OPT_Wtraditional_conversion, + "passing argument %d of %qE as floating rather " + "than complex due to prototype", + argnum, rname); + /* ??? At some point, messages should be written about + conversions between complex types, but that's too messy + to do now. */ + else if (TREE_CODE (type) == REAL_TYPE + && TREE_CODE (valtype) == REAL_TYPE) + { + /* Warn if any argument is passed as `float', + since without a prototype it would be `double'. */ + if (formal_prec == TYPE_PRECISION (float_type_node) + && type != dfloat32_type_node) + warning_at (ploc, 0, + "passing argument %d of %qE as %<float%> " + "rather than %<double%> due to prototype", + argnum, rname); + + /* Warn if mismatch between argument and prototype + for decimal float types. Warn of conversions with + binary float types and of precision narrowing due to + prototype. */ + else if (type != valtype + && (type == dfloat32_type_node + || type == dfloat64_type_node + || type == dfloat128_type_node + || valtype == dfloat32_type_node + || valtype == dfloat64_type_node + || valtype == dfloat128_type_node) + && (formal_prec + <= TYPE_PRECISION (valtype) + || (type == dfloat128_type_node + && (valtype + != dfloat64_type_node + && (valtype + != dfloat32_type_node))) + || (type == dfloat64_type_node + && (valtype + != dfloat32_type_node)))) + warning_at (ploc, 0, + "passing argument %d of %qE as %qT " + "rather than %qT due to prototype", + argnum, rname, type, valtype); + + } + /* Detect integer changing in width or signedness. + These warnings are only activated with + -Wtraditional-conversion, not with -Wtraditional. */ + else if (warn_traditional_conversion + && INTEGRAL_TYPE_P (type) + && INTEGRAL_TYPE_P (valtype)) + { + tree would_have_been = default_conversion (val); + tree type1 = TREE_TYPE (would_have_been); + + if (val == error_mark_node) + /* VAL could have been of incomplete type. */; + else if (TREE_CODE (type) == ENUMERAL_TYPE + && (TYPE_MAIN_VARIANT (type) + == TYPE_MAIN_VARIANT (valtype))) + /* No warning if function asks for enum + and the actual arg is that enum type. */ + ; + else if (formal_prec != TYPE_PRECISION (type1)) + warning_at (ploc, OPT_Wtraditional_conversion, + "passing argument %d of %qE " + "with different width due to prototype", + argnum, rname); + else if (TYPE_UNSIGNED (type) == TYPE_UNSIGNED (type1)) + ; + /* Don't complain if the formal parameter type + is an enum, because we can't tell now whether + the value was an enum--even the same enum. */ + else if (TREE_CODE (type) == ENUMERAL_TYPE) + ; + else if (TREE_CODE (val) == INTEGER_CST + && int_fits_type_p (val, type)) + /* Change in signedness doesn't matter + if a constant value is unaffected. */ + ; + /* If the value is extended from a narrower + unsigned type, it doesn't matter whether we + pass it as signed or unsigned; the value + certainly is the same either way. */ + else if (TYPE_PRECISION (valtype) < TYPE_PRECISION (type) + && TYPE_UNSIGNED (valtype)) + ; + else if (TYPE_UNSIGNED (type)) + warning_at (ploc, OPT_Wtraditional_conversion, + "passing argument %d of %qE " + "as unsigned due to prototype", + argnum, rname); + else + warning_at (ploc, OPT_Wtraditional_conversion, + "passing argument %d of %qE " + "as signed due to prototype", + argnum, rname); + } + } + + /* Possibly restore an EXCESS_PRECISION_EXPR for the + sake of better warnings from convert_and_check. */ + if (excess_precision) + val = build1 (EXCESS_PRECISION_EXPR, valtype, val); + + parmval = convert_for_assignment (ploc, ploc, type, + val, origtype, ic_argpass, + npc, fundecl, function, + parmnum + 1, warnopt); + + if (targetm.calls.promote_prototypes (fundecl ? TREE_TYPE (fundecl) : 0) + && INTEGRAL_TYPE_P (type) + && (TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node))) + parmval = default_conversion (parmval); + } + + return parmval; +} + /* Convert the argument expressions in the vector VALUES to the types in the list TYPELIST. @@ -3209,7 +3392,6 @@ convert_arguments (location_t loc, vec<location_t> arg_loc, tree typelist, vec<tree, va_gc> *values, vec<tree, va_gc> *origtypes, tree function, tree fundecl) { - tree typetail, val; unsigned int parmnum; bool error_args = false; const bool type_generic = fundecl @@ -3227,50 +3409,69 @@ convert_arguments (location_t loc, vec<location_t> arg_loc, tree typelist, /* Handle an ObjC selector specially for diagnostics. */ selector = objc_message_selector (); + /* For a call to a built-in function declared without a prototype, + set to the built-in function's argument list. */ + tree builtin_typelist = NULL_TREE; + /* For type-generic built-in functions, determine whether excess precision should be removed (classification) or not (comparison). */ - if (type_generic + if (fundecl && fndecl_built_in_p (fundecl, BUILT_IN_NORMAL)) { - switch (DECL_FUNCTION_CODE (fundecl)) + built_in_function code = DECL_FUNCTION_CODE (fundecl); + if (C_DECL_BUILTIN_PROTOTYPE (fundecl)) { - case BUILT_IN_ISFINITE: - case BUILT_IN_ISINF: - case BUILT_IN_ISINF_SIGN: - case BUILT_IN_ISNAN: - case BUILT_IN_ISNORMAL: - case BUILT_IN_FPCLASSIFY: - type_generic_remove_excess_precision = true; - break; + if (tree bdecl = builtin_decl_implicit (code)) + builtin_typelist = TYPE_ARG_TYPES (TREE_TYPE (bdecl)); + } - case BUILT_IN_ADD_OVERFLOW_P: - case BUILT_IN_SUB_OVERFLOW_P: - case BUILT_IN_MUL_OVERFLOW_P: - /* The last argument of these type-generic builtins - should not be promoted. */ - type_generic_overflow_p = true; - break; + /* For type-generic built-in functions, determine whether excess + precision should be removed (classification) or not + (comparison). */ + if (type_generic) + switch (code) + { + case BUILT_IN_ISFINITE: + case BUILT_IN_ISINF: + case BUILT_IN_ISINF_SIGN: + case BUILT_IN_ISNAN: + case BUILT_IN_ISNORMAL: + case BUILT_IN_FPCLASSIFY: + type_generic_remove_excess_precision = true; + break; - default: - break; - } + case BUILT_IN_ADD_OVERFLOW_P: + case BUILT_IN_SUB_OVERFLOW_P: + case BUILT_IN_MUL_OVERFLOW_P: + /* The last argument of these type-generic builtins + should not be promoted. */ + type_generic_overflow_p = true; + break; + + default: + break; + } } /* Scan the given expressions and types, producing individual converted arguments. */ - for (typetail = typelist, parmnum = 0; + tree typetail, builtin_typetail, val; + for (typetail = typelist, + builtin_typetail = builtin_typelist, + parmnum = 0; values && values->iterate (parmnum, &val); ++parmnum) { - tree type = typetail ? TREE_VALUE (typetail) : 0; + tree type = typetail ? TREE_VALUE (typetail) : NULL_TREE; + tree builtin_type = (builtin_typetail + ? TREE_VALUE (builtin_typetail) : NULL_TREE); tree valtype = TREE_TYPE (val); tree rname = function; int argnum = parmnum + 1; const char *invalid_func_diag; bool excess_precision = false; - bool npc; tree parmval; /* Some __atomic_* builtins have additional hidden argument at position 0. */ @@ -3289,13 +3490,25 @@ convert_arguments (location_t loc, vec<location_t> arg_loc, tree typelist, return error_args ? -1 : (int) parmnum; } + if (builtin_type == void_type_node) + { + warning_at (loc, OPT_Wbuiltin_declaration_mismatch, + "too many arguments to built-in function %qE " + "expecting %d", + function, parmnum); + + inform_declaration (fundecl); + builtin_typetail = NULL_TREE; + } + if (selector && argnum > 2) { rname = selector; argnum -= 2; } - npc = null_pointer_constant_p (val); + /* Determine if VAL is a null pointer constant before folding it. */ + bool npc = null_pointer_constant_p (val); /* If there is excess precision and a prototype, convert once to the required type rather than converting via the semantic @@ -3340,172 +3553,10 @@ convert_arguments (location_t loc, vec<location_t> arg_loc, tree typelist, if (type != NULL_TREE) { - /* Formal parm type is specified by a function prototype. */ - - if (type == error_mark_node || !COMPLETE_TYPE_P (type)) - { - error_at (ploc, "type of formal parameter %d is incomplete", - parmnum + 1); - parmval = val; - } - else - { - tree origtype; - - /* Optionally warn about conversions that - differ from the default conversions. */ - if (warn_traditional_conversion || warn_traditional) - { - unsigned int formal_prec = TYPE_PRECISION (type); - - if (INTEGRAL_TYPE_P (type) - && TREE_CODE (valtype) == REAL_TYPE) - warning_at (ploc, OPT_Wtraditional_conversion, - "passing argument %d of %qE as integer rather " - "than floating due to prototype", - argnum, rname); - if (INTEGRAL_TYPE_P (type) - && TREE_CODE (valtype) == COMPLEX_TYPE) - warning_at (ploc, OPT_Wtraditional_conversion, - "passing argument %d of %qE as integer rather " - "than complex due to prototype", - argnum, rname); - else if (TREE_CODE (type) == COMPLEX_TYPE - && TREE_CODE (valtype) == REAL_TYPE) - warning_at (ploc, OPT_Wtraditional_conversion, - "passing argument %d of %qE as complex rather " - "than floating due to prototype", - argnum, rname); - else if (TREE_CODE (type) == REAL_TYPE - && INTEGRAL_TYPE_P (valtype)) - warning_at (ploc, OPT_Wtraditional_conversion, - "passing argument %d of %qE as floating rather " - "than integer due to prototype", - argnum, rname); - else if (TREE_CODE (type) == COMPLEX_TYPE - && INTEGRAL_TYPE_P (valtype)) - warning_at (ploc, OPT_Wtraditional_conversion, - "passing argument %d of %qE as complex rather " - "than integer due to prototype", - argnum, rname); - else if (TREE_CODE (type) == REAL_TYPE - && TREE_CODE (valtype) == COMPLEX_TYPE) - warning_at (ploc, OPT_Wtraditional_conversion, - "passing argument %d of %qE as floating rather " - "than complex due to prototype", - argnum, rname); - /* ??? At some point, messages should be written about - conversions between complex types, but that's too messy - to do now. */ - else if (TREE_CODE (type) == REAL_TYPE - && TREE_CODE (valtype) == REAL_TYPE) - { - /* Warn if any argument is passed as `float', - since without a prototype it would be `double'. */ - if (formal_prec == TYPE_PRECISION (float_type_node) - && type != dfloat32_type_node) - warning_at (ploc, 0, - "passing argument %d of %qE as %<float%> " - "rather than %<double%> due to prototype", - argnum, rname); - - /* Warn if mismatch between argument and prototype - for decimal float types. Warn of conversions with - binary float types and of precision narrowing due to - prototype. */ - else if (type != valtype - && (type == dfloat32_type_node - || type == dfloat64_type_node - || type == dfloat128_type_node - || valtype == dfloat32_type_node - || valtype == dfloat64_type_node - || valtype == dfloat128_type_node) - && (formal_prec - <= TYPE_PRECISION (valtype) - || (type == dfloat128_type_node - && (valtype - != dfloat64_type_node - && (valtype - != dfloat32_type_node))) - || (type == dfloat64_type_node - && (valtype - != dfloat32_type_node)))) - warning_at (ploc, 0, - "passing argument %d of %qE as %qT " - "rather than %qT due to prototype", - argnum, rname, type, valtype); - - } - /* Detect integer changing in width or signedness. - These warnings are only activated with - -Wtraditional-conversion, not with -Wtraditional. */ - else if (warn_traditional_conversion - && INTEGRAL_TYPE_P (type) - && INTEGRAL_TYPE_P (valtype)) - { - tree would_have_been = default_conversion (val); - tree type1 = TREE_TYPE (would_have_been); - - if (val == error_mark_node) - /* VAL could have been of incomplete type. */; - else if (TREE_CODE (type) == ENUMERAL_TYPE - && (TYPE_MAIN_VARIANT (type) - == TYPE_MAIN_VARIANT (valtype))) - /* No warning if function asks for enum - and the actual arg is that enum type. */ - ; - else if (formal_prec != TYPE_PRECISION (type1)) - warning_at (ploc, OPT_Wtraditional_conversion, - "passing argument %d of %qE " - "with different width due to prototype", - argnum, rname); - else if (TYPE_UNSIGNED (type) == TYPE_UNSIGNED (type1)) - ; - /* Don't complain if the formal parameter type - is an enum, because we can't tell now whether - the value was an enum--even the same enum. */ - else if (TREE_CODE (type) == ENUMERAL_TYPE) - ; - else if (TREE_CODE (val) == INTEGER_CST - && int_fits_type_p (val, type)) - /* Change in signedness doesn't matter - if a constant value is unaffected. */ - ; - /* If the value is extended from a narrower - unsigned type, it doesn't matter whether we - pass it as signed or unsigned; the value - certainly is the same either way. */ - else if (TYPE_PRECISION (valtype) < TYPE_PRECISION (type) - && TYPE_UNSIGNED (valtype)) - ; - else if (TYPE_UNSIGNED (type)) - warning_at (ploc, OPT_Wtraditional_conversion, - "passing argument %d of %qE " - "as unsigned due to prototype", - argnum, rname); - else - warning_at (ploc, OPT_Wtraditional_conversion, - "passing argument %d of %qE " - "as signed due to prototype", - argnum, rname); - } - } - - /* Possibly restore an EXCESS_PRECISION_EXPR for the - sake of better warnings from convert_and_check. */ - if (excess_precision) - val = build1 (EXCESS_PRECISION_EXPR, valtype, val); - origtype = (!origtypes) ? NULL_TREE : (*origtypes)[parmnum]; - parmval = convert_for_assignment (loc, ploc, type, - val, origtype, ic_argpass, - npc, fundecl, function, - parmnum + 1); - - if (targetm.calls.promote_prototypes (fundecl ? TREE_TYPE (fundecl) : 0) - && INTEGRAL_TYPE_P (type) - && (TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node))) - parmval = default_conversion (parmval); - } + tree origtype = (!origtypes) ? NULL_TREE : (*origtypes)[parmnum]; + parmval = convert_argument (ploc, function, fundecl, type, origtype, + val, npc, rname, parmnum, argnum, + excess_precision, 0); } else if (promote_float_arg) { @@ -3547,8 +3598,24 @@ convert_arguments (location_t loc, vec<location_t> arg_loc, tree typelist, if (parmval == error_mark_node) error_args = true; + if (!type && builtin_type && TREE_CODE (builtin_type) != VOID_TYPE) + { + /* For a call to a built-in function declared without a prototype, + perform the conversions from the argument to the expected type + but issue warnings rather than errors for any mismatches. + Ignore the converted argument and use the PARMVAL obtained + above by applying default conversions instead. */ + tree origtype = (!origtypes) ? NULL_TREE : (*origtypes)[parmnum]; + convert_argument (ploc, function, fundecl, builtin_type, origtype, + val, npc, rname, parmnum, argnum, excess_precision, + OPT_Wbuiltin_declaration_mismatch); + } + if (typetail) typetail = TREE_CHAIN (typetail); + + if (builtin_typetail) + builtin_typetail = TREE_CHAIN (builtin_typetail); } gcc_assert (parmnum == vec_safe_length (values)); @@ -3560,6 +3627,18 @@ convert_arguments (location_t loc, vec<location_t> arg_loc, tree typelist, return -1; } + if (builtin_typetail && TREE_VALUE (builtin_typetail) != void_type_node) + { + unsigned nargs = parmnum; + for (tree t = builtin_typetail; t; t = TREE_CHAIN (t)) + ++nargs; + + warning_at (loc, OPT_Wbuiltin_declaration_mismatch, + "too few arguments to built-in function %qE expecting %u", + function, nargs - 1); + inform_declaration (fundecl); + } + return error_args ? -1 : (int) parmnum; } @@ -4922,6 +5001,40 @@ ep_convert_and_check (location_t loc, tree type, tree expr, return convert (type, expr); } +/* If EXPR refers to a built-in declared without a prototype returns + the actual type of the built-in and, if non-null, set *BLTIN to + a pointer to the built-in. Otherwise return the type of EXPR + and clear *BLTIN if non-null. */ + +static tree +type_or_builtin_type (tree expr, tree *bltin = NULL) +{ + tree dummy; + if (!bltin) + bltin = &dummy; + + *bltin = NULL_TREE; + + tree type = TREE_TYPE (expr); + if (TREE_CODE (expr) != ADDR_EXPR) + return type; + + tree oper = TREE_OPERAND (expr, 0); + if (!DECL_P (oper) + || TREE_CODE (oper) != FUNCTION_DECL + || !fndecl_built_in_p (oper, BUILT_IN_NORMAL)) + return type; + + built_in_function code = DECL_FUNCTION_CODE (oper); + if (!C_DECL_BUILTIN_PROTOTYPE (oper)) + return type; + + if ((*bltin = builtin_decl_implicit (code))) + type = build_pointer_type (TREE_TYPE (*bltin)); + + return type; +} + /* Build and return a conditional expression IFEXP ? OP1 : OP2. If IFEXP_BCP then the condition is a call to __builtin_constant_p, and if folded to an integer constant then the unselected half may @@ -4966,9 +5079,11 @@ build_conditional_expr (location_t colon_loc, tree ifexp, bool ifexp_bcp, || TREE_CODE (TREE_TYPE (op2)) == ERROR_MARK) return error_mark_node; - type1 = TREE_TYPE (op1); + tree bltin1 = NULL_TREE; + tree bltin2 = NULL_TREE; + type1 = type_or_builtin_type (op1, &bltin1); code1 = TREE_CODE (type1); - type2 = TREE_TYPE (op2); + type2 = type_or_builtin_type (op2, &bltin2); code2 = TREE_CODE (type2); if (code1 == POINTER_TYPE && reject_gcc_builtin (op1)) @@ -5206,9 +5321,14 @@ build_conditional_expr (location_t colon_loc, tree ifexp, bool ifexp_bcp, else { int qual = ENCODE_QUAL_ADDR_SPACE (as_common); - - pedwarn (colon_loc, 0, - "pointer type mismatch in conditional expression"); + if (bltin1 && bltin2) + warning_at (colon_loc, OPT_Wincompatible_pointer_types, + "pointer type mismatch between %qT and %qT " + "of %qD and %qD in conditional expression", + type1, type2, bltin1, bltin2); + else + pedwarn (colon_loc, 0, + "pointer type mismatch in conditional expression"); result_type = build_pointer_type (build_qualified_type (void_type_node, qual)); } @@ -6322,6 +6442,46 @@ inform_for_arg (tree fundecl, location_t ploc, int parmnum, expected_type, actual_type); } +/* Issue a warning when an argument of ARGTYPE is passed to a built-in + function FUNDECL declared without prototype to parameter PARMNUM of + PARMTYPE when ARGTYPE does not promote to PARMTYPE. */ + +static void +maybe_warn_builtin_no_proto_arg (location_t loc, tree fundecl, int parmnum, + tree parmtype, tree argtype) +{ + tree_code parmcode = TREE_CODE (parmtype); + tree_code argcode = TREE_CODE (argtype); + tree promoted = c_type_promotes_to (argtype); + + /* Avoid warning for enum arguments that promote to an integer type + of the same size/mode. */ + if (parmcode == INTEGER_TYPE + && argcode == ENUMERAL_TYPE + && TYPE_MODE (parmtype) == TYPE_MODE (argtype)) + return; + + if (parmcode == argcode + && TYPE_MAIN_VARIANT (parmtype) == TYPE_MAIN_VARIANT (promoted)) + return; + + /* This diagnoses even signed/unsigned mismatches. Those might be + safe in many cases but GCC may emit suboptimal code for them so + warning on those cases drives efficiency improvements. */ + if (warning_at (loc, OPT_Wbuiltin_declaration_mismatch, + TYPE_MAIN_VARIANT (promoted) == argtype + ? G_("%qD argument %d type is %qT where %qT is expected " + "in a call to built-in function declared without " + "prototype") + : G_("%qD argument %d promotes to %qT where %qT is expected " + "in a call to built-in function declared without " + "prototype"), + fundecl, parmnum, promoted, parmtype)) + inform (DECL_SOURCE_LOCATION (fundecl), + "built-in %qD declared here", + fundecl); +} + /* Convert value RHS to type TYPE as preparation for an assignment to an lvalue of type TYPE. If ORIGTYPE is not NULL_TREE, it is the original type of RHS; this differs from TREE_TYPE (RHS) for enum @@ -6346,13 +6506,16 @@ inform_for_arg (tree fundecl, location_t ploc, int parmnum, ^ FUNCTION is a tree for the function being called. - PARMNUM is the number of the argument, for printing in error messages. */ + PARMNUM is the number of the argument, for printing in error messages. + WARNOPT may be set to a warning option to issue the corresponding warning + rather than an error for invalid conversions. Used for calls to built-in + functions declared without a prototype. */ static tree convert_for_assignment (location_t location, location_t expr_loc, tree type, tree rhs, tree origtype, enum impl_conv errtype, bool null_pointer_constant, tree fundecl, - tree function, int parmnum) + tree function, int parmnum, int warnopt /* = 0 */) { enum tree_code codel = TREE_CODE (type); tree orig_rhs = rhs; @@ -6550,7 +6713,11 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type, an unprototyped function, it is compile-time undefined; making it a constraint in that case was rejected in DR#252. */ - error_at (location, "void value not ignored as it ought to be"); + const char msg[] = "void value not ignored as it ought to be"; + if (warnopt) + warning_at (location, warnopt, msg); + else + error_at (location, msg); return error_mark_node; } rhs = require_complete_type (location, rhs); @@ -6566,7 +6733,11 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type, { if (!lvalue_p (rhs)) { - error_at (location, "cannot pass rvalue to reference parameter"); + const char msg[] = "cannot pass rvalue to reference parameter"; + if (warnopt) + warning_at (location, warnopt, msg); + else + error_at (location, msg); return error_mark_node; } if (!c_mark_addressable (rhs)) @@ -6578,7 +6749,7 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type, build_pointer_type (TREE_TYPE (type)), rhs, origtype, errtype, null_pointer_constant, fundecl, function, - parmnum); + parmnum, warnopt); if (rhs == error_mark_node) return error_mark_node; @@ -6600,15 +6771,18 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type, || coder == ENUMERAL_TYPE || coder == COMPLEX_TYPE || coder == BOOLEAN_TYPE)) { - tree ret; + if (warnopt && errtype == ic_argpass) + maybe_warn_builtin_no_proto_arg (expr_loc, fundecl, parmnum, type, + rhstype); + bool save = in_late_binary_op; if (codel == BOOLEAN_TYPE || codel == COMPLEX_TYPE || (coder == REAL_TYPE && (codel == INTEGER_TYPE || codel == ENUMERAL_TYPE) && sanitize_flags_p (SANITIZE_FLOAT_CAST))) in_late_binary_op = true; - ret = convert_and_check (expr_loc != UNKNOWN_LOCATION - ? expr_loc : location, type, orig_rhs); + tree ret = convert_and_check (expr_loc != UNKNOWN_LOCATION + ? expr_loc : location, type, orig_rhs); in_late_binary_op = save; return ret; } @@ -6742,6 +6916,12 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type, else if ((codel == POINTER_TYPE || codel == REFERENCE_TYPE) && (coder == codel)) { + /* If RHS refers to a built-in declared without a prototype + BLTIN is the declaration of the built-in with a prototype + and RHSTYPE is set to the actual type of the built-in. */ + tree bltin; + rhstype = type_or_builtin_type (rhs, &bltin); + tree ttl = TREE_TYPE (type); tree ttr = TREE_TYPE (rhstype); tree mvl = ttl; @@ -6805,21 +6985,45 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type, switch (errtype) { case ic_argpass: - error_at (expr_loc, "passing argument %d of %qE from pointer to " - "non-enclosed address space", parmnum, rname); + { + const char msg[] = G_("passing argument %d of %qE from " + "pointer to non-enclosed address space"); + if (warnopt) + warning_at (expr_loc, warnopt, msg, parmnum, rname); + else + error_at (expr_loc, msg, parmnum, rname); break; + } case ic_assign: - error_at (location, "assignment from pointer to " - "non-enclosed address space"); - break; + { + const char msg[] = G_("assignment from pointer to " + "non-enclosed address space"); + if (warnopt) + warning_at (location, warnopt, msg); + else + error_at (location, msg); + break; + } case ic_init: - error_at (location, "initialization from pointer to " - "non-enclosed address space"); - break; + { + const char msg[] = G_("initialization from pointer to " + "non-enclosed address space"); + if (warnopt) + warning_at (location, warnopt, msg); + else + error_at (location, msg); + break; + } case ic_return: - error_at (location, "return from pointer to " - "non-enclosed address space"); - break; + { + const char msg[] = G_("return from pointer to " + "non-enclosed address space"); + if (warnopt) + warning_at (location, warnopt, msg); + else + error_at (location, msg); + break; + } default: gcc_unreachable (); } @@ -7017,19 +7221,38 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type, } break; case ic_assign: - pedwarn (location, OPT_Wincompatible_pointer_types, - "assignment to %qT from incompatible pointer type %qT", - type, rhstype); + if (bltin) + pedwarn (location, OPT_Wincompatible_pointer_types, + "assignment to %qT from pointer to " + "%qD with incompatible type %qT", + type, bltin, rhstype); + else + pedwarn (location, OPT_Wincompatible_pointer_types, + "assignment to %qT from incompatible pointer type %qT", + type, rhstype); break; case ic_init: - pedwarn_init (location, OPT_Wincompatible_pointer_types, - "initialization of %qT from incompatible pointer " - "type %qT", type, rhstype); + if (bltin) + pedwarn_init (location, OPT_Wincompatible_pointer_types, + "initialization of %qT from pointer to " + "%qD with incompatible type %qT", + type, bltin, rhstype); + else + pedwarn_init (location, OPT_Wincompatible_pointer_types, + "initialization of %qT from incompatible " + "pointer type %qT", + type, rhstype); break; case ic_return: - pedwarn (location, OPT_Wincompatible_pointer_types, - "returning %qT from a function with incompatible " - "return type %qT", rhstype, type); + if (bltin) + pedwarn (location, OPT_Wincompatible_pointer_types, + "returning pointer to %qD of type %qT from " + "a function with incompatible type %qT", + bltin, rhstype, type); + else + pedwarn (location, OPT_Wincompatible_pointer_types, + "returning %qT from a function with incompatible " + "return type %qT", rhstype, type); break; default: gcc_unreachable (); @@ -7042,7 +7265,11 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type, { /* ??? This should not be an error when inlining calls to unprototyped functions. */ - error_at (location, "invalid use of non-lvalue array"); + const char msg[] = "invalid use of non-lvalue array"; + if (warnopt) + warning_at (location, warnopt, msg); + else + error_at (location, msg); return error_mark_node; } else if (codel == POINTER_TYPE && coder == INTEGER_TYPE) @@ -7138,25 +7365,44 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type, auto_diagnostic_group d; range_label_for_type_mismatch rhs_label (rhstype, type); gcc_rich_location richloc (expr_loc, &rhs_label); - error_at (&richloc, "incompatible type for argument %d of %qE", parmnum, - rname); + const char msg[] = G_("incompatible type for argument %d of %qE"); + if (warnopt) + warning_at (expr_loc, warnopt, msg, parmnum, rname); + else + error_at (&richloc, msg, parmnum, rname); inform_for_arg (fundecl, expr_loc, parmnum, type, rhstype); } break; case ic_assign: - error_at (location, "incompatible types when assigning to type %qT from " - "type %qT", type, rhstype); - break; + { + const char msg[] + = G_("incompatible types when assigning to type %qT from type %qT"); + if (warnopt) + warning_at (expr_loc, 0, msg, type, rhstype); + else + error_at (expr_loc, msg, type, rhstype); + break; + } case ic_init: - error_at (location, - "incompatible types when initializing type %qT using type %qT", - type, rhstype); - break; + { + const char msg[] + = G_("incompatible types when initializing type %qT using type %qT"); + if (warnopt) + warning_at (location, 0, msg, type, rhstype); + else + error_at (location, msg, type, rhstype); + break; + } case ic_return: - error_at (location, - "incompatible types when returning type %qT but %qT was " - "expected", rhstype, type); - break; + { + const char msg[] + = G_("incompatible types when returning type %qT but %qT was expected"); + if (warnopt) + warning_at (location, 0, msg, rhstype, type); + else + error_at (location, msg, rhstype, type); + break; + } default: gcc_unreachable (); } |