Skip to content
  • Pedro Alves's avatar
    -Wwrite-strings: Wrap PyGetSetDef for construction with string literals · 0d1f4ceb
    Pedro Alves authored
    Unfortunately, PyGetSetDef's 'name' and 'doc' members are 'char *'
    instead of 'const char *', meaning that in order to list-initialize
    PyGetSetDef arrays using string literals requires writing explicit
    'char *' casts.  For example:
    
        static PyGetSetDef value_object_getset[] = {
       -  { "address", valpy_get_address, NULL, "The address of the value.",
       +  { (char *) "address", valpy_get_address, NULL,
       +    (char *) "The address of the value.",
    	NULL },
       -  { "is_optimized_out", valpy_get_is_optimized_out, NULL,
       -    "Boolean telling whether the value is optimized "
       +  { (char *) "is_optimized_out", valpy_get_is_optimized_out, NULL,
       +    (char *) "Boolean telling whether the value is optimized "
    	"out (i.e., not available).",
    	NULL },
       -  { "type", valpy_get_type, NULL, "Type of the value.", NULL },
       -  { "dynamic_type", valpy_get_dynamic_type, NULL,
       -    "Dynamic type of the value.", NULL },
       -  { "is_lazy", valpy_get_is_lazy, NULL,
       -    "Boolean telling whether the value is lazy (not fetched yet\n\
       +  { (char *) "type", valpy_get_type, NULL,
       +    (char *) "Type of the value.", NULL },
       +  { (char *) "dynamic_type", valpy_get_dynamic_type, NULL,
       +    (char *) "Dynamic type of the value.", NULL },
       +  { (char *) "is_lazy", valpy_get_is_lazy, NULL,
       +    (char *) "Boolean telling whether the value is lazy (not fetched yet\n\
        from the inferior).  A lazy value is fetched when needed, or when\n\
        the \"fetch_lazy()\" method is called.", NULL },
          {NULL}  /* Sentinel */
    
    We have ~20 such arrays, and I first wrote a patch that fixed all of
    them like that...  It's not pretty...
    
    One way to make these a bit less ugly would be add a new macro that
    hides the casts, like:
    
      #define GDBPY_GSDEF(NAME, GET, SET, DOC, CLOSURE) \
         { (char *) NAME, GET, SET, (char *) DOC, CLOSURE }
    
    and then use it like:
    
        static PyGetSetDef value_object_getset[] = {
           GDBPY_GSDEF ("address", valpy_get_address, NULL,
           		    "The address of the value.", NULL),
           GDBPY_GSDEF ("is_optimized_out", valpy_get_is_optimized_out, NULL,
           		    "Boolean telling whether the value is optimized ", NULL),
          {NULL}  /* Sentinel */
        };
    
    But since we have C++11, which gives us constexpr and list
    initialization, I thought of a way that requires no changes where the
    arrays are initialized:
    
    We add a new type that extends PyGetSetDef (called gdb_PyGetSetDef),
    and add constexpr constructors that accept const 'name' and 'doc', and
    then list/aggregate initialization simply "calls" these matching
    constructors instead.
    
    I put "calls" in quotes, because given "constexpr", it's all done at
    compile time, and there's no overhead either in binary size or at run
    time.  In fact, we get identical binaries, before/after this change.
    
    Unlike the fixes that fix some old Python API to match the API of more
    recent Python, this switches to using explicit "gdb_PyGetSetDef"
    everywhere, just to be clear that we are using our own version of it.
    
    gdb/ChangeLog:
    2017-04-05  Pedro Alves  <palves@redhat.com>
    
    	* python/python-internal.h (gdb_PyGetSetDef): New type.
    	* python/py-block.c (block_object_getset)
    	(breakpoint_object_getset): Now a gdb_PyGetSetDef array.
    	* python/py-event.c (event_object_getset)
    	(finish_breakpoint_object_getset): Likewise.
    	* python/py-inferior.c (inferior_object_getset): Likewise.
    	* python/py-infthread.c (thread_object_getset): Likewise.
    	* python/py-lazy-string.c (lazy_string_object_getset): Likewise.
    	* python/py-linetable.c (linetable_entry_object_getset): Likewise.
    	* python/py-objfile.c (objfile_getset): Likewise.
    	* python/py-progspace.c (pspace_getset): Likewise.
    	* python/py-record-btrace.c (btpy_insn_getset, btpy_call_getset):
    	Likewise.
    	* python/py-record.c (recpy_record_getset): Likewise.
    	* python/py-symbol.c (symbol_object_getset): Likewise.
    	* python/py-symtab.c (symtab_object_getset, sal_object_getset):
    	Likewise.
    	* python/py-type.c (type_object_getset, field_object_getset):
    	Likewise.
    	* python/py-value.c (value_object_getset): Likewise.
    0d1f4ceb