From patchwork Tue Sep 18 10:58:31 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: Add extra location information - PR43486 Date: Tue, 18 Sep 2012 00:58:31 -0000 From: Arnaud Charlet X-Patchwork-Id: 184674 Message-Id: <20120918105831.GA15097@adacore.com> To: gcc-patches@gcc.gnu.org, Jason Merrill , Joseph Myers Cc: Aldy Hernandez , lopezibanez@gmail.com, Arnaud Charlet This is a relatively large patch which tackles the difficult issue of generating more sloc information in front-ends (in particular C and C++ front-ends), so that "static analyzers" based on GCC can get more useful and detailed information. This happens to be related/similar to the need mentioned in PR43486, hence the mention of this PR in the subject line. In my work, as I mentioned a few times in the past, this patch is the first foundation for another patch, which will provide source navigation capabilities in IDEs/editors, by generating source cross reference information based on the C and C++ front-ends (introducing a new switch -fdump-xref). Ideally I'd like to submit both patches. Since this issue is more general, I have split my changes and introduced a new tentative switch called -fextra-slocs, which is the subject of this email. In order to provide more sloc info attached to nodes (and in particular VAR_DECLs), there are basically two possibilities: - the one mentioned in comment 4 of PR43486: << Jason Merrill 2010-03-23 01:51:34 UTC I suppose we could wrap rvalue uses in NOP_EXPR and lvalue uses in VIEW_CONVERT_EXPR. >> I investigated this option, and unfortunately this does not work because of folding occurring all over the place in the C and C++ front-ends, removing these extra EXPRs very early. So I opted for the second approach: - Keep another data structure which will associate extra slocs with some node expressions. The idea is that since you can't associate slocs with VAR_DECLs in an expr, instead we store extra slocs in the containing expression node. For instance, all binary expressions (add ADD, MINUS, ...) will contain two extra slocs: one for the left hand side, and one for the right hand side of the expression. One extra sloc for unary operators, etc... I've used a hash table which associates an array of location_t to some expr nodes, which could then be used by static analysis passes (as done by my patch to implement a -fdump-xref switch). I have attached the various patches, split in directories: - difs.common contains the common parts, introducing the -fextra-slocs switch and the generic data structure/API to store/retrieve extra slocs (in tree.[hc]) - difs.c contains the C front-end specific parts and add lots of source location information, add some extra loc parameters to various parser functions, and store these extra slocs when -fextra-slocs is enabled - difs.cp does the same thing for the C++ front-end and includes testsuite updates which are triggered by this patch, showing some of the immediate benefits/side effects of generating more accurate "primary" slocs in some cases (the case of Class::Method () references, where we now want to reference the sloc pointing to Method rather than Class) OK on principle? Or is the whole approach not suitable/doomed? If OK on principle, I'd appreciate a C, C++ front-end maintainers, and a general maintainer (for the common/general part) to review my patches in more details, and hopefully give their review/OK. Here is the ChangeLog (which will be split into the various directories of course), patches are in attachment. 2012-09-18 Arnaud Charlet * tree.h, tree.c (stabilize_reference): Copy source locations. (sloc_struct, extra_slocs): New. (node_hash, node_eq): Implement extra_slocs hash table. (expr_locations, set_expr_locations, set_expr_location2, duplicate_expr_locations, expr_location_n): New functions. (EXPR_LOCATIONS, SET_EXPR_LOCATION2, SET_EXPR_LOCATIONS): New macros. * common.opt: New switch -fextra-slocs. c/ * c-parser.c (c_parser_expr_list): New parameter locs, num_locs. Set extra locations. (c_parser_attributes): Adjust calls to c_parser_expr_list. (c_parser_statement_after_labels): Adjust calls to c_finish_return with extra expr location. (c_parser_expr_no_commas, c_parser_conditional_expression, c_parser_binary_expression, c_parser_cast_expression, c_parser_unary_expression, c_parser_postfix_expression_after_primary, c_parser_expr_list): Set extra locations. (c_parser_postfix_expression): Remove extra semicolon. (c_parser_objc_keywordexpr): Adjust call to c_parser_expr_list. * c-typeck.c (c_finish_return): New parameter loc_expr. * c-tree.h (c_finish_return): Add location_t parameter. * c-decl.c (finish_function): Update call to c_finish_return. (build_function_declarator): Set ret->id_loc. c-family/ * c-common.c (c_fully_fold_internal): Copy extra locations on new node. objc/ * objc-act.c (objc_synthesize_getter): Update call to c_finish_return. cp/ * parser.c (cp_parser_unary_expression, cp_parser_binary_expression, cp_parser_question_colon_clause, cp_parser_assignment_expression, cp_parser_enumerator_definition): Set extra locations. (cp_parser_parenthesized_expression_list): Ditto. New parameters locs, num_locs. (cp_parser_parse_and_diagnose_invalid_typ): Adjust call to cp_parser_id_location. (cp_parser_userdef_char_literal, cp_parser_userdef_numeric_literal, cp_parser_userdef_string_literal, cp_parser_perform_range_for_lookup, cp_parser_range_for_member_function): Adjust calls to finish_call_expr. (cp_parser_primary_expression, cp_parser_postfix_dot_deref_expression, cp_parser_decltype, cp_parser_type_parameter, cp_parser_template_argument, cp_parser_omp_var_list_no_open): Adjust calls to cp_parser_id_expression. (cp_parser_id_expression, cp_parser_declarator_id): New parameter location_t *. Set location to proper sloc for class::method declarations. (cp_parser_postfix_expression): Set extra locations. Update calls to cp_parser_parenthesized_expression_list, build_new_method_call and finish_call_expr. (cp_parser_postfix_open_square_expression): Add extra locations for array refs (e.g. a[i]). (cp_parser_direct_declarator): Adjust call to cp_parser_declarator_id and adjust sloc of declarator. (cp_parser_new_placement, cp_parser_new_initializer, cp_parser_mem_initializer, cp_parser_initializer, cp_parser_attribute_list, cp_parser_functional_cast): Adjust call to cp_parser_parenthesized_expression_list. * typeck.c (build_c_cast): Ensure extra sloc information is preserved over this function. * call.c (build_over_call): New parameter loc. (build_new_function_call, build_operator_new_call, build_op_call_1, build_new_op_1, convert_like_real): Update call to build_over_call. (build_new_method_call, build_new_method_call_1, finish_call_expr): New parameter loc. (build_special_member_call): Update call to build_new_method_call. (perform_implicit_conversion_flags): Ensure line number information is preserved over this function. * method.c (locate_fn_flags): Update call to build_new_method_call. * class.c (build_self_reference): Update decl location of internal type. * cp-tree.h (build_new_method_call, finish_call_expr): New parameter loc. * pt.c (tsubst_copy_and_build): Update call to build_new_method_call and finish_call_expr. * init.c (build_new_1, build_dtor_call): Ditto. * semantics.c (finish_omp_barrier, finish_omp_flush, finish_omp_taskyield, finish_omp_taskwait): Ditto. (finish_call_expr): Ditto. New parameter loc. (finish_id_expression): Add sloc on decl. testsuite/ * g++.dg/warn/pr26785.C, g++.old-deja/g++.brendan/crash16.C: Update column numbers. * g++.dg/tc1/dr52.C: Update baseline. Index: cp/typeck.c =================================================================== --- cp/typeck.c (revision 190939) +++ cp/typeck.c (working copy) @@ -6645,9 +6645,14 @@ build_const_cast (tree type, tree expr, /* Like cp_build_c_cast, but for the c-common bits. */ tree -build_c_cast (location_t loc ATTRIBUTE_UNUSED, tree type, tree expr) +build_c_cast (location_t loc, tree type, tree expr) { - return cp_build_c_cast (type, expr, tf_warning_or_error); + tree result = cp_build_c_cast (type, expr, tf_warning_or_error); + + if (EXPR_P (result)) + SET_EXPR_LOCATION2 (result, loc); + + return result; } /* Build an expression representing an explicit C-style cast to type Index: cp/call.c =================================================================== --- cp/call.c (revision 190939) +++ cp/call.c (working copy) @@ -146,7 +146,8 @@ static int equal_functions (tree, tree); static int joust (struct z_candidate *, struct z_candidate *, bool, tsubst_flags_t); static int compare_ics (conversion *, conversion *); -static tree build_over_call (struct z_candidate *, int, tsubst_flags_t); +static tree build_over_call (struct z_candidate *, int, tsubst_flags_t, + location_t); static tree build_java_interface_fn_ref (tree, tree); #define convert_like(CONV, EXPR, COMPLAIN) \ convert_like_real ((CONV), (EXPR), NULL_TREE, 0, 0, \ @@ -3905,7 +3906,7 @@ build_new_function_call (tree fn, VEC(tr about peculiar null pointer conversion. */ if (TREE_CODE (fn) == TEMPLATE_ID_EXPR) flags |= LOOKUP_EXPLICIT_TMPL_ARGS; - result = build_over_call (cand, flags, complain); + result = build_over_call (cand, flags, complain, input_location); } /* Free all the conversions we allocated. */ @@ -4024,7 +4025,7 @@ build_operator_new_call (tree fnname, VE *fn = cand->fn; /* Build the CALL_EXPR. */ - return build_over_call (cand, LOOKUP_NORMAL, complain); + return build_over_call (cand, LOOKUP_NORMAL, complain, input_location); } /* Build a new call to operator(). This may change ARGS. */ @@ -4145,7 +4146,8 @@ build_op_call_1 (tree obj, VEC(tree,gc) DECL_NAME here. */ else if (TREE_CODE (cand->fn) == FUNCTION_DECL && DECL_OVERLOADED_OPERATOR_P (cand->fn) == CALL_EXPR) - result = build_over_call (cand, LOOKUP_NORMAL, complain); + result = build_over_call (cand, LOOKUP_NORMAL, complain, + input_location); else { obj = convert_like_with_context (cand->convs[0], obj, cand->fn, -1, @@ -5171,7 +5173,8 @@ build_new_op_1 (location_t loc, enum tre if (resolve_args (arglist, complain) == NULL) result = error_mark_node; else - result = build_over_call (cand, LOOKUP_NORMAL, complain); + result = build_over_call (cand, LOOKUP_NORMAL, complain, + input_location); } else { @@ -5783,7 +5786,7 @@ convert_like_real (conversion *convs, tr for (i = 0; i < cand->num_convs; ++i) cand->convs[i]->user_conv_p = true; - expr = build_over_call (cand, LOOKUP_NORMAL, complain); + expr = build_over_call (cand, LOOKUP_NORMAL, complain, input_location); /* If this is a constructor or a function returning an aggr type, we need to build up a TARGET_EXPR. */ @@ -6402,7 +6405,8 @@ magic_varargs_p (tree fn) bitmask of various LOOKUP_* flags which apply to the call itself. */ static tree -build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain) +build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain, + location_t loc ATTRIBUTE_UNUSED) { tree fn = cand->fn; const VEC(tree,gc) *args = cand->args; @@ -7130,7 +7134,7 @@ build_special_member_call (tree instance ret = build_new_method_call (instance, fns, args, TYPE_BINFO (BINFO_TYPE (binfo)), flags, /*fn=*/NULL, - complain); + complain, input_location); if (allocated != NULL) release_tree_vector (allocated); @@ -7185,12 +7189,12 @@ name_as_c_string (tree name, tree type, /* Build a call to "INSTANCE.FN (ARGS)". If FN_P is non-NULL, it will be set, upon return, to the function called. ARGS may be NULL. - This may change ARGS. */ + This may change ARGS. LOC is the source location of the call. */ static tree build_new_method_call_1 (tree instance, tree fns, VEC(tree,gc) **args, tree conversion_path, int flags, - tree *fn_p, tsubst_flags_t complain) + tree *fn_p, tsubst_flags_t complain, location_t loc) { struct z_candidate *candidates = 0, *cand; tree explicit_targs = NULL_TREE; @@ -7469,7 +7473,7 @@ build_new_method_call_1 (tree instance, if (fn_p) *fn_p = fn; /* Build the actual CALL_EXPR. */ - call = build_over_call (cand, flags, complain); + call = build_over_call (cand, flags, complain, loc); /* In an expression of the form `a->f()' where `f' turns out to be a static member function, `a' is none-the-less evaluated. */ @@ -7534,12 +7538,12 @@ build_new_method_call_1 (tree instance, tree build_new_method_call (tree instance, tree fns, VEC(tree,gc) **args, tree conversion_path, int flags, - tree *fn_p, tsubst_flags_t complain) + tree *fn_p, tsubst_flags_t complain, location_t loc) { tree ret; bool subtime = timevar_cond_start (TV_OVERLOAD); ret = build_new_method_call_1 (instance, fns, args, conversion_path, flags, - fn_p, complain); + fn_p, complain, loc); timevar_cond_stop (TV_OVERLOAD, subtime); return ret; } @@ -8562,6 +8566,7 @@ tree perform_implicit_conversion_flags (tree type, tree expr, tsubst_flags_t complain, int flags) { + tree result = expr; conversion *conv; void *p; location_t loc = EXPR_LOC_OR_HERE (expr); @@ -8605,6 +8610,9 @@ perform_implicit_conversion_flags (tree } else expr = convert_like (conv, expr, complain); + + if (expr != error_mark_node) + duplicate_expr_locations (expr, result); /* Free all the conversions we allocated. */ obstack_free (&conversion_obstack, p); Index: cp/method.c =================================================================== --- cp/method.c (revision 190939) +++ cp/method.c (working copy) @@ -837,7 +837,8 @@ locate_fn_flags (tree type, tree name, t } fns = lookup_fnfields (binfo, name, 0); - rval = build_new_method_call (ob, fns, &args, binfo, flags, &fn, complain); + rval = build_new_method_call (ob, fns, &args, binfo, flags, &fn, complain, + input_location); release_tree_vector (args); if (fn && rval == error_mark_node) Index: cp/class.c =================================================================== --- cp/class.c (revision 190939) +++ cp/class.c (working copy) @@ -7355,6 +7355,9 @@ build_self_reference (void) DECL_CONTEXT (value) = current_class_type; DECL_ARTIFICIAL (value) = 1; SET_DECL_SELF_REFERENCE_P (value); + DECL_SOURCE_LOCATION (value) = + DECL_SOURCE_LOCATION (TYPE_NAME (current_class_type)); + set_underlying_type (value); if (processing_template_decl) Index: cp/pt.c =================================================================== --- cp/pt.c (revision 190939) +++ cp/pt.c (working copy) @@ -13788,20 +13788,20 @@ tsubst_copy_and_build (tree t, ret = finish_call_expr (function, &call_args, /*disallow_virtual=*/false, /*koenig_p=*/false, - complain); + complain, input_location); else ret = (build_new_method_call (instance, fn, &call_args, NULL_TREE, qualified_p ? LOOKUP_NONVIRTUAL : LOOKUP_NORMAL, /*fn_p=*/NULL, - complain)); + complain, input_location)); } else ret = finish_call_expr (function, &call_args, /*disallow_virtual=*/qualified_p, koenig_p, - complain); + complain, input_location); release_tree_vector (call_args); Index: cp/parser.c =================================================================== --- cp/parser.c (revision 190939) +++ cp/parser.c (working copy) @@ -1787,7 +1787,7 @@ static bool cp_parser_translation_unit static tree cp_parser_primary_expression (cp_parser *, bool, bool, bool, cp_id_kind *); static tree cp_parser_id_expression - (cp_parser *, bool, bool, bool *, bool, bool); + (cp_parser *, bool, bool, bool *, bool, bool, location_t *); static tree cp_parser_unqualified_id (cp_parser *, bool, bool, bool, bool); static tree cp_parser_nested_name_specifier_opt @@ -1803,7 +1803,7 @@ static tree cp_parser_postfix_open_squar static tree cp_parser_postfix_dot_deref_expression (cp_parser *, enum cpp_ttype, tree, bool, cp_id_kind *, location_t); static VEC(tree,gc) *cp_parser_parenthesized_expression_list - (cp_parser *, int, bool, bool, bool *); + (cp_parser *, int, bool, bool, bool *, location_t *, int *); /* Values for the second parameter of cp_parser_parenthesized_expression_list. */ enum { non_attr = 0, normal_attr = 1, id_attr = 2 }; static void cp_parser_pseudo_destructor_name @@ -1831,7 +1831,7 @@ static tree cp_parser_cast_expression static tree cp_parser_binary_expression (cp_parser *, bool, bool, enum cp_parser_prec, cp_id_kind *); static tree cp_parser_question_colon_clause - (cp_parser *, tree); + (cp_parser *, tree, location_t); static tree cp_parser_assignment_expression (cp_parser *, bool, cp_id_kind *); static enum tree_code cp_parser_assignment_operator_opt @@ -1968,7 +1968,7 @@ static cp_virt_specifiers cp_parser_virt static tree cp_parser_late_return_type_opt (cp_parser *, cp_cv_quals); static tree cp_parser_declarator_id - (cp_parser *, bool); + (cp_parser *, bool, location_t *); static tree cp_parser_type_id (cp_parser *); static tree cp_parser_template_type_arg @@ -2844,7 +2844,8 @@ cp_parser_parse_and_diagnose_invalid_typ /*check_dependency_p=*/true, /*template_p=*/NULL, /*declarator_p=*/true, - /*optional_p=*/false); + /*optional_p=*/false, + /*loc=*/NULL); /* If the next token is a (, this is a function with no explicit return type, i.e. constructor, destructor or conversion op. */ if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN) @@ -3583,7 +3584,8 @@ cp_parser_userdef_char_literal (cp_parse release_tree_vector (args); return error_mark_node; } - result = finish_call_expr (decl, &args, false, true, tf_warning_or_error); + result = finish_call_expr + (decl, &args, false, true, tf_warning_or_error, token->location); release_tree_vector (args); if (result != error_mark_node) return result; @@ -3641,7 +3643,8 @@ cp_parser_userdef_numeric_literal (cp_pa decl = lookup_literal_operator (name, args); if (decl && decl != error_mark_node) { - result = finish_call_expr (decl, &args, false, true, tf_none); + result = finish_call_expr + (decl, &args, false, true, tf_none, token->location); if (result != error_mark_node) { release_tree_vector (args); @@ -3658,7 +3661,8 @@ cp_parser_userdef_numeric_literal (cp_pa decl = lookup_literal_operator (name, args); if (decl && decl != error_mark_node) { - result = finish_call_expr (decl, &args, false, true, tf_none); + result = finish_call_expr + (decl, &args, false, true, tf_none, token->location); if (result != error_mark_node) { release_tree_vector (args); @@ -3676,7 +3680,8 @@ cp_parser_userdef_numeric_literal (cp_pa { tree tmpl_args = make_char_string_pack (num_string); decl = lookup_template_function (decl, tmpl_args); - result = finish_call_expr (decl, &args, false, true, tf_none); + result = finish_call_expr + (decl, &args, false, true, tf_none, token->location); if (result != error_mark_node) { release_tree_vector (args); @@ -3716,7 +3721,7 @@ cp_parser_userdef_string_literal (cp_tok release_tree_vector (args); return error_mark_node; } - result = finish_call_expr (decl, &args, false, true, tf_none); + result = finish_call_expr (decl, &args, false, true, tf_none, token->location); release_tree_vector (args); if (result != error_mark_node) return result; @@ -4226,7 +4231,8 @@ cp_parser_primary_expression (cp_parser /*check_dependency_p=*/true, &template_p, /*declarator_p=*/false, - /*optional_p=*/false); + /*optional_p=*/false, + /*loc=*/NULL); if (id_expression == error_mark_node) return error_mark_node; id_expr_token = token; @@ -4389,7 +4395,10 @@ cp_parser_primary_expression (cp_parser named is a template. If DECLARATOR_P is true, the id-expression is appearing as part of - a declarator, rather than as part of an expression. */ + a declarator, rather than as part of an expression. + + If LOC is non-NULL and a qualified-id is found, LOC is set to the location + of the unqualified-id. */ static tree cp_parser_id_expression (cp_parser *parser, @@ -4397,7 +4406,8 @@ cp_parser_id_expression (cp_parser *pars bool check_dependency_p, bool *template_p, bool declarator_p, - bool optional_p) + bool optional_p, + location_t *loc) { bool global_scope_p; bool nested_name_specifier_p; @@ -4437,6 +4447,10 @@ cp_parser_id_expression (cp_parser *pars saved_scope = parser->scope; saved_object_scope = parser->object_scope; saved_qualifying_scope = parser->qualifying_scope; + + if (loc) + *loc = cp_lexer_peek_token (parser->lexer)->location; + /* Process the final unqualified-id. */ unqualified_id = cp_parser_unqualified_id (parser, *template_p, check_dependency_p, @@ -4459,6 +4473,9 @@ cp_parser_id_expression (cp_parser *pars /* Peek at the next token. */ token = cp_lexer_peek_token (parser->lexer); + if (loc) + *loc = token->location; + /* If it's an identifier, and the next token is not a "<", then we can avoid the template-id case. This is an optimization for this common case. */ @@ -4498,10 +4515,15 @@ cp_parser_id_expression (cp_parser *pars } } else - return cp_parser_unqualified_id (parser, template_keyword_p, - /*check_dependency_p=*/true, - declarator_p, - optional_p); + { + if (loc) + *loc = cp_lexer_peek_token (parser->lexer)->location; + + return cp_parser_unqualified_id (parser, template_keyword_p, + /*check_dependency_p=*/true, + declarator_p, + optional_p); + } } /* Parse an unqualified-id. @@ -5326,6 +5348,7 @@ cp_parser_postfix_expression (cp_parser cp_id_kind idk = CP_ID_KIND_NONE; tree postfix_expression = NULL_TREE; bool is_member_access = false; + location_t locs[64], member_loc = UNKNOWN_LOCATION; /* Peek at the next token. */ token = cp_lexer_peek_token (parser->lexer); @@ -5468,7 +5491,8 @@ cp_parser_postfix_expression (cp_parser cp_lexer_consume_token (parser->lexer); vec = cp_parser_parenthesized_expression_list (parser, non_attr, /*cast_p=*/false, /*allow_expansion_p=*/true, - /*non_constant_p=*/NULL); + /*non_constant_p=*/NULL, + /*locs=*/NULL, /*num_locs=*/NULL); if (vec == NULL) return error_mark_node; @@ -5603,6 +5627,7 @@ cp_parser_postfix_expression (cp_parser = unqualified_name_lookup_error (postfix_expression); /* Peek at the next token. */ + locs[0] = token->location; token = cp_lexer_peek_token (parser->lexer); switch (token->type) @@ -5624,6 +5649,7 @@ cp_parser_postfix_expression (cp_parser bool saved_integral_constant_expression_p = false; bool saved_non_integral_constant_expression_p = false; VEC(tree,gc) *args; + int num_locs = 63; is_member_access = false; @@ -5642,7 +5668,7 @@ cp_parser_postfix_expression (cp_parser args = (cp_parser_parenthesized_expression_list (parser, non_attr, /*cast_p=*/false, /*allow_expansion_p=*/true, - /*non_constant_p=*/NULL)); + /*non_constant_p=*/NULL, &locs[1], &num_locs)); if (is_builtin_constant_p) { parser->integral_constant_expression_p @@ -5717,6 +5743,11 @@ cp_parser_postfix_expression (cp_parser tree instance = TREE_OPERAND (postfix_expression, 0); tree fn = TREE_OPERAND (postfix_expression, 1); + if (member_loc == UNKNOWN_LOCATION) + member_loc = locs[0]; + else + locs[0] = member_loc; + if (processing_template_decl && (type_dependent_expression_p (instance) || (!BASELINK_P (fn) @@ -5739,14 +5770,14 @@ cp_parser_postfix_expression (cp_parser ? LOOKUP_NORMAL|LOOKUP_NONVIRTUAL : LOOKUP_NORMAL), /*fn_p=*/NULL, - tf_warning_or_error)); + tf_warning_or_error, member_loc)); } else postfix_expression = finish_call_expr (postfix_expression, &args, /*disallow_virtual=*/false, /*koenig_p=*/false, - tf_warning_or_error); + tf_warning_or_error, member_loc); } else if (TREE_CODE (postfix_expression) == OFFSET_REF || TREE_CODE (postfix_expression) == MEMBER_REF @@ -5760,14 +5791,15 @@ cp_parser_postfix_expression (cp_parser = finish_call_expr (postfix_expression, &args, /*disallow_virtual=*/true, koenig_p, - tf_warning_or_error); + tf_warning_or_error, locs[0]); else /* All other function calls. */ postfix_expression = finish_call_expr (postfix_expression, &args, /*disallow_virtual=*/false, koenig_p, - tf_warning_or_error); + tf_warning_or_error, locs[0]); + SET_EXPR_LOCATIONS (postfix_expression, locs, num_locs+1); /* The POSTFIX_EXPRESSION is certainly no longer an id. */ idk = CP_ID_KIND_NONE; @@ -5785,6 +5817,7 @@ cp_parser_postfix_expression (cp_parser /* Consume the `.' or `->' operator. */ cp_lexer_consume_token (parser->lexer); + member_loc = locs[1] = cp_lexer_peek_token (parser->lexer)->location; postfix_expression = cp_parser_postfix_dot_deref_expression (parser, token->type, @@ -5792,6 +5825,8 @@ cp_parser_postfix_expression (cp_parser false, &idk, token->location); + protected_set_expr_location (postfix_expression, token->location); + SET_EXPR_LOCATIONS (postfix_expression, locs, 2); is_member_access = true; break; @@ -5799,6 +5834,7 @@ cp_parser_postfix_expression (cp_parser /* postfix-expression ++ */ /* Consume the `++' token. */ cp_lexer_consume_token (parser->lexer); + locs[1] = locs [0]; /* Generate a representation for the complete expression. */ postfix_expression = finish_increment_expr (postfix_expression, @@ -5806,6 +5842,11 @@ cp_parser_postfix_expression (cp_parser /* Increments may not appear in constant-expressions. */ if (cp_parser_non_integral_constant_expression (parser, NIC_INC)) postfix_expression = error_mark_node; + else + { + protected_set_expr_location (postfix_expression, token->location); + SET_EXPR_LOCATIONS (postfix_expression, locs, 2); + } idk = CP_ID_KIND_NONE; is_member_access = false; break; @@ -5814,6 +5855,7 @@ cp_parser_postfix_expression (cp_parser /* postfix-expression -- */ /* Consume the `--' token. */ cp_lexer_consume_token (parser->lexer); + locs[1] = locs [0]; /* Generate a representation for the complete expression. */ postfix_expression = finish_increment_expr (postfix_expression, @@ -5821,6 +5863,11 @@ cp_parser_postfix_expression (cp_parser /* Decrements may not appear in constant-expressions. */ if (cp_parser_non_integral_constant_expression (parser, NIC_DEC)) postfix_expression = error_mark_node; + else + { + protected_set_expr_location (postfix_expression, token->location); + SET_EXPR_LOCATIONS (postfix_expression, locs, 2); + } idk = CP_ID_KIND_NONE; is_member_access = false; break; @@ -5855,10 +5902,13 @@ cp_parser_postfix_open_square_expression bool for_offsetof) { tree index; + location_t locs[2]; location_t loc = cp_lexer_peek_token (parser->lexer)->location; + locs[0] = input_location; /* Consume the `[' token. */ cp_lexer_consume_token (parser->lexer); + locs[1] = cp_lexer_peek_token (parser->lexer)->location; /* Parse the index expression. */ /* ??? For offsetof, there is a question of what to allow here. If @@ -5893,6 +5943,10 @@ cp_parser_postfix_open_square_expression if (!for_offsetof && (cp_parser_non_integral_constant_expression (parser, NIC_ARRAY_REF))) postfix_expression = error_mark_node; + else if (TREE_CODE (postfix_expression) == INDIRECT_REF) + SET_EXPR_LOCATIONS (TREE_OPERAND (postfix_expression, 0), locs, 2); + else + SET_EXPR_LOCATIONS (postfix_expression, locs, 2); return postfix_expression; } @@ -6018,7 +6072,8 @@ cp_parser_postfix_dot_deref_expression ( /*check_dependency_p=*/true, &template_p, /*declarator_p=*/false, - /*optional_p=*/false)); + /*optional_p=*/false, + /*loc=*/NULL)); /* In general, build a SCOPE_REF if the member name is qualified. However, if the name was not dependent and has already been resolved; there is no need to build the SCOPE_REF. For example; @@ -6115,12 +6170,14 @@ cp_parser_parenthesized_expression_list int is_attribute_list, bool cast_p, bool allow_expansion_p, - bool *non_constant_p) + bool *non_constant_p, + location_t *locs, int *num_locs) { VEC(tree,gc) *expression_list; bool fold_expr_p = is_attribute_list != non_attr; tree identifier = NULL_TREE; bool saved_greater_than_is_operator_p; + int i = 0; /* Assume all the expressions will be constant. */ if (non_constant_p) @@ -6143,6 +6200,9 @@ cp_parser_parenthesized_expression_list { tree expr; + if (locs && i < *num_locs) + locs[i++] = cp_lexer_peek_token (parser->lexer)->location; + /* At the beginning of attribute lists, check to see if the next token is an identifier. */ if (is_attribute_list == id_attr @@ -6238,6 +6298,9 @@ cp_parser_parenthesized_expression_list } } + if (locs) + *num_locs = i; + parser->greater_than_is_operator_p = saved_greater_than_is_operator_p; @@ -6540,9 +6603,11 @@ cp_parser_unary_expression (cp_parser *p tree identifier; tree expression; location_t loc = token->location; + location_t loc2; /* Consume the '&&' token. */ cp_lexer_consume_token (parser->lexer); + loc2 = cp_lexer_peek_token (parser->lexer)->location; /* Look for the identifier. */ identifier = cp_parser_identifier (parser); /* Create an expression representing the address. */ @@ -6550,6 +6615,8 @@ cp_parser_unary_expression (cp_parser *p if (cp_parser_non_integral_constant_expression (parser, NIC_ADDR_LABEL)) expression = error_mark_node; + else + SET_EXPR_LOCATION2 (expression, loc2); return expression; } } @@ -6559,9 +6626,11 @@ cp_parser_unary_expression (cp_parser *p tree expression = error_mark_node; non_integral_constant non_constant_p = NIC_NONE; location_t loc = token->location; + location_t loc2; /* Consume the operator token. */ token = cp_lexer_consume_token (parser->lexer); + loc2 = cp_lexer_peek_token (parser->lexer)->location; /* Parse the cast-expression. */ cast_expression = cp_parser_cast_expression (parser, @@ -6606,6 +6675,8 @@ cp_parser_unary_expression (cp_parser *p && cp_parser_non_integral_constant_expression (parser, non_constant_p)) expression = error_mark_node; + else + SET_EXPR_LOCATION2 (expression, loc2); return expression; } @@ -6761,7 +6832,7 @@ cp_parser_new_placement (cp_parser* pars expression_list = (cp_parser_parenthesized_expression_list (parser, non_attr, /*cast_p=*/false, /*allow_expansion_p=*/true, - /*non_constant_p=*/NULL)); + /*non_constant_p=*/NULL, /*locs=*/NULL, /*num_locs=*/NULL)); return expression_list; } @@ -6963,7 +7034,7 @@ cp_parser_new_initializer (cp_parser* pa expression_list = (cp_parser_parenthesized_expression_list (parser, non_attr, /*cast_p=*/false, /*allow_expansion_p=*/true, - /*non_constant_p=*/NULL)); + /*non_constant_p=*/NULL, /*locs=*/NULL, /*num_locs=*/NULL)); return expression_list; } @@ -7281,10 +7352,14 @@ cp_parser_binary_expression (cp_parser* enum tree_code rhs_type; enum cp_parser_prec new_prec, lookahead_prec; tree overload; + location_t locs[2]; /* Parse the first expression. */ + locs[0] = cp_lexer_peek_token (parser->lexer)->location; current.lhs = cp_parser_cast_expression (parser, /*address_p=*/false, cast_p, pidk); + if (EXPR_P (current.lhs)) + locs[0] = EXPR_LOCATION (current.lhs); current.lhs_type = ERROR_MARK; current.prec = prec; @@ -7340,6 +7415,7 @@ cp_parser_binary_expression (cp_parser* /* Extract another operand. It may be the RHS of this expression or the LHS of a new, higher priority expression. */ + locs[1] = cp_lexer_peek_token (parser->lexer)->location; rhs = cp_parser_simple_cast_expression (parser); rhs_type = ERROR_MARK; @@ -7359,6 +7435,8 @@ cp_parser_binary_expression (cp_parser* current.lhs = rhs; current.lhs_type = rhs_type; current.prec = new_prec; + current.loc = locs[0]; + locs[0] = locs[1]; new_prec = lookahead_prec; goto get_rhs; @@ -7375,6 +7453,8 @@ cp_parser_binary_expression (cp_parser* rhs_type = current.lhs_type; --sp; current = *sp; + locs[1] = locs[0]; + locs[0] = sp->loc; } /* Undo the disabling of warnings done above. */ @@ -7402,6 +7482,7 @@ cp_parser_binary_expression (cp_parser* current.lhs, current.lhs_type, rhs, rhs_type, &overload, tf_warning_or_error); + SET_EXPR_LOCATIONS (current.lhs, locs, 2); current.lhs_type = current.tree_type; /* If the binary operator required the use of an overloaded operator, @@ -7423,6 +7504,7 @@ cp_parser_binary_expression (cp_parser* /* Parse the `? expression : assignment-expression' part of a conditional-expression. The LOGICAL_OR_EXPR is the logical-or-expression that started the conditional-expression. + LHS_LOC is the location of the lhs. Returns a representation of the entire conditional-expression. This routine is used by cp_parser_assignment_expression. @@ -7434,13 +7516,24 @@ cp_parser_binary_expression (cp_parser* ? : assignment-expression */ static tree -cp_parser_question_colon_clause (cp_parser* parser, tree logical_or_expr) +cp_parser_question_colon_clause (cp_parser* parser, + tree logical_or_expr, + location_t lhs_loc) { tree expr; tree assignment_expr; + tree result; + /* locations of the conditional expression: + locs[0] == location of ? + locs[1] == location of lhs + locs[2] == location of expression + locs[3] == location of assignment-expression. */ + location_t locs[4]; struct cp_token *token; location_t loc = cp_lexer_peek_token (parser->lexer)->location; + locs[0] = cp_lexer_peek_token (parser->lexer)->location; + locs[1] = lhs_loc; /* Consume the `?' token. */ cp_lexer_consume_token (parser->lexer); token = cp_lexer_peek_token (parser->lexer); @@ -7451,6 +7544,7 @@ cp_parser_question_colon_clause (cp_pars "ISO C++ does not allow ?: with omitted middle operand"); /* Implicit true clause. */ expr = NULL_TREE; + locs[2] = UNKNOWN_LOCATION; c_inhibit_evaluation_warnings += logical_or_expr == truthvalue_true_node; warn_for_omitted_condop (token->location, logical_or_expr); } @@ -7458,6 +7552,7 @@ cp_parser_question_colon_clause (cp_pars { bool saved_colon_corrects_to_scope_p = parser->colon_corrects_to_scope_p; parser->colon_corrects_to_scope_p = false; + locs[2] = cp_lexer_peek_token (parser->lexer)->location; /* Parse the expression. */ c_inhibit_evaluation_warnings += logical_or_expr == truthvalue_false_node; expr = cp_parser_expression (parser, /*cast_p=*/false, NULL); @@ -7469,15 +7564,19 @@ cp_parser_question_colon_clause (cp_pars /* The next token should be a `:'. */ cp_parser_require (parser, CPP_COLON, RT_COLON); + locs[3] = cp_lexer_peek_token (parser->lexer)->location; /* Parse the assignment-expression. */ assignment_expr = cp_parser_assignment_expression (parser, /*cast_p=*/false, NULL); c_inhibit_evaluation_warnings -= logical_or_expr == truthvalue_true_node; /* Build the conditional-expression. */ - return build_x_conditional_expr (loc, logical_or_expr, - expr, - assignment_expr, - tf_warning_or_error); + result = build_x_conditional_expr (loc, logical_or_expr, + expr, + assignment_expr, + tf_warning_or_error); + protected_set_expr_location (result, locs[0]); + SET_EXPR_LOCATIONS (result, &locs[1], 3); + return result; } /* Parse an assignment-expression. @@ -7496,6 +7595,12 @@ cp_parser_assignment_expression (cp_pars cp_id_kind * pidk) { tree expr; + /* extra locations of the assignment expression: + locs[0] == location of lhs + locs[1] == location of rhs. */ + location_t locs[2]; + + locs[0] = cp_lexer_peek_token (parser->lexer)->location; /* If the next token is the `throw' keyword, then we're looking at a throw-expression. */ @@ -7511,7 +7616,7 @@ cp_parser_assignment_expression (cp_pars /* If the next token is a `?' then we're actually looking at a conditional-expression. */ if (cp_lexer_next_token_is (parser->lexer, CPP_QUERY)) - return cp_parser_question_colon_clause (parser, expr); + return cp_parser_question_colon_clause (parser, expr, locs[0]); else { location_t loc = cp_lexer_peek_token (parser->lexer)->location; @@ -7524,9 +7629,11 @@ cp_parser_assignment_expression (cp_pars { bool non_constant_p; location_t saved_input_location; + tree rhs; /* Parse the right-hand side of the assignment. */ - tree rhs = cp_parser_initializer_clause (parser, &non_constant_p); + locs[1] = cp_lexer_peek_token (parser->lexer)->location; + rhs = cp_parser_initializer_clause (parser, &non_constant_p); if (BRACE_ENCLOSED_INITIALIZER_P (rhs)) maybe_warn_cpp0x (CPP0X_INITIALIZER_LISTS); @@ -7545,6 +7652,7 @@ cp_parser_assignment_expression (cp_pars rhs, tf_warning_or_error); input_location = saved_input_location; + SET_EXPR_LOCATIONS (expr, locs, 2); } } } @@ -9609,12 +9717,12 @@ cp_parser_perform_range_for_lookup (tree /*include_std=*/true, tf_warning_or_error); *begin = finish_call_expr (member_begin, &vec, false, true, - tf_warning_or_error); + tf_warning_or_error, input_location); member_end = perform_koenig_lookup (id_end, vec, /*include_std=*/true, tf_warning_or_error); *end = finish_call_expr (member_end, &vec, false, true, - tf_warning_or_error); + tf_warning_or_error, input_location); release_tree_vector (vec); } @@ -9658,7 +9766,7 @@ cp_parser_range_for_member_function (tre res = finish_call_expr (member, &vec, /*disallow_virtual=*/false, /*koenig_p=*/false, - tf_warning_or_error); + tf_warning_or_error, input_location); release_tree_vector (vec); return res; } @@ -11067,7 +11175,8 @@ cp_parser_decltype (cp_parser *parser) /*check_dependency_p=*/true, /*template_p=*/NULL, /*declarator_p=*/false, - /*optional_p=*/false); + /*optional_p=*/false, + /*loc=*/NULL); if (!cp_parser_error_occurred (parser) && expr != error_mark_node) { @@ -11513,7 +11622,9 @@ cp_parser_mem_initializer (cp_parser* pa vec = cp_parser_parenthesized_expression_list (parser, non_attr, /*cast_p=*/false, /*allow_expansion_p=*/true, - /*non_constant_p=*/NULL); + /*non_constant_p=*/NULL, + /*locs=*/NULL, + /*num_locs=*/NULL); if (vec == NULL) return error_mark_node; expression_list = build_tree_list_vec (vec); @@ -12315,7 +12426,8 @@ cp_parser_type_parameter (cp_parser* par /*check_dependency_p=*/true, /*template_p=*/&is_template, /*declarator_p=*/false, - /*optional_p=*/false); + /*optional_p=*/false, + /*loc=*/NULL); if (TREE_CODE (default_argument) == TYPE_DECL) /* If the id-expression was a template-id that refers to a template-class, we already have the declaration here, @@ -12943,7 +13055,8 @@ cp_parser_template_argument (cp_parser* /*check_dependency_p=*/true, &template_p, /*declarator_p=*/false, - /*optional_p=*/false); + /*optional_p=*/false, + /*loc=*/NULL); /* If the next token isn't a `,' or a `>', then this argument wasn't really finished. */ if (!cp_parser_next_token_ends_template_argument_p (parser)) @@ -16245,6 +16358,7 @@ cp_parser_direct_declarator (cp_parser* bool abstract_ok; bool pack_expansion_p = false; cp_token *declarator_id_start_token; + location_t loc; /* Parse a declarator-id */ abstract_ok = (dcl_kind == CP_PARSER_DECLARATOR_EITHER); @@ -16265,7 +16379,8 @@ cp_parser_direct_declarator (cp_parser* declarator_id_start_token = cp_lexer_peek_token (parser->lexer); unqualified_name - = cp_parser_declarator_id (parser, /*optional_p=*/abstract_ok); + = cp_parser_declarator_id (parser, /*optional_p=*/abstract_ok, + &loc); qualifying_scope = parser->scope; if (abstract_ok) { @@ -16421,7 +16536,7 @@ cp_parser_direct_declarator (cp_parser* declarator = make_id_declarator (qualifying_scope, unqualified_name, sfk); - declarator->id_loc = token->location; + declarator->id_loc = loc; declarator->parameter_pack_p = pack_expansion_p; if (pack_expansion_p) @@ -16772,10 +16887,12 @@ cp_parser_late_return_type_opt (cp_parse If the id-expression was a qualified-id, then a SCOPE_REF is returned. The first operand is the scope (either a NAMESPACE_DECL or TREE_TYPE), but the second is still just a representation of an - unqualified-id. */ + unqualified-id. + + if LOC is not-NULL, it is set to the location of the unqualified-id. */ static tree -cp_parser_declarator_id (cp_parser* parser, bool optional_p) +cp_parser_declarator_id (cp_parser* parser, bool optional_p, location_t *loc) { tree id; /* The expression must be an id-expression. Assume that qualified @@ -16797,7 +16914,8 @@ cp_parser_declarator_id (cp_parser* pars /*check_dependency_p=*/false, /*template_p=*/NULL, /*declarator_p=*/true, - optional_p); + optional_p, + loc); if (id && BASELINK_P (id)) id = BASELINK_FUNCTIONS (id); return id; @@ -17548,7 +17666,9 @@ cp_parser_initializer (cp_parser* parser vec = cp_parser_parenthesized_expression_list (parser, non_attr, /*cast_p=*/false, /*allow_expansion_p=*/true, - non_constant_p); + non_constant_p, + /*locs=*/NULL, + /*num_locs=*/NULL); if (vec == NULL) return error_mark_node; init = build_tree_list_vec (vec); @@ -20223,7 +20343,7 @@ cp_parser_attribute_list (cp_parser* par vec = cp_parser_parenthesized_expression_list (parser, attr_flag, /*cast_p=*/false, /*allow_expansion_p=*/false, - /*non_constant_p=*/NULL); + /*non_constant_p=*/NULL, /*locs=*/NULL, /*num_locs=*/NULL); if (vec == NULL) arguments = error_mark_node; else @@ -21489,7 +21609,9 @@ cp_parser_functional_cast (cp_parser* pa vec = cp_parser_parenthesized_expression_list (parser, non_attr, /*cast_p=*/true, /*allow_expansion_p=*/true, - /*non_constant_p=*/NULL); + /*non_constant_p=*/NULL, + /*locs=*/NULL, + /*num_locs=*/NULL); if (vec == NULL) expression_list = error_mark_node; else @@ -25145,7 +25267,8 @@ cp_parser_omp_var_list_no_open (cp_parse /*check_dependency_p=*/true, /*template_p=*/NULL, /*declarator_p=*/false, - /*optional_p=*/false); + /*optional_p=*/false, + /*loc=*/NULL); if (name == error_mark_node) goto skip_comma; Index: cp/init.c =================================================================== --- cp/init.c (revision 190939) +++ cp/init.c (working copy) @@ -2482,7 +2482,7 @@ build_new_1 (VEC(tree,gc) **placement, t /*conversion_path=*/NULL_TREE, LOOKUP_NORMAL, &alloc_fn, - complain); + complain, input_location); } else { @@ -3693,7 +3693,7 @@ build_dtor_call (tree exp, special_funct /*conversion_path=*/NULL_TREE, flags, /*fn_p=*/NULL, - complain); + complain, input_location); } /* Generate a call to a destructor. TYPE is the type to cast ADDR to. Index: cp/cp-tree.h =================================================================== --- cp/cp-tree.h (revision 190939) +++ cp/cp-tree.h (working copy) @@ -4890,7 +4890,7 @@ extern tree build_operator_new_call (tr tsubst_flags_t); extern tree build_new_method_call (tree, tree, VEC(tree,gc) **, tree, int, tree *, - tsubst_flags_t); + tsubst_flags_t, location_t); extern tree build_special_member_call (tree, tree, VEC(tree,gc) **, tree, int, tsubst_flags_t); extern tree build_new_op (location_t, enum tree_code, @@ -5594,7 +5594,8 @@ bool empty_expr_stmt_p (tree); extern tree perform_koenig_lookup (tree, VEC(tree,gc) *, bool, tsubst_flags_t); extern tree finish_call_expr (tree, VEC(tree,gc) **, bool, - bool, tsubst_flags_t); + bool, tsubst_flags_t, + location_t); extern tree finish_increment_expr (tree, enum tree_code); extern tree finish_this_expr (void); extern tree finish_pseudo_destructor_expr (tree, tree, tree); Index: cp/semantics.c =================================================================== --- cp/semantics.c (revision 190939) +++ cp/semantics.c (working copy) @@ -2047,7 +2047,7 @@ perform_koenig_lookup (tree fn, VEC(tree tree finish_call_expr (tree fn, VEC(tree,gc) **args, bool disallow_virtual, - bool koenig_p, tsubst_flags_t complain) + bool koenig_p, tsubst_flags_t complain, location_t loc) { tree result; tree orig_fn; @@ -2117,7 +2117,7 @@ finish_call_expr (tree fn, VEC(tree,gc) ? LOOKUP_NORMAL | LOOKUP_NONVIRTUAL : LOOKUP_NORMAL), /*fn_p=*/NULL, - complain); + complain, loc); } } @@ -2167,7 +2167,7 @@ finish_call_expr (tree fn, VEC(tree,gc) ? LOOKUP_NORMAL|LOOKUP_NONVIRTUAL : LOOKUP_NORMAL), /*fn_p=*/NULL, - complain); + complain, loc); } else if (is_overloaded_fn (fn)) { @@ -3211,6 +3211,8 @@ finish_id_expression (tree id_expression decl = finish_non_static_data_member (decl, NULL_TREE, /*qualifying_scope=*/NULL_TREE); + if (EXPR_P (decl)) + SET_EXPR_LOCATION (decl, location); pop_deferring_access_checks (); return decl; } @@ -3288,6 +3290,8 @@ finish_id_expression (tree id_expression push_deferring_access_checks (dk_no_check); decl = finish_non_static_data_member (decl, NULL_TREE, /*qualifying_scope=*/NULL_TREE); + if (EXPR_P (decl)) + SET_EXPR_LOCATION (decl, location); pop_deferring_access_checks (); } else if (is_overloaded_fn (decl)) @@ -4978,7 +4982,8 @@ finish_omp_barrier (void) { tree fn = builtin_decl_explicit (BUILT_IN_GOMP_BARRIER); VEC(tree,gc) *vec = make_tree_vector (); - tree stmt = finish_call_expr (fn, &vec, false, false, tf_warning_or_error); + tree stmt = finish_call_expr (fn, &vec, false, false, tf_warning_or_error, + input_location); release_tree_vector (vec); finish_expr_stmt (stmt); } @@ -4988,7 +4993,8 @@ finish_omp_flush (void) { tree fn = builtin_decl_explicit (BUILT_IN_SYNC_SYNCHRONIZE); VEC(tree,gc) *vec = make_tree_vector (); - tree stmt = finish_call_expr (fn, &vec, false, false, tf_warning_or_error); + tree stmt = finish_call_expr (fn, &vec, false, false, tf_warning_or_error, + input_location); release_tree_vector (vec); finish_expr_stmt (stmt); } @@ -4998,7 +5004,8 @@ finish_omp_taskwait (void) { tree fn = builtin_decl_explicit (BUILT_IN_GOMP_TASKWAIT); VEC(tree,gc) *vec = make_tree_vector (); - tree stmt = finish_call_expr (fn, &vec, false, false, tf_warning_or_error); + tree stmt = finish_call_expr (fn, &vec, false, false, tf_warning_or_error, + input_location); release_tree_vector (vec); finish_expr_stmt (stmt); } @@ -5008,7 +5015,8 @@ finish_omp_taskyield (void) { tree fn = builtin_decl_explicit (BUILT_IN_GOMP_TASKYIELD); VEC(tree,gc) *vec = make_tree_vector (); - tree stmt = finish_call_expr (fn, &vec, false, false, tf_warning_or_error); + tree stmt = finish_call_expr (fn, &vec, false, false, tf_warning_or_error, + input_location); release_tree_vector (vec); finish_expr_stmt (stmt); } Index: testsuite/g++.dg/warn/pr26785.C =================================================================== --- testsuite/g++.dg/warn/pr26785.C (revision 190939) +++ testsuite/g++.dg/warn/pr26785.C (working copy) @@ -3,7 +3,7 @@ // { dg-options "-fshow-column" } class foo { - foo::foo // { dg-error "3:extra qualification" } + foo::foo // { dg-error "8:extra qualification" } (int a, int b, int c); Index: testsuite/g++.dg/tc1/dr52.C =================================================================== --- testsuite/g++.dg/tc1/dr52.C (revision 190939) +++ testsuite/g++.dg/tc1/dr52.C (working copy) @@ -16,8 +16,8 @@ private: struct B1 : B {}; struct B2 : B {}; -struct C -{ // { dg-error "C" } +struct C // { dg-error "C" } +{ void foo(void); }; Index: testsuite/g++.old-deja/g++.brendan/crash16.C =================================================================== --- testsuite/g++.old-deja/g++.brendan/crash16.C (revision 190939) +++ testsuite/g++.old-deja/g++.brendan/crash16.C (working copy) @@ -8,7 +8,7 @@ public: Graph(void) {} // { dg-error "7:'Graph" } } -Graph::Graph(void) // { dg-error "18:return type|1: error: redefinition" } +Graph::Graph(void) // { dg-error "18:return type|8: error: redefinition" } { N = 10; } Index: common.opt =================================================================== --- common.opt (revision 190939) +++ common.opt (working copy) @@ -1098,6 +1098,10 @@ fexcess-precision= Common Joined RejectNegative Enum(excess_precision) Var(flag_excess_precision_cmdline) Init(EXCESS_PRECISION_DEFAULT) -fexcess-precision=[fast|standard] Specify handling of excess floating-point precision +fextra-slocs +Common Var(flag_extra_slocs) Init(0) +Generate extra sloc information on expression trees + Enum Name(excess_precision) Type(enum excess_precision) UnknownError(unknown excess precision style %qs) Index: tree.c =================================================================== --- tree.c (revision 190939) +++ tree.c (working copy) @@ -3561,6 +3561,8 @@ stabilize_reference (tree ref) TREE_READONLY (result) = TREE_READONLY (ref); TREE_SIDE_EFFECTS (result) = TREE_SIDE_EFFECTS (ref); TREE_THIS_VOLATILE (result) = TREE_THIS_VOLATILE (ref); + protected_set_expr_location (result, EXPR_LOCATION (ref)); + duplicate_expr_locations (result, ref); return result; } @@ -4157,6 +4159,123 @@ build_block (tree vars, tree subblocks, return block; } +/* extra location hash table */ + +typedef struct { + const_tree node; + unsigned char len; + location_t locus[1]; +} sloc_struct; + +static htab_t extra_slocs = NULL; + +/* Hash function used by extra_slocs htable. */ +static hashval_t +node_hash (const void *p) +{ + const sloc_struct *m = (const sloc_struct *)p; + return htab_hash_pointer (m->node); +} + +/* Comparison function used by extra_slocs htable. */ +static int +node_eq (const void *p, const void *q) +{ + const sloc_struct *a = (const sloc_struct *)p; + const sloc_struct *b = (const sloc_struct *)q; + + return a->node == b->node; +} + +/* Only relevant for EXPR_P nodes and when flag_extra_slocs is enabled. + Return secondary locations if any for a given expression. This is useful for + getting precise sloc information in particular correct column + numbers for each member of an expression. Unary expressions will return one + extra location, binary expressions will return two, COND_EXPR 3 extra, + etc... CALL_EXPR will return one extra loc for the precise location of the + function or method called, and one extra loc per argument. */ +location_t * +expr_locations (const_tree node) +{ + sloc_struct key; + sloc_struct *res; + + if (!extra_slocs) + return NULL; + + key.node = node; + res = (sloc_struct *) htab_find (extra_slocs, &key); + return res ? res->locus : NULL; +} + +/* Return the nth location N associated with NODE, or UNKNOWN_LOCATION if + no extra location can be found (or -fextra-slocs is not set). */ +location_t +expr_location_n (const_tree node, int n) +{ + sloc_struct key; + sloc_struct *res; + + if (!extra_slocs) + return UNKNOWN_LOCATION; + + key.node = node; + res = (sloc_struct *) htab_find (extra_slocs, &key); + + if (res && res->len > n) + return res->locus[n]; + else + return UNKNOWN_LOCATION; +} + +/* Set extra locations associated with NODE. LOCUS is an array of LEN + locations. No-op unless -fextra-slocs is set. */ +void +set_expr_locations (tree node, location_t *locus, int len) +{ + sloc_struct *m; + + if (!flag_extra_slocs) + return; + + if (!extra_slocs) + extra_slocs = htab_create (8192, node_hash, node_eq, free); + + m = (sloc_struct *) + xcalloc (1, sizeof (sloc_struct) + sizeof (location_t) * (len - 1)); + m->node = node; + m->len = len; + memcpy (m->locus, locus, sizeof (location_t) * len); + *htab_find_slot (extra_slocs, m, INSERT) = m; +} + +/* Set an extra location LOCUS for tree NODE. No-op unless -fextra-slocs. */ +void +set_expr_location2 (tree node, location_t locus) +{ + if (!flag_extra_slocs) + return; + + location_t l = locus; + set_expr_locations (node, &l, 1); +} + +/* Copy extra locations associated with TARGET to SOURCE, if any. */ +void +duplicate_expr_locations (tree target, tree source) +{ + sloc_struct key; + sloc_struct *res; + + if (!extra_slocs || !CAN_HAVE_LOCATION_P (target)) + return; + + key.node = source; + res = (sloc_struct *) htab_find (extra_slocs, &key); + + if (res) + set_expr_locations (target, res->locus, res->len); +} /* Like SET_EXPR_LOCATION, but make sure the tree can have a location. Index: tree.h =================================================================== --- tree.h (revision 190939) +++ tree.h (working copy) @@ -1618,7 +1618,10 @@ struct GTY(()) tree_constructor { return nothing. */ #define EXPR_LOCATION(NODE) \ (CAN_HAVE_LOCATION_P ((NODE)) ? (NODE)->exp.locus : UNKNOWN_LOCATION) +#define EXPR_LOCATIONS(NODE) expr_locations ((NODE)) #define SET_EXPR_LOCATION(NODE, LOCUS) EXPR_CHECK ((NODE))->exp.locus = (LOCUS) +#define SET_EXPR_LOCATION2(NODE, FROM) set_expr_location2 ((NODE), (FROM)) +#define SET_EXPR_LOCATIONS(NODE, FROM, LENGTH) set_expr_locations ((NODE), (FROM), (LENGTH)) #define EXPR_HAS_LOCATION(NODE) (EXPR_LOCATION (NODE) != UNKNOWN_LOCATION) /* The location to be used in a diagnostic about this expression. Do not use this macro if the location will be assigned to other expressions. */ @@ -1631,6 +1634,11 @@ struct GTY(()) tree_constructor { #define CAN_HAVE_LOCATION_P(NODE) ((NODE) && EXPR_P (NODE)) extern void protected_set_expr_location (tree, location_t); +extern location_t *expr_locations (const_tree); +extern location_t expr_location_n (const_tree, int); +extern void set_expr_location2 (tree, location_t); +extern void set_expr_locations (tree, location_t *, int); +extern void duplicate_expr_locations (tree, tree); /* In a TARGET_EXPR node. */ #define TARGET_EXPR_SLOT(NODE) TREE_OPERAND_CHECK_CODE (NODE, TARGET_EXPR, 0)