Message ID | 20120918105831.GA15097@adacore.com |
---|---|
State | New |
Headers | show |
On Tue, Sep 18, 2012 at 3:58 AM, Arnaud Charlet <charlet@adacore.com> wrote: > > 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. Sorry for picking on simple stuff, but the switch name seems meaningless, and there isn't any documentation. Conceptually it looks like you are trying to make up for the absence of a proper AST by building an on-the-side hash table to track expression locations. The hash table key is the tree structure itself. The thing is, any call into fold-const may give you an entirely new tree, and at that point you have lost your extra location information. And the C/C++ frontends call into fold-const regularly, which is why we don't have a proper AST in the first place. So it seems to me that this is going to be kind of frustrating, in that we will often have the extra location information but sometimes we won't. And whether we have it or not will change as the frontends change. So while a proper AST would be nice, I'm not convinced that this is the right workaround. Another approach might be to tie this to the location information, because the location information does generally survive fold-const. E.g., perhaps we could grab a bit in the location information to mean that it is special. And we could keep an on-the-side hash table mapping special location values to additional location information. Ian
On Tue, 18 Sep 2012, Ian Lance Taylor wrote: > On Tue, Sep 18, 2012 at 3:58 AM, Arnaud Charlet <charlet@adacore.com> wrote: > > > > 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. > > Sorry for picking on simple stuff, but the switch name seems > meaningless, and there isn't any documentation. My simple points are that size_t is better than int for when you want to store the length of a list on the host, and that when building up a list of locations for an expression list it would be better to use a VEC rather than a fixed-length array. > Another approach might be to tie this to the > location information, because the location information does generally > survive fold-const. E.g., perhaps we could grab a bit in the location > information to mean that it is special. And we could keep an > on-the-side hash table mapping special location values to additional > location information. I also think this is to be preferred. I think of location_t as being, for most of the compiler, an opaque handle to location information. Just as it can now represent information about different concepts of location in the presence of macro expansion, so it's entirely reasonable for a location_t value to represent information about a range of locations (start and end points) for an expression, or to represent information about the locations (or ranges of locations) of the operands and operators of an expression (in the absence of an unfolded AST, where for locations of operands themselves you could just look one level down in the AST). I would guess that much of the patch would be unchanged with such an approach - you still need to pass extra location information to various places, but the details of how you attach it to the expressions might be different. I would say that a location_t mapping to a set of other locations more complicated than at present should have some structure to how it maps to them. That is, rather than just mapping to an array of values with those values used in different ways for different source code constructs, it should be possible to tell that a given location_t is mapping to certain locations as corresponding to first and second operands of an binary operator (for example).
Thanks for your feedback. > I also think this is to be preferred. I think of location_t as being, for > most of the compiler, an opaque handle to location information. Just as > it can now represent information about different concepts of location in > the presence of macro expansion, so it's entirely reasonable for a > location_t value to represent information about a range of locations > (start and end points) for an expression, or to represent information > about the locations (or ranges of locations) of the operands and operators > of an expression (in the absence of an unfolded AST, where for locations > of operands themselves you could just look one level down in the AST). OK, I agree that's an interesting/promising approach (using/reserving a bit to add a level of indirection into a separate hash table), I'll investigate what it could take to implement such approach, which would indeed get rid of the duplicate_expr_locations() calls, since this would be implicit as part of protected_set_expr_location() somehow, right? > I would guess that much of the patch would be unchanged with such an > approach - you still need to pass extra location information to various > places, but the details of how you attach it to the expressions might be > different. Right, hopefully the main difference would be the implementation of the new functions in tree.[ch] (possibly moved elsewhere?) to set/retrieve these extra slocs, most of the changes would remain almost identical I suspect. > I would say that a location_t mapping to a set of other locations more > complicated than at present should have some structure to how it maps to > them. That is, rather than just mapping to an array of values with those > values used in different ways for different source code constructs, it > should be possible to tell that a given location_t is mapping to certain > locations as corresponding to first and second operands of an binary > operator (for example). OK, so you mean, instead of knowing the number of locations from the tree kind (e.g. 1 extra sloc for unary exprs, 2 for binary exprs, ...), we would encode this as part of the extra loc info? Note that the number of extra locations is already stored in my current patch, this is the unsigned char len field of sloc_Struct in tree.c. Is that sufficient (knowing the number of slocs), or do you have something more advanced in mind? Note that the structure stored in the hash table is: typedef struct { const_tree node; unsigned char len; location_t locus[1]; } sloc_struct; In other words, we have all the info you mentioned: number of extra slocs (len field) and tree kind (via the node field). If this is not what you had in mind, could you clarify what else? Arno
On Wed, Sep 19, 2012 at 09:18:39AM +0200, Arnaud Charlet wrote: > Thanks for your feedback. > > > I also think this is to be preferred. I think of location_t as being, for > > most of the compiler, an opaque handle to location information. Just as > > it can now represent information about different concepts of location in > > the presence of macro expansion, so it's entirely reasonable for a > > location_t value to represent information about a range of locations > > (start and end points) for an expression, or to represent information > > about the locations (or ranges of locations) of the operands and operators > > of an expression (in the absence of an unfolded AST, where for locations > > of operands themselves you could just look one level down in the AST). > > OK, I agree that's an interesting/promising approach (using/reserving a bit > to add a level of indirection into a separate hash table), I'll investigate > what it could take to implement such approach, which would indeed get rid > of the duplicate_expr_locations() calls, since this would be implicit as > part of protected_set_expr_location() somehow, right? Please also read Dodji's slides from Cauldron on this: http://dodji.seketeli.net/talks/gnu-cauldron-2012/track-macro-locations.pdf and discuss with him, there is also the "Combine location with block using block_locations" patchset floating around that interferes with this partially. But range locations as part of location_t is definitely the way to go, we want that for proper diagnostics anyway. Jakub
On Wed, 19 Sep 2012, Arnaud Charlet wrote: > OK, so you mean, instead of knowing the number of locations from the > tree kind (e.g. 1 extra sloc for unary exprs, 2 for binary exprs, ...), > we would encode this as part of the extra loc info? Note that the number of No, I mean that rather than the front end using an interface defined as "set the first location to A and the second location to B" it should use one meaning "set the first operand's location to A and the second operand's location to B" or "set the beginning of the range to A and the end of the range to B" - the extra locations should in some way be tagged to indicate what their relation is to the expression, and users of the locations should then also look things up by tag rather than knowing that internally the first location for a binary operation has some particular semantics. As illustrated in the example I gave, there's more than one way one might naturally associate two locations with a binary operation, hence the desire for code to operate on them at a better-defined level than "first" and "second" locations. If you then want to insert a third location in the middle (the location of the operator, say) then you don't need to change everything that referred to locations symbolically.
On 18 September 2012 12:58, Arnaud Charlet <charlet@adacore.com> wrote: > 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. These are issues that require to be fixed. The front-ends should only fold when actually required, and then, they should keep around the original expression. > 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... Consider bugs like: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=55173, where a warning ocurs in a system-header, but GCC does not see this because the expression that triggers that warning does not have a location, so input_location is used, which is not at the header. The proposed approach does not fully solve such bugs, because at the point of warning, only the operands are available, and not the containing expression node, so the additional locations are not available. Thus, this second approach would still require passing an explicit location all over the FE. Admitedly, this is what we are currently doing in many cases. But do we want to add one extra (or worse, one per tree argument) explicit location argument on almost every FE function? For functions that accept tree nodes with location and without location, this is a waste, because depending on the particular expression, we will pass two times the same location (explicitly and implicitly as part of the node). Even worse, many functions that don't care about locations will have to pass around locations. I think, in the long-term, your proposed approach is less useful than fixing early folding and adding locations (via a wrapper or an on-the-side index) to the tree nodes that don't have one. But, since nobody is working on the latter, the "long term" may be longer than the time until someone makes a LLVM-to-GIMPLE conversor, and replaces the C/C++ FEs by clang. ;-) So, as a short-term fix, your proposed approach is definitely better than the status-quo, so I hope you manage to get it finished. Cheers, Manuel.
> I think, in the long-term, your proposed approach is less useful than > fixing early folding and adding locations (via a wrapper or an > on-the-side index) to the tree nodes that don't have one. But, since > nobody is working on the latter, the "long term" may be longer than > the time until someone makes a LLVM-to-GIMPLE conversor, and replaces > the C/C++ FEs by clang. ;-) Given the current state of front end trees and LLVM, I suspect indeed most people interested in e.g. static analysis will likely switch to LLVM if not already done. > So, as a short-term fix, your proposed > approach is definitely better than the status-quo, so I hope you > manage to get it finished. Unfortunately the suggestions I received, while they make sense on paper require a large amount of work, which I can hardly justify for now and certainly not in the short term. I suspect it would take me less time to redo my work using LLVM than to introduce a whole new API/kludge on top of gcc locations, with also still a large unknown as to whether my new patch would be accepted without yet another large rewrite. Or to put it another way, it does not really make much more sense to me to use pseudo locations than my current htable approach (it only marginally improves things, for a large development effort), in particular since a better solution would be to have a real C and C++ AST, which I suspect GCC will end up having sooner or later (e.g. via clang as you hinted). Arno
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)
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 <charlet@adacore.com> * 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; }