> "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]