The goal of this patch is to improve the location info for the "incomplete type" error. Turned out this is isn't as trivial as it should be: 1) c_incomplete_type_error is a target hook, so I had to add the location parameter to the other hooks, too, 2) I had to add the location parameter to size_in_bytes, too. I renamed it to size_in_bytes_loc and defined a macro so I don't have to change all the callsites, 3) for the C++ FE I used a macro so that I don't have to change all the cxx_incomplete_type_error calls now, 4) what with using EXPR_LOC_OR_LOC (exp, input_location), we sometimes still produce imprecise location :(.
Bootstrapped/regtested on x86_64-linux, ok for trunk? 2016-04-28 Marek Polacek <pola...@redhat.com> PR c/70756 * c-common.c (pointer_int_sum): Call size_in_bytes_loc instead of size_in_bytes and pass LOC to it. * c-decl.c (build_compound_literal): Pass LOC down to c_incomplete_type_error. * c-tree.h (require_complete_type): Adjust declaration. (c_incomplete_type_error): Likewise. * c-typeck.c (require_complete_type): Add location parameter, pass it down to c_incomplete_type_error. (c_incomplete_type_error): Add location parameter, pass it down to error_at. (build_component_ref): Pass location down to c_incomplete_type_error. (default_conversion): Pass location down to require_complete_type. (build_array_ref): Likewise. (build_function_call_vec): Likewise. (convert_arguments): Likewise. (build_unary_op): Likewise. (build_c_cast): Likewise. (build_modify_expr): Likewise. (convert_for_assignment): Likewise. (c_finish_omp_clauses): Likewise. * cp-tree.h (cxx_incomplete_type_error): Adjust declaration. * typeck2.c (cxx_incomplete_type_error): Add location parameter. * langhooks-def.h (lhd_incomplete_type_error): Adjust declaration. * langhooks.c (lhd_incomplete_type_error): Add location parameter. * langhooks.h (incomplete_type_error): Likewise. * tree.c (size_in_bytes_loc): Renamed from size_in_bytes. Add location parameter, pass it down to incomplete_type_error. * tree.h (size_in_bytes): Define macro. (size_in_bytes_loc): Renamed from size_in_bytes. * gcc.dg/pr70756.c: New test. diff --git gcc/c-family/c-common.c gcc/c-family/c-common.c index c086dee..decbe8b 100644 --- gcc/c-family/c-common.c +++ gcc/c-family/c-common.c @@ -4270,7 +4270,7 @@ pointer_int_sum (location_t loc, enum tree_code resultcode, size_exp = integer_one_node; } else - size_exp = size_in_bytes (TREE_TYPE (result_type)); + size_exp = size_in_bytes_loc (loc, TREE_TYPE (result_type)); /* We are manipulating pointer values, so we don't need to warn about relying on undefined signed overflow. We disable the diff --git gcc/c/c-decl.c gcc/c/c-decl.c index 16e4250..d714ec2 100644 --- gcc/c/c-decl.c +++ gcc/c/c-decl.c @@ -5112,7 +5112,7 @@ build_compound_literal (location_t loc, tree type, tree init, bool non_const) if (type == error_mark_node || !COMPLETE_TYPE_P (type)) { - c_incomplete_type_error (NULL_TREE, type); + c_incomplete_type_error (loc, NULL_TREE, type); return error_mark_node; } diff --git gcc/c/c-tree.h gcc/c/c-tree.h index 4633182..d3a6c4c 100644 --- gcc/c/c-tree.h +++ gcc/c/c-tree.h @@ -588,13 +588,13 @@ extern tree c_last_sizeof_arg; extern struct c_switch *c_switch_stack; extern tree c_objc_common_truthvalue_conversion (location_t, tree); -extern tree require_complete_type (tree); +extern tree require_complete_type (location_t, tree); extern int same_translation_unit_p (const_tree, const_tree); extern int comptypes (tree, tree); extern int comptypes_check_different_types (tree, tree, bool *); extern bool c_vla_type_p (const_tree); extern bool c_mark_addressable (tree); -extern void c_incomplete_type_error (const_tree, const_tree); +extern void c_incomplete_type_error (location_t, const_tree, const_tree); extern tree c_type_promotes_to (tree); extern struct c_expr default_function_array_conversion (location_t, struct c_expr); diff --git gcc/c/c-typeck.c gcc/c/c-typeck.c index 58c2139..32fd504 100644 --- gcc/c/c-typeck.c +++ gcc/c/c-typeck.c @@ -183,11 +183,12 @@ struct tagged_tu_seen_cache { static const struct tagged_tu_seen_cache * tagged_tu_seen_base; static void free_all_tagged_tu_seen_up_to (const struct tagged_tu_seen_cache *); -/* Do `exp = require_complete_type (exp);' to make sure exp - does not have an incomplete type. (That includes void types.) */ +/* Do `exp = require_complete_type (loc, exp);' to make sure exp + does not have an incomplete type. (That includes void types.) + LOC is the location of the use. */ tree -require_complete_type (tree value) +require_complete_type (location_t loc, tree value) { tree type = TREE_TYPE (value); @@ -198,23 +199,24 @@ require_complete_type (tree value) if (COMPLETE_TYPE_P (type)) return value; - c_incomplete_type_error (value, type); + c_incomplete_type_error (loc, value, type); return error_mark_node; } /* Print an error message for invalid use of an incomplete type. VALUE is the expression that was used (or 0 if that isn't known) - and TYPE is the type that was invalid. */ + and TYPE is the type that was invalid. LOC is the location for + the error. */ void -c_incomplete_type_error (const_tree value, const_tree type) +c_incomplete_type_error (location_t loc, const_tree value, const_tree type) { /* Avoid duplicate error message. */ if (TREE_CODE (type) == ERROR_MARK) return; if (value != 0 && (VAR_P (value) || TREE_CODE (value) == PARM_DECL)) - error ("%qD has an incomplete type %qT", value, type); + error_at (loc, "%qD has an incomplete type %qT", value, type); else { retry: @@ -228,7 +230,7 @@ c_incomplete_type_error (const_tree value, const_tree type) break; case VOID_TYPE: - error ("invalid use of void expression"); + error_at (loc, "invalid use of void expression"); return; case ARRAY_TYPE: @@ -236,13 +238,13 @@ c_incomplete_type_error (const_tree value, const_tree type) { if (TYPE_MAX_VALUE (TYPE_DOMAIN (type)) == NULL) { - error ("invalid use of flexible array member"); + error_at (loc, "invalid use of flexible array member"); return; } type = TREE_TYPE (type); goto retry; } - error ("invalid use of array with unspecified bounds"); + error_at (loc, "invalid use of array with unspecified bounds"); return; default: @@ -250,10 +252,10 @@ c_incomplete_type_error (const_tree value, const_tree type) } if (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE) - error ("invalid use of undefined type %qT", type); + error_at (loc, "invalid use of undefined type %qT", type); else /* If this type has a typedef-name, the TYPE_NAME is a TYPE_DECL. */ - error ("invalid use of incomplete typedef %qT", type); + error_at (loc, "invalid use of incomplete typedef %qT", type); } } @@ -2117,7 +2119,7 @@ default_conversion (tree exp) return error_mark_node; } - exp = require_complete_type (exp); + exp = require_complete_type (EXPR_LOC_OR_LOC (exp, input_location), exp); if (exp == error_mark_node) return error_mark_node; @@ -2334,7 +2336,7 @@ build_component_ref (location_t loc, tree datum, tree component) { if (!COMPLETE_TYPE_P (type)) { - c_incomplete_type_error (NULL_TREE, type); + c_incomplete_type_error (loc, NULL_TREE, type); return error_mark_node; } @@ -2642,7 +2644,7 @@ build_array_ref (location_t loc, tree array, tree index) in an inline function. Hope it doesn't break something else. */ | TREE_THIS_VOLATILE (array)); - ret = require_complete_type (rval); + ret = require_complete_type (loc, rval); protected_set_expr_location (ret, loc); if (non_lvalue) ret = non_lvalue_loc (loc, ret); @@ -3087,7 +3089,7 @@ build_function_call_vec (location_t loc, vec<location_t> arg_loc, "function with qualified void return type called"); return result; } - return require_complete_type (result); + return require_complete_type (loc, result); } /* Like build_function_call_vec, but call also resolve_overloaded_builtin. */ @@ -3238,7 +3240,7 @@ convert_arguments (location_t loc, vec<location_t> arg_loc, tree typelist, val = c_fully_fold (val, false, NULL); STRIP_TYPE_NOPS (val); - val = require_complete_type (val); + val = require_complete_type (ploc, val); if (type != 0) { @@ -4046,7 +4048,7 @@ build_unary_op (location_t location, arg = remove_c_maybe_const_expr (arg); if (code != ADDR_EXPR) - arg = require_complete_type (arg); + arg = require_complete_type (location, arg); typecode = TREE_CODE (TREE_TYPE (arg)); if (typecode == ERROR_MARK) @@ -5267,7 +5269,7 @@ build_c_cast (location_t loc, tree type, tree expr) if (!VOID_TYPE_P (type)) { - value = require_complete_type (value); + value = require_complete_type (loc, value); if (value == error_mark_node) return error_mark_node; } @@ -5537,7 +5539,7 @@ build_modify_expr (location_t location, tree lhs, tree lhs_origtype, bool is_atomic_op; /* Types that aren't fully specified cannot be used in assignments. */ - lhs = require_complete_type (lhs); + lhs = require_complete_type (location, lhs); /* Avoid duplicate error messages from operands that had errors. */ if (TREE_CODE (lhs) == ERROR_MARK || TREE_CODE (rhs) == ERROR_MARK) @@ -6132,7 +6134,7 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type, error_at (location, "void value not ignored as it ought to be"); return error_mark_node; } - rhs = require_complete_type (rhs); + rhs = require_complete_type (location, rhs); if (rhs == error_mark_node) return error_mark_node; @@ -12548,7 +12550,7 @@ c_finish_omp_clauses (tree clauses, bool is_omp, bool declare_simd, t = OMP_CLAUSE_DECL (c); } - t = require_complete_type (t); + t = require_complete_type (OMP_CLAUSE_LOCATION (c), t); if (t == error_mark_node) { remove = true; @@ -13359,7 +13361,7 @@ c_finish_omp_clauses (tree clauses, bool is_omp, bool declare_simd, if (need_complete) { - t = require_complete_type (t); + t = require_complete_type (OMP_CLAUSE_LOCATION (c), t); if (t == error_mark_node) remove = true; } diff --git gcc/cp/cp-tree.h gcc/cp/cp-tree.h index 4c548c9..2656edd 100644 --- gcc/cp/cp-tree.h +++ gcc/cp/cp-tree.h @@ -6726,7 +6726,8 @@ extern tree finish_binary_fold_expr (tree, tree, int); extern void require_complete_eh_spec_types (tree, tree); extern void cxx_incomplete_type_diagnostic (const_tree, const_tree, diagnostic_t); #undef cxx_incomplete_type_error -extern void cxx_incomplete_type_error (const_tree, const_tree); +extern void cxx_incomplete_type_error (location_t, const_tree, + const_tree); #define cxx_incomplete_type_error(V,T) \ (cxx_incomplete_type_diagnostic ((V), (T), DK_ERROR)) extern void cxx_incomplete_type_inform (const_tree); diff --git gcc/cp/typeck2.c gcc/cp/typeck2.c index e59ad51..b4d466d 100644 --- gcc/cp/typeck2.c +++ gcc/cp/typeck2.c @@ -574,7 +574,7 @@ cxx_incomplete_type_diagnostic (const_tree value, const_tree type, required by ../tree.c. */ #undef cxx_incomplete_type_error void -cxx_incomplete_type_error (const_tree value, const_tree type) +cxx_incomplete_type_error (location_t, const_tree value, const_tree type) { cxx_incomplete_type_diagnostic (value, type, DK_ERROR); } diff --git gcc/langhooks-def.h gcc/langhooks-def.h index a2566ec..034b3b7 100644 --- gcc/langhooks-def.h +++ gcc/langhooks-def.h @@ -52,7 +52,7 @@ extern void lhd_print_error_function (diagnostic_context *, const char *, struct diagnostic_info *); extern void lhd_set_decl_assembler_name (tree); extern bool lhd_warn_unused_global_decl (const_tree); -extern void lhd_incomplete_type_error (const_tree, const_tree); +extern void lhd_incomplete_type_error (location_t, const_tree, const_tree); extern tree lhd_type_promotes_to (tree); extern void lhd_register_builtin_type (tree, const char *); extern bool lhd_decl_ok_for_sibcall (const_tree); diff --git gcc/langhooks.c gcc/langhooks.c index 7c07175..6444631 100644 --- gcc/langhooks.c +++ gcc/langhooks.c @@ -199,7 +199,8 @@ lhd_register_builtin_type (tree ARG_UNUSED (type), /* Invalid use of an incomplete type. */ void -lhd_incomplete_type_error (const_tree ARG_UNUSED (value), const_tree type) +lhd_incomplete_type_error (location_t ARG_UNUSED (loc), + const_tree ARG_UNUSED (value), const_tree type) { gcc_assert (TREE_CODE (type) == ERROR_MARK); return; diff --git gcc/langhooks.h gcc/langhooks.h index bcfd389..0593424 100644 --- gcc/langhooks.h +++ gcc/langhooks.h @@ -100,8 +100,9 @@ struct lang_hooks_for_types /* This routine is called in tree.c to print an error message for invalid use of an incomplete type. VALUE is the expression that was used (or 0 if that isn't known) and TYPE is the type that was - invalid. */ - void (*incomplete_type_error) (const_tree value, const_tree type); + invalid. LOC is the location of the use. */ + void (*incomplete_type_error) (location_t loc, const_tree value, + const_tree type); /* Called from assign_temp to return the maximum size, if there is one, for a type. */ diff --git gcc/testsuite/gcc.dg/pr70756.c gcc/testsuite/gcc.dg/pr70756.c index e69de29..e867832 100644 --- gcc/testsuite/gcc.dg/pr70756.c +++ gcc/testsuite/gcc.dg/pr70756.c @@ -0,0 +1,23 @@ +/* PR c/70756 */ +/* { dg-do compile } */ +/* { dg-options "" } */ + +enum E e; /* { dg-error "storage size" } */ +int (*A)[]; + +void +fn0 (void) +{ + struct + { + int x; + int y[]; + } s; + 1234 && &s.y + 1; /* { dg-error "16:invalid use of flexible array member" } */ +} + +void +fn1 (void) +{ + 1234, A += 1; /* { dg-error "11:invalid use of array with unspecified bounds" } */ +} diff --git gcc/tree.c gcc/tree.c index 8692182..45c6498 100644 --- gcc/tree.c +++ gcc/tree.c @@ -2944,7 +2944,7 @@ ctor_to_vec (tree ctor) make_unsigned_type). */ tree -size_in_bytes (const_tree type) +size_in_bytes_loc (location_t loc, const_tree type) { tree t; @@ -2956,7 +2956,7 @@ size_in_bytes (const_tree type) if (t == 0) { - lang_hooks.types.incomplete_type_error (NULL_TREE, type); + lang_hooks.types.incomplete_type_error (loc, NULL_TREE, type); return size_zero_node; } diff --git gcc/tree.h gcc/tree.h index 259a2bf..3bf47bf 100644 --- gcc/tree.h +++ gcc/tree.h @@ -4224,7 +4224,9 @@ extern tree type_hash_canon (unsigned int, tree); extern tree convert (tree, tree); extern unsigned int expr_align (const_tree); -extern tree size_in_bytes (const_tree); +#define size_in_bytes(T)\ + size_in_bytes_loc (input_location, T) +extern tree size_in_bytes_loc (location_t, const_tree); extern HOST_WIDE_INT int_size_in_bytes (const_tree); extern HOST_WIDE_INT max_int_size_in_bytes (const_tree); extern tree bit_position (const_tree); Marek