[PATCH, v2.2] Support for adding and stripping location_t wrapper nodes
David Malcolm
dmalcolm@redhat.com
Thu Nov 30 18:38:00 GMT 2017
On Thu, 2017-11-30 at 12:36 -0500, Jason Merrill wrote:
> On Thu, Nov 30, 2017 at 12:16 PM, David Malcolm <dmalcolm@redhat.com>
> wrote:
> > On Thu, 2017-11-16 at 10:58 +0100, Richard Biener wrote:
> > > On Wed, Nov 15, 2017 at 4:33 PM, David Malcolm <dmalcolm@redhat.c
> > > om>
> > > 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@tb
> > > > > saun
> > > > > 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.
>
> Note that STRIP_NOPS is now implemented in terms of such an inline
> function, it would make sense to do the same here.
FWIW STRIP_NOPS is currently:
#define STRIP_NOPS(EXP) \
(EXP) = tree_strip_nop_conversions (CONST_CAST_TREE (EXP))
and tree_strip_nop_conversions *isn't* inline.
But assuming I follow you, I've updated the new macro to be:
#define STRIP_ANY_LOCATION_WRAPPER(EXP) \
(EXP) = tree_strip_any_location_wrapper (CONST_CAST_TREE (EXP))
introducing a new inline tree_strip_any_location_wrapper.
> > > > > 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.
>
> Basically, we can only strip a NON_LVALUE_EXPR if the argument is
> already not an lvalue. We shouldn't need any extra check on
> VIEW_CONVERT_EXPR.
Aha. Thanks. I've updated location_wrapper_p accordingly and updated
its comment to read:
We don't need to check a VIEW_CONVERT_EXPR that wraps the same type
for !CONSTANT_CLASS_P; such instances of VIEW_CONVERT_EXPR are always
wrappers.
> > [...]
> >
> > 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 still like this approach.
>
> Jason
Thanks.
Here's a v2.2 of the patch.
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.
(tree_strip_any_location_wrapper): 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 | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
gcc/tree.h | 52 ++++++++++++++++++++++++++++++++++++++++++
3 files changed, 127 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..253d239 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,42 @@ 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));
+ ASSERT_EQ (int_cst, tree_strip_any_location_wrapper (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));
+ ASSERT_EQ (int_var, tree_strip_any_location_wrapper (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));
+ ASSERT_EQ (r_cast, tree_strip_any_location_wrapper (r_cast));
+}
+
/* Run all of the selftests within this file. */
void
@@ -14024,6 +14092,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..acb5883 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -483,6 +483,12 @@ 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) \
+ (EXP) = tree_strip_any_location_wrapper (CONST_CAST_TREE (EXP))
+
/* Nonzero if TYPE represents a vector type. */
#define VECTOR_TYPE_P(TYPE) (TREE_CODE (TYPE) == VECTOR_TYPE)
@@ -1146,6 +1152,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 +3651,50 @@ 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 may 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))
+ for a NON_LVALUE_EXPR for EXP to be a wrapper.
+ We don't need to check a VIEW_CONVERT_EXPR that wraps the same type
+ for !CONSTANT_CLASS_P; such instances of VIEW_CONVERT_EXPR are always
+ wrappers. */
+
+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)
+ && (TREE_TYPE (exp)
+ == TREE_TYPE (TREE_OPERAND (exp, 0))))
+ return true;
+ return false;
+}
+
+/* Implementation of STRIP_ANY_LOCATION_WRAPPER. */
+
+inline tree
+tree_strip_any_location_wrapper (tree exp)
+{
+ if (location_wrapper_p (exp))
+ return TREE_OPERAND (exp, 0);
+ else
+ return exp;
+}
+
#define error_mark_node global_trees[TI_ERROR_MARK]
#define intQI_type_node global_trees[TI_INTQI_TYPE]
--
1.8.5.3
More information about the Gcc-patches
mailing list