PR libstdc++/80276 fix template argument handling in type printers
PR libstdc++/80276 * python/libstdcxx/v6/printers.py (strip_inline_namespaces): New. (get_template_arg_list): New. (StdVariantPrinter._template_args): Remove, use get_template_arg_list instead. (TemplateTypePrinter): Rewrite to work with gdb.Type objects instead of strings and regular expressions. (add_one_template_type_printer): Adapt to new TemplateTypePrinter. (FilteringTypePrinter): Add docstring. Match using startswith. Use strip_inline_namespaces instead of strip_versioned_namespace. (add_one_type_printer): Prepend namespace to match argument. (register_type_printers): Add type printers for char16_t and char32_t string types and for types using cxx11 ABI. Update calls to add_one_template_type_printer to provide default argument dicts. * testsuite/libstdc++-prettyprinters/80276.cc: New test. * testsuite/libstdc++-prettyprinters/whatis.cc: Remove tests for basic_string<unsigned char> and basic_string<signed char>. * testsuite/libstdc++-prettyprinters/whatis2.cc: Duplicate whatis.cc to test local variables, without overriding _GLIBCXX_USE_CXX11_ABI. From-SVN: r256689
This commit is contained in:
parent
ed99ae13bb
commit
bab0a26de5
|
@ -1,3 +1,25 @@
|
|||
2018-01-15 Jonathan Wakely <jwakely@redhat.com>
|
||||
|
||||
PR libstdc++/80276
|
||||
* python/libstdcxx/v6/printers.py (strip_inline_namespaces): New.
|
||||
(get_template_arg_list): New.
|
||||
(StdVariantPrinter._template_args): Remove, use get_template_arg_list
|
||||
instead.
|
||||
(TemplateTypePrinter): Rewrite to work with gdb.Type objects instead
|
||||
of strings and regular expressions.
|
||||
(add_one_template_type_printer): Adapt to new TemplateTypePrinter.
|
||||
(FilteringTypePrinter): Add docstring. Match using startswith. Use
|
||||
strip_inline_namespaces instead of strip_versioned_namespace.
|
||||
(add_one_type_printer): Prepend namespace to match argument.
|
||||
(register_type_printers): Add type printers for char16_t and char32_t
|
||||
string types and for types using cxx11 ABI. Update calls to
|
||||
add_one_template_type_printer to provide default argument dicts.
|
||||
* testsuite/libstdc++-prettyprinters/80276.cc: New test.
|
||||
* testsuite/libstdc++-prettyprinters/whatis.cc: Remove tests for
|
||||
basic_string<unsigned char> and basic_string<signed char>.
|
||||
* testsuite/libstdc++-prettyprinters/whatis2.cc: Duplicate whatis.cc
|
||||
to test local variables, without overriding _GLIBCXX_USE_CXX11_ABI.
|
||||
|
||||
2018-01-14 Andreas Schwab <schwab@linux-m68k.org>
|
||||
|
||||
PR libstdc++/81092
|
||||
|
|
|
@ -101,8 +101,8 @@ def find_type(orig, name):
|
|||
|
||||
_versioned_namespace = '__8::'
|
||||
|
||||
# Test if a type is a given template instantiation.
|
||||
def is_specialization_of(type, template_name):
|
||||
"Test if a type is a given template instantiation."
|
||||
global _versioned_namespace
|
||||
if _versioned_namespace:
|
||||
return re.match('^std::(%s)?%s<.*>$' % (_versioned_namespace, template_name), type) is not None
|
||||
|
@ -114,6 +114,28 @@ def strip_versioned_namespace(typename):
|
|||
return typename.replace(_versioned_namespace, '')
|
||||
return typename
|
||||
|
||||
def strip_inline_namespaces(type_str):
|
||||
"Remove known inline namespaces from the canonical name of a type."
|
||||
type_str = strip_versioned_namespace(type_str)
|
||||
type_str = type_str.replace('std::__cxx11::', 'std::')
|
||||
expt_ns = 'std::experimental::'
|
||||
for lfts_ns in ('fundamentals_v1', 'fundamentals_v2'):
|
||||
type_str = type_str.replace(expt_ns+lfts_ns+'::', expt_ns)
|
||||
fs_ns = expt_ns + 'filesystem::'
|
||||
type_str = type_str.replace(fs_ns+'v1::', fs_ns)
|
||||
return type_str
|
||||
|
||||
def get_template_arg_list(type_obj):
|
||||
"Return a type's template arguments as a list"
|
||||
n = 0
|
||||
template_args = []
|
||||
while True:
|
||||
try:
|
||||
template_args.append(type_obj.template_argument(n))
|
||||
except:
|
||||
return template_args
|
||||
n += 1
|
||||
|
||||
class SmartPtrIterator(Iterator):
|
||||
"An iterator for smart pointer types with a single 'child' value"
|
||||
|
||||
|
@ -1063,7 +1085,7 @@ class StdVariantPrinter(SingleObjContainerPrinter):
|
|||
"Print a std::variant"
|
||||
|
||||
def __init__(self, typename, val):
|
||||
alternatives = self._template_args(val)
|
||||
alternatives = get_template_arg_list(val.type)
|
||||
self.typename = strip_versioned_namespace(typename)
|
||||
self.typename = "%s<%s>" % (self.typename, ', '.join([self._recognize(alt) for alt in alternatives]))
|
||||
self.index = val['_M_index']
|
||||
|
@ -1078,17 +1100,6 @@ class StdVariantPrinter(SingleObjContainerPrinter):
|
|||
visualizer = gdb.default_visualizer(contained_value)
|
||||
super (StdVariantPrinter, self).__init__(contained_value, visualizer, 'array')
|
||||
|
||||
@staticmethod
|
||||
def _template_args(val):
|
||||
n = 0
|
||||
args = []
|
||||
while True:
|
||||
try:
|
||||
args.append(val.type.template_argument(n))
|
||||
except:
|
||||
return args
|
||||
n += 1
|
||||
|
||||
def to_string(self):
|
||||
if self.contained_value is None:
|
||||
return "%s [no contained value]" % self.typename
|
||||
|
@ -1294,84 +1305,168 @@ libstdcxx_printer = None
|
|||
|
||||
class TemplateTypePrinter(object):
|
||||
r"""
|
||||
A type printer for class templates.
|
||||
A type printer for class templates with default template arguments.
|
||||
|
||||
Recognizes type names that match a regular expression.
|
||||
Replaces them with a formatted string which can use replacement field
|
||||
{N} to refer to the \N subgroup of the regex match.
|
||||
Type printers are recusively applied to the subgroups.
|
||||
Recognizes specializations of class templates and prints them without
|
||||
any template arguments that use a default template argument.
|
||||
Type printers are recursively applied to the template arguments.
|
||||
|
||||
This allows recognizing e.g. "std::vector<(.*), std::allocator<\\1> >"
|
||||
and replacing it with "std::vector<{1}>", omitting the template argument
|
||||
that uses the default type.
|
||||
e.g. replace "std::vector<T, std::allocator<T> >" with "std::vector<T>".
|
||||
"""
|
||||
|
||||
def __init__(self, name, pattern, subst):
|
||||
def __init__(self, name, defargs):
|
||||
self.name = name
|
||||
self.pattern = re.compile(pattern)
|
||||
self.subst = subst
|
||||
self.defargs = defargs
|
||||
self.enabled = True
|
||||
|
||||
class _recognizer(object):
|
||||
def __init__(self, pattern, subst):
|
||||
self.pattern = pattern
|
||||
self.subst = subst
|
||||
self.type_obj = None
|
||||
"The recognizer class for TemplateTypePrinter."
|
||||
|
||||
def __init__(self, name, defargs):
|
||||
self.name = name
|
||||
self.defargs = defargs
|
||||
# self.type_obj = None
|
||||
|
||||
def recognize(self, type_obj):
|
||||
"""
|
||||
If type_obj is a specialization of self.name that uses all the
|
||||
default template arguments for the class template, then return
|
||||
a string representation of the type without default arguments.
|
||||
Otherwise, return None.
|
||||
"""
|
||||
|
||||
if type_obj.tag is None:
|
||||
return None
|
||||
|
||||
m = self.pattern.match(type_obj.tag)
|
||||
if m:
|
||||
subs = list(m.groups())
|
||||
for i, sub in enumerate(subs):
|
||||
if ('{%d}' % (i+1)) in self.subst:
|
||||
# apply recognizers to subgroup
|
||||
try:
|
||||
subtype = gdb.lookup_type(sub)
|
||||
except gdb.error:
|
||||
continue
|
||||
rep = gdb.types.apply_type_recognizers(
|
||||
gdb.types.get_type_recognizers(),
|
||||
subtype)
|
||||
if rep:
|
||||
subs[i] = rep
|
||||
subs = [None] + subs
|
||||
return self.subst.format(*subs)
|
||||
return None
|
||||
if not type_obj.tag.startswith(self.name):
|
||||
return None
|
||||
|
||||
template_args = get_template_arg_list(type_obj)
|
||||
displayed_args = []
|
||||
require_defaulted = False
|
||||
for n in range(len(template_args)):
|
||||
# The actual template argument in the type:
|
||||
targ = template_args[n]
|
||||
# The default template argument for the class template:
|
||||
defarg = self.defargs.get(n)
|
||||
if defarg is not None:
|
||||
# Substitute other template arguments into the default:
|
||||
defarg = defarg.format(*template_args)
|
||||
# Fail to recognize the type (by returning None)
|
||||
# unless the actual argument is the same as the default.
|
||||
try:
|
||||
if targ != gdb.lookup_type(defarg):
|
||||
return None
|
||||
except gdb.error:
|
||||
# Type lookup failed, just use string comparison:
|
||||
if targ.tag != defarg:
|
||||
return None
|
||||
# All subsequent args must have defaults:
|
||||
require_defaulted = True
|
||||
elif require_defaulted:
|
||||
return None
|
||||
else:
|
||||
# Recursively apply recognizers to the template argument
|
||||
# and add it to the arguments that will be displayed:
|
||||
displayed_args.append(self._recognize_subtype(targ))
|
||||
|
||||
# This assumes no class templates in the nested-name-specifier:
|
||||
template_name = type_obj.tag[0:type_obj.tag.find('<')]
|
||||
template_name = strip_inline_namespaces(template_name)
|
||||
|
||||
return template_name + '<' + ', '.join(displayed_args) + '>'
|
||||
|
||||
def _recognize_subtype(self, type_obj):
|
||||
"""Convert a gdb.Type to a string by applying recognizers,
|
||||
or if that fails then simply converting to a string."""
|
||||
|
||||
if type_obj.code == gdb.TYPE_CODE_PTR:
|
||||
return self._recognize_subtype(type_obj.target()) + '*'
|
||||
if type_obj.code == gdb.TYPE_CODE_ARRAY:
|
||||
type_str = self._recognize_subtype(type_obj.target())
|
||||
if str(type_obj.strip_typedefs()).endswith('[]'):
|
||||
return type_str + '[]' # array of unknown bound
|
||||
return "%s[%d]" % (type_str, type_obj.range()[1] + 1)
|
||||
if type_obj.code == gdb.TYPE_CODE_REF:
|
||||
return self._recognize_subtype(type_obj.target()) + '&'
|
||||
if hasattr(gdb, 'TYPE_CODE_RVALUE_REF'):
|
||||
if type_obj.code == gdb.TYPE_CODE_RVALUE_REF:
|
||||
return self._recognize_subtype(type_obj.target()) + '&&'
|
||||
|
||||
type_str = gdb.types.apply_type_recognizers(
|
||||
gdb.types.get_type_recognizers(), type_obj)
|
||||
if type_str:
|
||||
return type_str
|
||||
return str(type_obj)
|
||||
|
||||
def instantiate(self):
|
||||
return self._recognizer(self.pattern, self.subst)
|
||||
"Return a recognizer object for this type printer."
|
||||
return self._recognizer(self.name, self.defargs)
|
||||
|
||||
def add_one_template_type_printer(obj, name, match, subst):
|
||||
match = '^std::' + match + '$'
|
||||
printer = TemplateTypePrinter(name, match, 'std::' + subst)
|
||||
def add_one_template_type_printer(obj, name, defargs):
|
||||
r"""
|
||||
Add a type printer for a class template with default template arguments.
|
||||
|
||||
Args:
|
||||
name (str): The template-name of the class template.
|
||||
defargs (dict int:string) The default template arguments.
|
||||
|
||||
Types in defargs can refer to the Nth template-argument using {N}
|
||||
(with zero-based indices).
|
||||
|
||||
e.g. 'unordered_map' has these defargs:
|
||||
{ 2: 'std::hash<{0}>',
|
||||
3: 'std::equal_to<{0}>',
|
||||
4: 'std::allocator<std::pair<const {0}, {1}> >' }
|
||||
|
||||
"""
|
||||
printer = TemplateTypePrinter('std::'+name, defargs)
|
||||
gdb.types.register_type_printer(obj, printer)
|
||||
if _versioned_namespace:
|
||||
# Add second type printer for same type in versioned namespace:
|
||||
match = match.replace('std::', 'std::' + _versioned_namespace)
|
||||
printer = TemplateTypePrinter(name, match, 'std::' + subst)
|
||||
ns = 'std::' + _versioned_namespace
|
||||
defargs = { n: d.replace('std::', ns) for n,d in defargs.items() }
|
||||
printer = TemplateTypePrinter(ns+name, defargs)
|
||||
gdb.types.register_type_printer(obj, printer)
|
||||
|
||||
class FilteringTypePrinter(object):
|
||||
r"""
|
||||
A type printer that uses typedef names for common template specializations.
|
||||
|
||||
Args:
|
||||
match (str): The class template to recognize.
|
||||
name (str): The typedef-name that will be used instead.
|
||||
|
||||
Checks if a specialization of the class template 'match' is the same type
|
||||
as the typedef 'name', and prints it as 'name' instead.
|
||||
|
||||
e.g. if an instantiation of std::basic_istream<C, T> is the same type as
|
||||
std::istream then print it as std::istream.
|
||||
"""
|
||||
|
||||
def __init__(self, match, name):
|
||||
self.match = match
|
||||
self.name = name
|
||||
self.enabled = True
|
||||
|
||||
class _recognizer(object):
|
||||
"The recognizer class for TemplateTypePrinter."
|
||||
|
||||
def __init__(self, match, name):
|
||||
self.match = match
|
||||
self.name = name
|
||||
self.type_obj = None
|
||||
|
||||
def recognize(self, type_obj):
|
||||
"""
|
||||
If type_obj starts with self.match and is the same type as
|
||||
self.name then return self.name, otherwise None.
|
||||
"""
|
||||
if type_obj.tag is None:
|
||||
return None
|
||||
|
||||
if self.type_obj is None:
|
||||
if not self.match in type_obj.tag:
|
||||
if not type_obj.tag.startswith(self.match):
|
||||
# Filter didn't match.
|
||||
return None
|
||||
try:
|
||||
|
@ -1379,17 +1474,19 @@ class FilteringTypePrinter(object):
|
|||
except:
|
||||
pass
|
||||
if self.type_obj == type_obj:
|
||||
return strip_versioned_namespace(self.name)
|
||||
return strip_inline_namespaces(self.name)
|
||||
return None
|
||||
|
||||
def instantiate(self):
|
||||
"Return a recognizer object for this type printer."
|
||||
return self._recognizer(self.match, self.name)
|
||||
|
||||
def add_one_type_printer(obj, match, name):
|
||||
printer = FilteringTypePrinter(match, 'std::' + name)
|
||||
printer = FilteringTypePrinter('std::' + match, 'std::' + name)
|
||||
gdb.types.register_type_printer(obj, printer)
|
||||
if _versioned_namespace:
|
||||
printer = FilteringTypePrinter(match, 'std::' + _versioned_namespace + name)
|
||||
ns = 'std::' + _versioned_namespace
|
||||
printer = FilteringTypePrinter(ns + match, ns + name)
|
||||
gdb.types.register_type_printer(obj, printer)
|
||||
|
||||
def register_type_printers(obj):
|
||||
|
@ -1398,50 +1495,43 @@ def register_type_printers(obj):
|
|||
if not _use_type_printing:
|
||||
return
|
||||
|
||||
for pfx in ('', 'w'):
|
||||
add_one_type_printer(obj, 'basic_string', pfx + 'string')
|
||||
add_one_type_printer(obj, 'basic_string_view', pfx + 'string_view')
|
||||
add_one_type_printer(obj, 'basic_ios', pfx + 'ios')
|
||||
add_one_type_printer(obj, 'basic_streambuf', pfx + 'streambuf')
|
||||
add_one_type_printer(obj, 'basic_istream', pfx + 'istream')
|
||||
add_one_type_printer(obj, 'basic_ostream', pfx + 'ostream')
|
||||
add_one_type_printer(obj, 'basic_iostream', pfx + 'iostream')
|
||||
add_one_type_printer(obj, 'basic_stringbuf', pfx + 'stringbuf')
|
||||
add_one_type_printer(obj, 'basic_istringstream',
|
||||
pfx + 'istringstream')
|
||||
add_one_type_printer(obj, 'basic_ostringstream',
|
||||
pfx + 'ostringstream')
|
||||
add_one_type_printer(obj, 'basic_stringstream',
|
||||
pfx + 'stringstream')
|
||||
add_one_type_printer(obj, 'basic_filebuf', pfx + 'filebuf')
|
||||
add_one_type_printer(obj, 'basic_ifstream', pfx + 'ifstream')
|
||||
add_one_type_printer(obj, 'basic_ofstream', pfx + 'ofstream')
|
||||
add_one_type_printer(obj, 'basic_fstream', pfx + 'fstream')
|
||||
add_one_type_printer(obj, 'basic_regex', pfx + 'regex')
|
||||
add_one_type_printer(obj, 'sub_match', pfx + 'csub_match')
|
||||
add_one_type_printer(obj, 'sub_match', pfx + 'ssub_match')
|
||||
add_one_type_printer(obj, 'match_results', pfx + 'cmatch')
|
||||
add_one_type_printer(obj, 'match_results', pfx + 'smatch')
|
||||
add_one_type_printer(obj, 'regex_iterator', pfx + 'cregex_iterator')
|
||||
add_one_type_printer(obj, 'regex_iterator', pfx + 'sregex_iterator')
|
||||
add_one_type_printer(obj, 'regex_token_iterator',
|
||||
pfx + 'cregex_token_iterator')
|
||||
add_one_type_printer(obj, 'regex_token_iterator',
|
||||
pfx + 'sregex_token_iterator')
|
||||
# Add type printers for typedefs std::string, std::wstring etc.
|
||||
for ch in ('', 'w', 'u16', 'u32'):
|
||||
add_one_type_printer(obj, 'basic_string', ch + 'string')
|
||||
add_one_type_printer(obj, '__cxx11::basic_string',
|
||||
'__cxx11::' + ch + 'string')
|
||||
add_one_type_printer(obj, 'basic_string_view', ch + 'string_view')
|
||||
|
||||
# Add type printers for typedefs std::istream, std::wistream etc.
|
||||
for ch in ('', 'w'):
|
||||
for x in ('ios', 'streambuf', 'istream', 'ostream', 'iostream',
|
||||
'filebuf', 'ifstream', 'ofstream', 'fstream'):
|
||||
add_one_type_printer(obj, 'basic_' + x, ch + x)
|
||||
for x in ('stringbuf', 'istringstream', 'ostringstream',
|
||||
'stringstream'):
|
||||
add_one_type_printer(obj, 'basic_' + x, ch + x)
|
||||
# <sstream> types are in __cxx11 namespace, but typedefs aren'x:
|
||||
add_one_type_printer(obj, '__cxx11::basic_' + x, ch + x)
|
||||
|
||||
# Add type printers for typedefs regex, wregex, cmatch, wcmatch etc.
|
||||
for abi in ('', '__cxx11::'):
|
||||
for ch in ('', 'w'):
|
||||
add_one_type_printer(obj, abi + 'basic_regex', abi + ch + 'regex')
|
||||
for ch in ('c', 's', 'wc', 'ws'):
|
||||
add_one_type_printer(obj, abi + 'match_results', abi + ch + 'match')
|
||||
for x in ('sub_match', 'regex_iterator', 'regex_token_iterator'):
|
||||
add_one_type_printer(obj, abi + x, abi + ch + x)
|
||||
|
||||
# Note that we can't have a printer for std::wstreampos, because
|
||||
# it shares the same underlying type as std::streampos.
|
||||
# it is the same type as std::streampos.
|
||||
add_one_type_printer(obj, 'fpos', 'streampos')
|
||||
|
||||
add_one_type_printer(obj, 'basic_string', 'u16string')
|
||||
add_one_type_printer(obj, 'basic_string', 'u32string')
|
||||
add_one_type_printer(obj, 'basic_string_view', 'u16string_view')
|
||||
add_one_type_printer(obj, 'basic_string_view', 'u32string_view')
|
||||
|
||||
# Add type printers for <chrono> typedefs.
|
||||
for dur in ('nanoseconds', 'microseconds', 'milliseconds',
|
||||
'seconds', 'minutes', 'hours'):
|
||||
add_one_type_printer(obj, 'duration', dur)
|
||||
|
||||
# Add type printers for <random> typedefs.
|
||||
add_one_type_printer(obj, 'linear_congruential_engine', 'minstd_rand0')
|
||||
add_one_type_printer(obj, 'linear_congruential_engine', 'minstd_rand')
|
||||
add_one_type_printer(obj, 'mersenne_twister_engine', 'mt19937')
|
||||
|
@ -1452,62 +1542,46 @@ def register_type_printers(obj):
|
|||
add_one_type_printer(obj, 'discard_block_engine', 'ranlux48')
|
||||
add_one_type_printer(obj, 'shuffle_order_engine', 'knuth_b')
|
||||
|
||||
# Do not show defaulted template arguments in class templates
|
||||
add_one_template_type_printer(obj, 'unique_ptr<T>',
|
||||
'unique_ptr<(.*), std::default_delete<\\1 ?> >',
|
||||
'unique_ptr<{1}>')
|
||||
# Add type printers for experimental::basic_string_view typedefs.
|
||||
ns = 'experimental::fundamentals_v1::'
|
||||
for ch in ('', 'w', 'u16', 'u32'):
|
||||
add_one_type_printer(obj, ns + 'basic_string_view',
|
||||
ns + ch + 'string_view')
|
||||
|
||||
add_one_template_type_printer(obj, 'basic_string<T>',
|
||||
'basic_string<((un)?signed char), std::char_traits<\\1 ?>, std::allocator<\\1 ?> >',
|
||||
'basic_string<{1}>')
|
||||
|
||||
add_one_template_type_printer(obj, 'deque<T>',
|
||||
'deque<(.*), std::allocator<\\1 ?> >',
|
||||
'deque<{1}>')
|
||||
add_one_template_type_printer(obj, 'forward_list<T>',
|
||||
'forward_list<(.*), std::allocator<\\1 ?> >',
|
||||
'forward_list<{1}>')
|
||||
add_one_template_type_printer(obj, 'list<T>',
|
||||
'list<(.*), std::allocator<\\1 ?> >',
|
||||
'list<{1}>')
|
||||
add_one_template_type_printer(obj, 'vector<T>',
|
||||
'vector<(.*), std::allocator<\\1 ?> >',
|
||||
'vector<{1}>')
|
||||
add_one_template_type_printer(obj, 'map<Key, T>',
|
||||
'map<(.*), (.*), std::less<\\1 ?>, std::allocator<std::pair<\\1 const, \\2 ?> > >',
|
||||
'map<{1}, {2}>')
|
||||
add_one_template_type_printer(obj, 'multimap<Key, T>',
|
||||
'multimap<(.*), (.*), std::less<\\1 ?>, std::allocator<std::pair<\\1 const, \\2 ?> > >',
|
||||
'multimap<{1}, {2}>')
|
||||
add_one_template_type_printer(obj, 'set<T>',
|
||||
'set<(.*), std::less<\\1 ?>, std::allocator<\\1 ?> >',
|
||||
'set<{1}>')
|
||||
add_one_template_type_printer(obj, 'multiset<T>',
|
||||
'multiset<(.*), std::less<\\1 ?>, std::allocator<\\1 ?> >',
|
||||
'multiset<{1}>')
|
||||
add_one_template_type_printer(obj, 'unordered_map<Key, T>',
|
||||
'unordered_map<(.*), (.*), std::hash<\\1 ?>, std::equal_to<\\1 ?>, std::allocator<std::pair<\\1 const, \\2 ?> > >',
|
||||
'unordered_map<{1}, {2}>')
|
||||
add_one_template_type_printer(obj, 'unordered_multimap<Key, T>',
|
||||
'unordered_multimap<(.*), (.*), std::hash<\\1 ?>, std::equal_to<\\1 ?>, std::allocator<std::pair<\\1 const, \\2 ?> > >',
|
||||
'unordered_multimap<{1}, {2}>')
|
||||
add_one_template_type_printer(obj, 'unordered_set<T>',
|
||||
'unordered_set<(.*), std::hash<\\1 ?>, std::equal_to<\\1 ?>, std::allocator<\\1 ?> >',
|
||||
'unordered_set<{1}>')
|
||||
add_one_template_type_printer(obj, 'unordered_multiset<T>',
|
||||
'unordered_multiset<(.*), std::hash<\\1 ?>, std::equal_to<\\1 ?>, std::allocator<\\1 ?> >',
|
||||
'unordered_multiset<{1}>')
|
||||
|
||||
# strip the "fundamentals_v1" inline namespace from these types
|
||||
add_one_template_type_printer(obj, 'any<T>',
|
||||
'experimental::fundamentals_v\d::any<(.*)>',
|
||||
'experimental::any<\\1>')
|
||||
add_one_template_type_printer(obj, 'optional<T>',
|
||||
'experimental::fundamentals_v\d::optional<(.*)>',
|
||||
'experimental::optional<\\1>')
|
||||
add_one_template_type_printer(obj, 'basic_string_view<C>',
|
||||
'experimental::fundamentals_v\d::basic_string_view<(.*), std::char_traits<\\1> >',
|
||||
'experimental::basic_string_view<\\1>')
|
||||
# Do not show defaulted template arguments in class templates.
|
||||
add_one_template_type_printer(obj, 'unique_ptr',
|
||||
{ 1: 'std::default_delete<{0}>' })
|
||||
add_one_template_type_printer(obj, 'deque', { 1: 'std::allocator<{0}>'})
|
||||
add_one_template_type_printer(obj, 'forward_list', { 1: 'std::allocator<{0}>'})
|
||||
add_one_template_type_printer(obj, 'list', { 1: 'std::allocator<{0}>'})
|
||||
add_one_template_type_printer(obj, '__cxx11::list', { 1: 'std::allocator<{0}>'})
|
||||
add_one_template_type_printer(obj, 'vector', { 1: 'std::allocator<{0}>'})
|
||||
add_one_template_type_printer(obj, 'map',
|
||||
{ 2: 'std::less<{0}>',
|
||||
3: 'std::allocator<std::pair<{0} const, {1}>>' })
|
||||
add_one_template_type_printer(obj, 'multimap',
|
||||
{ 2: 'std::less<{0}>',
|
||||
3: 'std::allocator<std::pair<{0} const, {1}>>' })
|
||||
add_one_template_type_printer(obj, 'set',
|
||||
{ 1: 'std::less<{0}>', 2: 'std::allocator<{0}>' })
|
||||
add_one_template_type_printer(obj, 'multiset',
|
||||
{ 1: 'std::less<{0}>', 2: 'std::allocator<{0}>' })
|
||||
add_one_template_type_printer(obj, 'unordered_map',
|
||||
{ 2: 'std::hash<{0}>',
|
||||
3: 'std::equal_to<{0}>',
|
||||
4: 'std::allocator<std::pair<{0} const, {1}>>'})
|
||||
add_one_template_type_printer(obj, 'unordered_multimap',
|
||||
{ 2: 'std::hash<{0}>',
|
||||
3: 'std::equal_to<{0}>',
|
||||
4: 'std::allocator<std::pair<{0} const, {1}>>'})
|
||||
add_one_template_type_printer(obj, 'unordered_set',
|
||||
{ 1: 'std::hash<{0}>',
|
||||
2: 'std::equal_to<{0}>',
|
||||
3: 'std::allocator<{0}>'})
|
||||
add_one_template_type_printer(obj, 'unordered_multiset',
|
||||
{ 1: 'std::hash<{0}>',
|
||||
2: 'std::equal_to<{0}>',
|
||||
3: 'std::allocator<{0}>'})
|
||||
|
||||
def register_libstdcxx_printers (obj):
|
||||
"Register libstdc++ pretty-printers with objfile Obj."
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
// { dg-do run { target c++11 } }
|
||||
// { dg-options "-g -O0" }
|
||||
// { dg-skip-if "" { *-*-* } { "-D_GLIBCXX_PROFILE" } }
|
||||
|
||||
// Copyright (C) 2018 Free Software Foundation, Inc.
|
||||
//
|
||||
// This file is part of the GNU ISO C++ Library. This library is free
|
||||
// software; you can redistribute it and/or modify it under the
|
||||
// terms of the GNU General Public License as published by the
|
||||
// Free Software Foundation; either version 3, or (at your option)
|
||||
// any later version.
|
||||
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License along
|
||||
// with this library; see the file COPYING3. If not see
|
||||
// <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include <iostream>
|
||||
#include <list>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
template<class T>
|
||||
void
|
||||
placeholder(const T *s)
|
||||
{
|
||||
std::cout << (void *) s;
|
||||
}
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
using namespace std;
|
||||
unique_ptr<vector<unique_ptr<vector<int>*>>> p1;
|
||||
unique_ptr<vector<unique_ptr<set<int>*>>[]> p2;
|
||||
unique_ptr<set<unique_ptr<vector<int>*>>[10]> p3;
|
||||
unique_ptr<vector<unique_ptr<list<std::string>[]>>[99]> p4;
|
||||
// { dg-final { whatis-test p1 "std::unique_ptr<std::vector<std::unique_ptr<std::vector<int>*>>>" } }
|
||||
// { dg-final { whatis-test p2 "std::unique_ptr<std::vector<std::unique_ptr<std::set<int>*>>\[\]>" } }
|
||||
// { dg-final { whatis-test p3 "std::unique_ptr<std::set<std::unique_ptr<std::vector<int>*>>\[10\]>" } }
|
||||
// { dg-final { whatis-test p4 "std::unique_ptr<std::vector<std::unique_ptr<std::list<std::string>\[\]>>\[99\]>" } }
|
||||
|
||||
placeholder(&p1); // Mark SPOT
|
||||
placeholder(&p2);
|
||||
placeholder(&p3);
|
||||
placeholder(&p4);
|
||||
|
||||
std::cout << "\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
// { dg-final { gdb-test SPOT } }
|
|
@ -19,7 +19,8 @@
|
|||
// with this library; see the file COPYING3. If not see
|
||||
// <http://www.gnu.org/licenses/>.
|
||||
|
||||
// Type printers only recognize the old std::string for now.
|
||||
// GDB can't find global variables using the abi_tag attribute.
|
||||
// https://sourceware.org/bugzilla/show_bug.cgi?id=19436
|
||||
#define _GLIBCXX_USE_CXX11_ABI 0
|
||||
|
||||
#include <string>
|
||||
|
@ -49,8 +50,6 @@ struct holder
|
|||
T *f;
|
||||
};
|
||||
|
||||
typedef std::basic_string<unsigned char> ustring;
|
||||
|
||||
// This test is written in a somewhat funny way.
|
||||
// Each type under test is used twice: first, to form a pointer type,
|
||||
// and second, as a template parameter. This is done to work around
|
||||
|
@ -165,14 +164,6 @@ std::knuth_b *knuth_b_ptr;
|
|||
holder<std::knuth_b> knuth_b_holder;
|
||||
// { dg-final { whatis-test knuth_b_holder "holder<std::knuth_b>" } }
|
||||
|
||||
ustring *ustring_ptr;
|
||||
holder<ustring> ustring_holder;
|
||||
// { dg-final { whatis-test ustring_holder "holder<std::basic_string<unsigned char> >" } }
|
||||
|
||||
std::basic_string<signed char> *sstring_ptr;
|
||||
holder< std::basic_string<signed char> > sstring_holder;
|
||||
// { dg-final { whatis-test sstring_holder "holder<std::basic_string<signed char> >" } }
|
||||
|
||||
std::vector<std::deque<std::unique_ptr<char>>> *seq1_ptr;
|
||||
holder< std::vector<std::deque<std::unique_ptr<char>>> > seq1_holder;
|
||||
// { dg-final { whatis-test seq1_holder "holder<std::vector<std::deque<std::unique_ptr<char>>> >" } }
|
||||
|
@ -271,10 +262,6 @@ main()
|
|||
placeholder(&ranlux48_holder);
|
||||
placeholder(&knuth_b_ptr);
|
||||
placeholder(&knuth_b_holder);
|
||||
placeholder(&ustring_ptr);
|
||||
placeholder(&ustring_holder);
|
||||
placeholder(&sstring_ptr);
|
||||
placeholder(&sstring_holder);
|
||||
placeholder(&seq1_ptr);
|
||||
placeholder(&seq1_holder);
|
||||
placeholder(&seq2_ptr);
|
||||
|
|
|
@ -0,0 +1,278 @@
|
|||
// { dg-do run { target c++11 } }
|
||||
// { dg-options "-g -O0" }
|
||||
// { dg-skip-if "" { *-*-* } { "-D_GLIBCXX_PROFILE" } }
|
||||
|
||||
// Copyright (C) 2011-2018 Free Software Foundation, Inc.
|
||||
//
|
||||
// This file is part of the GNU ISO C++ Library. This library is free
|
||||
// software; you can redistribute it and/or modify it under the
|
||||
// terms of the GNU General Public License as published by the
|
||||
// Free Software Foundation; either version 3, or (at your option)
|
||||
// any later version.
|
||||
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License along
|
||||
// with this library; see the file COPYING3. If not see
|
||||
// <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <regex>
|
||||
#include <memory>
|
||||
#include <deque>
|
||||
#include <forward_list>
|
||||
#include <list>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <random>
|
||||
|
||||
template<class T>
|
||||
void
|
||||
placeholder(const T *s)
|
||||
{
|
||||
std::cout << (void *) s;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
struct holder
|
||||
{
|
||||
T *f;
|
||||
};
|
||||
|
||||
// This test is written in a somewhat funny way.
|
||||
// Each type under test is used twice: first, to form a pointer type,
|
||||
// and second, as a template parameter. This is done to work around
|
||||
// apparent GCC oddities. The pointer type is needed to ensure that
|
||||
// the typedef in question ends up in the debuginfo; while the
|
||||
// template type is used to ensure that a typedef-less variant is
|
||||
// presented to gdb.
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
std::string *string_ptr;
|
||||
holder<std::string> string_holder;
|
||||
// { dg-final { whatis-test string_holder "holder<std::string>" } }
|
||||
std::ios *ios_ptr;
|
||||
holder<std::ios> ios_holder;
|
||||
// { dg-final { whatis-test ios_holder "holder<std::ios>" } }
|
||||
std::streambuf *streambuf_ptr;
|
||||
holder<std::streambuf> streambuf_holder;
|
||||
// { dg-final { whatis-test streambuf_holder "holder<std::streambuf>" } }
|
||||
std::istream *istream_ptr;
|
||||
holder<std::istream> istream_holder;
|
||||
// { dg-final { whatis-test istream_holder "holder<std::istream>" } }
|
||||
std::ostream *ostream_ptr;
|
||||
holder<std::ostream> ostream_holder;
|
||||
// { dg-final { whatis-test ostream_holder "holder<std::ostream>" } }
|
||||
std::iostream *iostream_ptr;
|
||||
holder<std::iostream> iostream_holder;
|
||||
// { dg-final { whatis-test iostream_holder "holder<std::iostream>" } }
|
||||
std::stringbuf *stringbuf_ptr;
|
||||
holder<std::stringbuf> stringbuf_holder;
|
||||
// { dg-final { whatis-test stringbuf_holder "holder<std::stringbuf>" } }
|
||||
std::istringstream *istringstream_ptr;
|
||||
holder<std::istringstream> istringstream_holder;
|
||||
// { dg-final { whatis-test istringstream_holder "holder<std::istringstream>" } }
|
||||
std::ostringstream *ostringstream_ptr;
|
||||
holder<std::ostringstream> ostringstream_holder;
|
||||
// { dg-final { whatis-test ostringstream_holder "holder<std::ostringstream>" } }
|
||||
std::stringstream *stringstream_ptr;
|
||||
holder<std::stringstream> stringstream_holder;
|
||||
// { dg-final { whatis-test stringstream_holder "holder<std::stringstream>" } }
|
||||
std::filebuf *filebuf_ptr;
|
||||
holder<std::filebuf> filebuf_holder;
|
||||
// { dg-final { whatis-test filebuf_holder "holder<std::filebuf>" } }
|
||||
std::ifstream *ifstream_ptr;
|
||||
holder<std::ifstream> ifstream_holder;
|
||||
// { dg-final { whatis-test ifstream_holder "holder<std::ifstream>" } }
|
||||
std::ofstream *ofstream_ptr;
|
||||
holder<std::ofstream> ofstream_holder;
|
||||
// { dg-final { whatis-test ofstream_holder "holder<std::ofstream>" } }
|
||||
std::fstream *fstream_ptr;
|
||||
holder<std::fstream> fstream_holder;
|
||||
// { dg-final { whatis-test fstream_holder "holder<std::fstream>" } }
|
||||
std::streampos *streampos_ptr;
|
||||
holder<std::streampos> streampos_holder;
|
||||
// { dg-final { whatis-test streampos_holder "holder<std::streampos>" } }
|
||||
std::regex *regex_ptr;
|
||||
holder<std::regex> regex_holder;
|
||||
// { dg-final { whatis-test regex_holder "holder<std::regex>" } }
|
||||
std::csub_match *csub_match_ptr;
|
||||
holder<std::csub_match> csub_match_holder;
|
||||
// { dg-final { whatis-test csub_match_holder "holder<std::csub_match>" } }
|
||||
std::ssub_match *ssub_match_ptr;
|
||||
holder<std::ssub_match> ssub_match_holder;
|
||||
// { dg-final { whatis-test ssub_match_holder "holder<std::ssub_match>" } }
|
||||
std::cmatch *cmatch_ptr;
|
||||
holder<std::cmatch> cmatch_holder;
|
||||
// { dg-final { whatis-test cmatch_holder "holder<std::cmatch>" } }
|
||||
std::smatch *smatch_ptr;
|
||||
holder<std::smatch> smatch_holder;
|
||||
// { dg-final { whatis-test smatch_holder "holder<std::smatch>" } }
|
||||
std::cregex_iterator *cregex_iterator_ptr;
|
||||
holder<std::cregex_iterator> cregex_iterator_holder;
|
||||
// { dg-final { whatis-test cregex_iterator_holder "holder<std::cregex_iterator>" } }
|
||||
std::sregex_iterator *sregex_iterator_ptr;
|
||||
holder<std::sregex_iterator> sregex_iterator_holder;
|
||||
// { dg-final { whatis-test sregex_iterator_holder "holder<std::sregex_iterator>" } }
|
||||
std::cregex_token_iterator *cregex_token_iterator_ptr;
|
||||
holder<std::cregex_token_iterator> cregex_token_iterator_holder;
|
||||
// { dg-final { whatis-test cregex_token_iterator_holder "holder<std::cregex_token_iterator>" } }
|
||||
std::sregex_token_iterator *sregex_token_iterator_ptr;
|
||||
holder<std::sregex_token_iterator> sregex_token_iterator_holder;
|
||||
// { dg-final { whatis-test sregex_token_iterator_holder "holder<std::sregex_token_iterator>" } }
|
||||
std::u16string *u16string_ptr;
|
||||
holder<std::u16string> u16string_holder;
|
||||
// { dg-final { whatis-test u16string_holder "holder<std::u16string>" } }
|
||||
std::u32string *u32string_ptr;
|
||||
holder<std::u32string> u32string_holder;
|
||||
// { dg-final { whatis-test u32string_holder "holder<std::u32string>" } }
|
||||
std::minstd_rand0 *minstd_rand0_ptr;
|
||||
holder<std::minstd_rand0> minstd_rand0_holder;
|
||||
// { dg-final { whatis-test minstd_rand0_holder "holder<std::minstd_rand0>" } }
|
||||
std::minstd_rand *minstd_rand_ptr;
|
||||
holder<std::minstd_rand> minstd_rand_holder;
|
||||
// { dg-final { whatis-test minstd_rand_holder "holder<std::minstd_rand>" } }
|
||||
std::mt19937 *mt19937_ptr;
|
||||
holder<std::mt19937> mt19937_holder;
|
||||
// { dg-final { whatis-test mt19937_holder "holder<std::mt19937>" } }
|
||||
std::mt19937_64 *mt19937_64_ptr;
|
||||
holder<std::mt19937_64> mt19937_64_holder;
|
||||
// { dg-final { whatis-test mt19937_64_holder "holder<std::mt19937_64>" } }
|
||||
std::ranlux24_base *ranlux24_base_ptr;
|
||||
holder<std::ranlux24_base> ranlux24_base_holder;
|
||||
// { dg-final { whatis-test ranlux24_base_holder "holder<std::ranlux24_base>" } }
|
||||
std::ranlux48_base *ranlux48_base_ptr;
|
||||
holder<std::ranlux48_base> ranlux48_base_holder;
|
||||
// { dg-final { whatis-test ranlux48_base_holder "holder<std::ranlux48_base>" } }
|
||||
std::ranlux24 *ranlux24_ptr;
|
||||
holder<std::ranlux24> ranlux24_holder;
|
||||
// { dg-final { whatis-test ranlux24_holder "holder<std::ranlux24>" } }
|
||||
std::ranlux48 *ranlux48_ptr;
|
||||
holder<std::ranlux48> ranlux48_holder;
|
||||
// { dg-final { whatis-test ranlux48_holder "holder<std::ranlux48>" } }
|
||||
std::knuth_b *knuth_b_ptr;
|
||||
holder<std::knuth_b> knuth_b_holder;
|
||||
// { dg-final { whatis-test knuth_b_holder "holder<std::knuth_b>" } }
|
||||
|
||||
std::vector<std::deque<std::unique_ptr<char>>> *seq1_ptr;
|
||||
holder< std::vector<std::deque<std::unique_ptr<char>>> > seq1_holder;
|
||||
// { dg-final { whatis-test seq1_holder "holder<std::vector<std::deque<std::unique_ptr<char>>> >" } }
|
||||
|
||||
std::list<std::forward_list<std::unique_ptr<char>>> *seq2_ptr;
|
||||
holder< std::list<std::forward_list<std::unique_ptr<char>>> > seq2_holder;
|
||||
// { dg-final { whatis-test seq2_holder "holder<std::list<std::forward_list<std::unique_ptr<char>>> >" } }
|
||||
|
||||
std::map<int, std::set<int>> *assoc1_ptr;
|
||||
holder< std::map<int, std::set<int>> > assoc1_holder;
|
||||
// { dg-final { whatis-test assoc1_holder "holder<std::map<int, std::set<int>> >" } }
|
||||
|
||||
std::multimap<int, std::multiset<int>> *assoc2_ptr;
|
||||
holder< std::multimap<int, std::multiset<int>> > assoc2_holder;
|
||||
// { dg-final { whatis-test assoc2_holder "holder<std::multimap<int, std::multiset<int>> >" } }
|
||||
|
||||
std::unordered_map<int, std::unordered_set<int>> *unord1_ptr;
|
||||
holder< std::unordered_map<int, std::unordered_set<int>> > unord1_holder;
|
||||
// { dg-final { whatis-test unord1_holder "holder<std::unordered_map<int, std::unordered_set<int>> >" } }
|
||||
|
||||
std::unordered_multimap<int, std::unordered_multiset<int>> *unord2_ptr;
|
||||
holder< std::unordered_multimap<int, std::unordered_multiset<int>> > unord2_holder;
|
||||
// { dg-final { whatis-test unord2_holder "holder<std::unordered_multimap<int, std::unordered_multiset<int>> >" } }
|
||||
|
||||
|
||||
placeholder(&ios_ptr); // Mark SPOT
|
||||
placeholder(&ios_holder);
|
||||
placeholder(&string_ptr);
|
||||
placeholder(&string_holder);
|
||||
placeholder(&streambuf_ptr);
|
||||
placeholder(&streambuf_holder);
|
||||
placeholder(&istream_ptr);
|
||||
placeholder(&istream_holder);
|
||||
placeholder(&ostream_ptr);
|
||||
placeholder(&ostream_holder);
|
||||
placeholder(&iostream_ptr);
|
||||
placeholder(&iostream_holder);
|
||||
placeholder(&stringbuf_ptr);
|
||||
placeholder(&stringbuf_holder);
|
||||
placeholder(&istringstream_ptr);
|
||||
placeholder(&istringstream_holder);
|
||||
placeholder(&ostringstream_ptr);
|
||||
placeholder(&ostringstream_holder);
|
||||
placeholder(&stringstream_ptr);
|
||||
placeholder(&stringstream_holder);
|
||||
placeholder(&filebuf_ptr);
|
||||
placeholder(&filebuf_holder);
|
||||
placeholder(&ifstream_ptr);
|
||||
placeholder(&ifstream_holder);
|
||||
placeholder(&ofstream_ptr);
|
||||
placeholder(&ofstream_holder);
|
||||
placeholder(&fstream_ptr);
|
||||
placeholder(&fstream_holder);
|
||||
placeholder(&streampos_ptr);
|
||||
placeholder(&streampos_holder);
|
||||
placeholder(®ex_ptr);
|
||||
placeholder(®ex_holder);
|
||||
placeholder(&csub_match_ptr);
|
||||
placeholder(&csub_match_holder);
|
||||
placeholder(&ssub_match_ptr);
|
||||
placeholder(&ssub_match_holder);
|
||||
placeholder(&cmatch_ptr);
|
||||
placeholder(&cmatch_holder);
|
||||
placeholder(&smatch_ptr);
|
||||
placeholder(&smatch_holder);
|
||||
placeholder(&cregex_iterator_ptr);
|
||||
placeholder(&cregex_iterator_holder);
|
||||
placeholder(&sregex_iterator_ptr);
|
||||
placeholder(&sregex_iterator_holder);
|
||||
placeholder(&cregex_token_iterator_ptr);
|
||||
placeholder(&cregex_token_iterator_holder);
|
||||
placeholder(&sregex_token_iterator_ptr);
|
||||
placeholder(&sregex_token_iterator_holder);
|
||||
placeholder(&u16string_ptr);
|
||||
placeholder(&u16string_holder);
|
||||
placeholder(&u32string_ptr);
|
||||
placeholder(&u32string_holder);
|
||||
placeholder(&minstd_rand0_ptr);
|
||||
placeholder(&minstd_rand0_holder);
|
||||
placeholder(&minstd_rand_ptr);
|
||||
placeholder(&minstd_rand_holder);
|
||||
placeholder(&mt19937_ptr);
|
||||
placeholder(&mt19937_holder);
|
||||
placeholder(&mt19937_64_ptr);
|
||||
placeholder(&mt19937_64_holder);
|
||||
placeholder(&ranlux24_base_ptr);
|
||||
placeholder(&ranlux24_base_holder);
|
||||
placeholder(&ranlux48_base_ptr);
|
||||
placeholder(&ranlux48_base_holder);
|
||||
placeholder(&ranlux24_ptr);
|
||||
placeholder(&ranlux24_holder);
|
||||
placeholder(&ranlux48_ptr);
|
||||
placeholder(&ranlux48_holder);
|
||||
placeholder(&knuth_b_ptr);
|
||||
placeholder(&knuth_b_holder);
|
||||
placeholder(&seq1_ptr);
|
||||
placeholder(&seq1_holder);
|
||||
placeholder(&seq2_ptr);
|
||||
placeholder(&seq2_holder);
|
||||
placeholder(&assoc1_ptr);
|
||||
placeholder(&assoc1_holder);
|
||||
placeholder(&assoc2_ptr);
|
||||
placeholder(&assoc2_holder);
|
||||
placeholder(&unord1_ptr);
|
||||
placeholder(&unord1_holder);
|
||||
placeholder(&unord2_ptr);
|
||||
placeholder(&unord2_holder);
|
||||
|
||||
std::cout << "\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
// { dg-final { gdb-test SPOT } }
|
Loading…
Reference in New Issue