On Thu, 2017-11-16 at 10:58 +0100, Richard Biener wrote: > On Wed, Nov 15, 2017 at 4:33 PM, David Malcolm <dmalc...@redhat.com> > wrote: > > On Wed, 2017-11-15 at 12:11 +0100, Richard Biener wrote: > > > On Wed, Nov 15, 2017 at 7:17 AM, Trevor Saunders <tbsaunde@tbsaun > > > de.o > > > rg> wrote: > > > > On Fri, Nov 10, 2017 at 04:45:17PM -0500, David Malcolm wrote: > > > > > This patch provides a mechanism in tree.c for adding a > > > > > wrapper > > > > > node > > > > > for expressing a location_t, for those nodes for which > > > > > !CAN_HAVE_LOCATION_P, along with a new method of cp_expr. > > > > > > > > > > It's called in later patches in the kit via that new method. > > > > > > > > > > In this version of the patch, I use NON_LVALUE_EXPR for > > > > > wrapping > > > > > constants, and VIEW_CONVERT_EXPR for other nodes. > > > > > > > > > > I also turned off wrapper nodes for EXCEPTIONAL_CLASS_P, for > > > > > the > > > > > sake > > > > > of keeping the patch kit more minimal. > > > > > > > > > > The patch also adds a STRIP_ANY_LOCATION_WRAPPER macro for > > > > > stripping > > > > > such nodes, used later on in the patch kit. > > > > > > > > I happened to start reading this series near the end and was > > > > rather > > > > confused by this macro since it changes variables in a rather > > > > unhygienic > > > > way. Did you consider just defining a inline function to > > > > return > > > > the > > > > actual decl? It seems like its not used that often so the > > > > slight > > > > extra > > > > syntax should be that big a deal compared to the explicitness. > > > > > > Existing practice .... (STRIP_NOPS & friends). I'm fine either > > > way, > > > the patch looks good. > > > > > > Eventually you can simplify things by doing less checking in > > > location_wrapper_p, like only checking > > > > > > +inline bool location_wrapper_p (const_tree exp) > > > +{ > > > + if ((TREE_CODE (exp) == NON_LVALUE_EXPR > > > + || (TREE_CODE (exp) == VIEW_CONVERT_EXPR > > > + && (TREE_TYPE (exp) > > > + == TREE_TYPE (TREE_OPERAND (exp, 0))) > > > + return true; > > > + return false; > > > +} > > > > > > and renaming to maybe_location_wrapper_p. After all you can't > > > really > > > distinguish location wrappers from non-location wrappers? (and > > > why > > > would you want to?) > > > > That's the implementation I originally tried. > > > > As noted in an earlier thread about this, the problem I ran into > > was > > (in g++.dg/conversion/reinterpret1.C): > > > > // PR c++/15076 > > > > struct Y { Y(int &); }; > > > > int v; > > Y y1(reinterpret_cast<int>(v)); // { dg-error "" } > > > > where the "reinterpret_cast<int>" has the same type as the VAR_DECL > > v, > > and hence the argument to y1 is a NON_LVALUE_EXPR around a > > VAR_DECL, > > where both have the same type, and hence location_wrapper_p () on > > the > > cast would return true. > > > > Compare with: > > > > Y y1(v); > > > > where the argument "v" with a location wrapper is a > > VIEW_CONVERT_EXPR > > around a VAR_DECL. > > > > With the simpler conditions you suggested above, both are treated > > as > > location wrappers (leading to the dg-error in the test failing), > > whereas with the condition in the patch, only the latter is treated > > as > > a location wrapper, and an error is correctly emitted for the dg- > > error. > > > > Hope this sounds sane. Maybe the function needs a more detailed > > comment explaining this? > > Yes. I guess the above would argue for a new tree code but I can > see that it is better to avoid that. > > Thanks, > Richard.
[...] Here's an updated version of the patch which: * adds a much more detailed comment to location_wrapper_p, * fixes an erroneous reference to LOCATION_WRAPPER_EXPR in the comment to maybe_wrap_with_location (from an earlier unfinished experiment) * adds a selftest for handling wrapper nodes. Is there consensus about whether this approach is sane? i.e. * adding wrapper nodes via re-using existing tree codes (this kit), vs * adding them via some new tree code ("LOCATION_WRAPPER_EXPR"?), vs * the workaround of: "[PATCH] C++: use an optional vec<location_t> for callsites" https://gcc.gnu.org/ml/gcc-patches/2017-08/msg01392.html Jason? Jakub? others? (I'd like to get some version of this patch kit into gcc 8; I like this kit's approach, as a minimal way to fix a real usability issue, whilst giving us a route to doing more in gcc 9 (c.f. the v3 kit)) Thanks Dave gcc/ChangeLog: PR c++/43486 * tree.c (maybe_wrap_with_location): New function. (selftest::test_location_wrappers): New function. (selftest::tree_c_tests): Call it. * tree.h (STRIP_ANY_LOCATION_WRAPPER): New macro. (maybe_wrap_with_location): New decl. (location_wrapper_p): New inline function. gcc/cp/ChangeLog: PR c++/43486 * cp-tree.h (cp_expr::maybe_add_location_wrapper): New method. --- gcc/cp/cp-tree.h | 6 ++++++ gcc/tree.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ gcc/tree.h | 42 ++++++++++++++++++++++++++++++++++++ 3 files changed, 114 insertions(+) diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 4780df4..aa579a4 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -93,6 +93,12 @@ public: set_location (make_location (m_loc, start, finish)); } + cp_expr& maybe_add_location_wrapper () + { + m_value = maybe_wrap_with_location (m_value, m_loc); + return *this; + } + private: tree m_value; location_t m_loc; diff --git a/gcc/tree.c b/gcc/tree.c index 5416866..5e2b424 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -13791,6 +13791,38 @@ set_source_range (tree expr, source_range src_range) return adhoc; } +/* Return EXPR, potentially wrapped with a node expression LOC, + if !CAN_HAVE_LOCATION_P (expr). + + NON_LVALUE_EXPR is used for wrapping constants. + VIEW_CONVERT_EXPR is used for wrapping non-constants. + + Wrapper nodes can be identified using location_wrapper_p. */ + +tree +maybe_wrap_with_location (tree expr, location_t loc) +{ + if (expr == NULL) + return NULL; + if (loc == UNKNOWN_LOCATION) + return expr; + if (CAN_HAVE_LOCATION_P (expr)) + return expr; + /* We should only be adding wrappers for constants and for decls, + or for some exceptional tree nodes (e.g. BASELINK in the C++ FE). */ + gcc_assert (CONSTANT_CLASS_P (expr) + || DECL_P (expr) + || EXCEPTIONAL_CLASS_P (expr)); + + if (EXCEPTIONAL_CLASS_P (expr)) + return expr; + + if (CONSTANT_CLASS_P (expr)) + return build1_loc (loc, NON_LVALUE_EXPR, TREE_TYPE (expr), expr); + else + return build1_loc (loc, VIEW_CONVERT_EXPR, TREE_TYPE (expr), expr); +} + /* Return the name of combined function FN, for debugging purposes. */ const char * @@ -14016,6 +14048,39 @@ test_labels () ASSERT_FALSE (FORCED_LABEL (label_decl)); } +/* Verify location wrappers. */ + +static void +test_location_wrappers () +{ + location_t loc = BUILTINS_LOCATION; + + /* Wrapping a constant. */ + tree int_cst = build_int_cst (integer_type_node, 42); + ASSERT_FALSE (CAN_HAVE_LOCATION_P (int_cst)); + ASSERT_FALSE (location_wrapper_p (int_cst)); + + tree wrapped_int_cst = maybe_wrap_with_location (int_cst, loc); + ASSERT_TRUE (location_wrapper_p (wrapped_int_cst)); + ASSERT_EQ (loc, EXPR_LOCATION (wrapped_int_cst)); + + /* Wrapping a variable. */ + tree int_var = build_decl (UNKNOWN_LOCATION, VAR_DECL, + get_identifier ("some_int_var"), + integer_type_node); + ASSERT_FALSE (CAN_HAVE_LOCATION_P (int_var)); + ASSERT_FALSE (location_wrapper_p (int_var)); + + tree wrapped_int_var = maybe_wrap_with_location (int_var, loc); + ASSERT_TRUE (location_wrapper_p (wrapped_int_var)); + ASSERT_EQ (loc, EXPR_LOCATION (wrapped_int_var)); + + /* Verify that "reinterpret_cast<int>(some_int_var)" is not a location + wrapper. */ + tree r_cast = build1 (NON_LVALUE_EXPR, integer_type_node, int_var); + ASSERT_FALSE (location_wrapper_p (r_cast)); +} + /* Run all of the selftests within this file. */ void @@ -14024,6 +14089,7 @@ tree_c_tests () test_integer_constants (); test_identifiers (); test_labels (); + test_location_wrappers (); } } // namespace selftest diff --git a/gcc/tree.h b/gcc/tree.h index db67858..112471b 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -483,6 +483,15 @@ extern void omp_clause_range_check_failed (const_tree, const char *, int, #define STRIP_USELESS_TYPE_CONVERSION(EXP) \ (EXP) = tree_ssa_strip_useless_type_conversions (EXP) +/* Remove any VIEW_CONVERT_EXPR or NON_LVALUE_EXPR that's purely + in use to provide a location_t. */ + +#define STRIP_ANY_LOCATION_WRAPPER(EXP) \ + do { \ + if (location_wrapper_p (EXP)) \ + (EXP) = TREE_OPERAND ((EXP), 0); \ + } while (0) + /* Nonzero if TYPE represents a vector type. */ #define VECTOR_TYPE_P(TYPE) (TREE_CODE (TYPE) == VECTOR_TYPE) @@ -1146,6 +1155,8 @@ get_expr_source_range (tree expr) extern void protected_set_expr_location (tree, location_t); +extern tree maybe_wrap_with_location (tree, location_t); + /* In a TARGET_EXPR node. */ #define TARGET_EXPR_SLOT(NODE) TREE_OPERAND_CHECK_CODE (NODE, TARGET_EXPR, 0) #define TARGET_EXPR_INITIAL(NODE) TREE_OPERAND_CHECK_CODE (NODE, TARGET_EXPR, 1) @@ -3643,6 +3654,37 @@ id_equal (const char *str, const_tree id) return !strcmp (str, IDENTIFIER_POINTER (id)); } +/* Test if EXP is merely a wrapper node, added to express a location_t + on behalf of the node's child (e.g. by maybe_wrap_with_location). + + A wrapper node has code NON_LVALUE_EXPR or VIEW_CONVERT_EXPR, and the + same type as its operand. + + NON_LVALUE_EXPR is used for wrapping constants. + VIEW_CONVERT_EXPR is used for wrapping non-constants. + + A subtlety is that we have to test whether we have the correct + TREE_CODE for the wrapped TREE_CODE. Otherwise, e.g. the C++ expression: + reinterpret_cast<int>(some_int_var) + is a NON_LVALUE_EXPR around a non-constant of the same type, and + could thus be mischaracterized as a location wrapper node. + + Hence we need to check CONSTANT_CLASS_P (TREE_OPERAND (EXP, 0)) + and check for the corresponding NON_LVALUE_EXPR or VIEW_CONVERT_EXPR + for EXP to be a wrapper. */ + +inline bool location_wrapper_p (const_tree exp) +{ + if (((TREE_CODE (exp) == NON_LVALUE_EXPR + && CONSTANT_CLASS_P (TREE_OPERAND (exp, 0))) + || (TREE_CODE (exp) == VIEW_CONVERT_EXPR + && !CONSTANT_CLASS_P (TREE_OPERAND (exp, 0)))) + && (TREE_TYPE (exp) + == TREE_TYPE (TREE_OPERAND (exp, 0)))) + return true; + return false; +} + #define error_mark_node global_trees[TI_ERROR_MARK] #define intQI_type_node global_trees[TI_INTQI_TYPE] -- 1.8.5.3