> "Kaveh R. Ghazi" <[EMAIL PROTECTED]> writes:
 > 
 > [...]
 > 
 > | I'd like to do for tree and rtx what I did for const char *,
 > | namely constify those tree/rtx functions that aren't supposed to
 > | modify their arguments.  This would require introducing the
 > | const_tree and const_rtx typedefs Tristan suggested.
 > 
 > Yes, totally agreed -- that would be more profitable.
 > -- Gaby

So I tried a quick start on const_tree, etc to see if there would be
any problems and found one.  The issue is the definition of the
TREE_CHECK macro when using gcc and checking is enabled, i.e.:

#define TREE_CHECK(T, CODE) __extension__ \
({  const tree __t = (T); \
    if (TREE_CODE (__t) != (CODE)) \
      tree_check_failed (__t, __FILE__, __LINE__, __FUNCTION__, (CODE), 0); \
    __t; })

Now imagine if I change the type of __t to const_tree like so:

typedef const union tree_node *const_tree;
#define TREE_CHECK(T, CODE) __extension__ \
({  const_tree const __t = (T); \
    if (TREE_CODE (__t) != (CODE)) \
      tree_check_failed (__t, __FILE__, __LINE__, __FUNCTION__, (CODE), 0); \
    __t; })

(And also assume that tree_check_failed() has had its first parameter
constified.)

Now the problem is that the statement expression in the TREE_CHECK
macro uses __t as it's "return value".  The TREE_CHECK macro is used
in both read and write situations of tree members.  So the "return
value" of this statement expression cannot be const or all the write
cases barf.

We may need two versions of this macro, a TREE_CHECK and a
CONST_TREE_CHECK, and we would have to create duplicate tree accessors
that use one or the other.  But that would require modifying the gcc
sources at every invocation of tree accesses to call an appropriate
macro depending on whether the intended operation was read or write.
Yuck.

Another easier solution would be to cast away the const-ness of __t
when returning like so:

typedef const union tree_node *const_tree;
#define TREE_CHECK(T, CODE) __extension__ \
({  const_tree const __t = (T); \
    if (TREE_CODE (__t) != (CODE)) \
      tree_check_failed (__t, __FILE__, __LINE__, __FUNCTION__, (CODE), 0); \
    (tree)__t; })


But this defeats the purpose of using const.  (It's sort of like using
strchr's return value, not const-safe.)  It will also generate
gillions of -Wcast-qual warnings if you add that flag.

Another solution might be to use the macro parameter as the return
type like so:

typedef const union tree_node *const_tree;
#define TREE_CHECK(T, CODE) __extension__ \
({  const_tree const __t = (T); \
    if (TREE_CODE (__t) != (CODE)) \
      tree_check_failed (__t, __FILE__, __LINE__, __FUNCTION__, (CODE), 0); \
    (T); })

Then if "T" isn't already const you can write to it.  But this
evaluates "T" twice so if there are side-effects potentially we get
hosed.


I guess I'm looking for something like how C++ lets you overload
functions based on const-ness of a parameter and change the
return-type's const-ness respectively.  Someone once told me C++
should have had two "strchr" functions.

        extern const char *strchr(const char *, int);
        extern char *strchr(char *, int);

Note the non-gcc non-checking TREE_CHECK macros are fine because they
just evaluate to the tree parameter "T" and do nothing.  So their
const-ness just works.  That means we're free to use gcc extensions to
work around this in the checking-enabled version of the macros.

Any ideas?

                Thanks,
                --Kaveh
--
Kaveh R. Ghazi                  [EMAIL PROTECTED]

Reply via email to