diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index 8003d8906e824..ae14482b6d723 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -614,19 +614,21 @@ impl Step for DebuggerScripts { cp_debugger_script("natvis/libcore.natvis"); cp_debugger_script("natvis/libstd.natvis"); } else { - cp_debugger_script("debugger_pretty_printers_common.py"); + cp_debugger_script("rust_types.py"); // gdb debugger scripts builder.install(&builder.src.join("src/etc/rust-gdb"), &sysroot.join("bin"), 0o755); builder.install(&builder.src.join("src/etc/rust-gdbgui"), &sysroot.join("bin"), 0o755); cp_debugger_script("gdb_load_rust_pretty_printers.py"); - cp_debugger_script("gdb_rust_pretty_printing.py"); + cp_debugger_script("gdb_lookup.py"); + cp_debugger_script("gdb_providers.py"); // lldb debugger scripts builder.install(&builder.src.join("src/etc/rust-lldb"), &sysroot.join("bin"), 0o755); - cp_debugger_script("lldb_rust_formatters.py"); + cp_debugger_script("lldb_lookup.py"); + cp_debugger_script("lldb_providers.py"); } } } diff --git a/src/etc/debugger_pretty_printers_common.py b/src/etc/debugger_pretty_printers_common.py deleted file mode 100644 index b3f8f50636bee..0000000000000 --- a/src/etc/debugger_pretty_printers_common.py +++ /dev/null @@ -1,401 +0,0 @@ -""" -This module provides an abstraction layer over common Rust pretty printing -functionality needed by both GDB and LLDB. -""" - -import re - -# Type codes that indicate the kind of type as it appears in DWARF debug -# information. This code alone is not sufficient to determine the Rust type. -# For example structs, tuples, fat pointers, or enum variants will all have -# DWARF_TYPE_CODE_STRUCT. -DWARF_TYPE_CODE_STRUCT = 1 -DWARF_TYPE_CODE_UNION = 2 -DWARF_TYPE_CODE_PTR = 3 -DWARF_TYPE_CODE_ARRAY = 4 -DWARF_TYPE_CODE_ENUM = 5 - -# These constants specify the most specific kind of type that could be -# determined for a given value. -TYPE_KIND_UNKNOWN = -1 -TYPE_KIND_EMPTY = 0 -TYPE_KIND_SLICE = 1 -TYPE_KIND_REGULAR_STRUCT = 2 -TYPE_KIND_TUPLE = 3 -TYPE_KIND_TUPLE_STRUCT = 4 -TYPE_KIND_CSTYLE_VARIANT = 5 -TYPE_KIND_TUPLE_VARIANT = 6 -TYPE_KIND_STRUCT_VARIANT = 7 -TYPE_KIND_STR_SLICE = 8 -TYPE_KIND_STD_VEC = 9 -TYPE_KIND_STD_STRING = 10 -TYPE_KIND_REGULAR_ENUM = 11 -TYPE_KIND_COMPRESSED_ENUM = 12 -TYPE_KIND_SINGLETON_ENUM = 13 -TYPE_KIND_CSTYLE_ENUM = 14 -TYPE_KIND_PTR = 15 -TYPE_KIND_FIXED_SIZE_VEC = 16 -TYPE_KIND_REGULAR_UNION = 17 -TYPE_KIND_OS_STRING = 18 -TYPE_KIND_STD_VECDEQUE = 19 -TYPE_KIND_STD_BTREESET = 20 -TYPE_KIND_STD_BTREEMAP = 21 - -ENCODED_ENUM_PREFIX = "RUST$ENCODED$ENUM$" -ENUM_DISR_FIELD_NAME = "RUST$ENUM$DISR" - -# Slice related constants -SLICE_FIELD_NAME_DATA_PTR = "data_ptr" -SLICE_FIELD_NAME_LENGTH = "length" -SLICE_FIELD_NAMES = [SLICE_FIELD_NAME_DATA_PTR, SLICE_FIELD_NAME_LENGTH] - -# std::Vec<> related constants -STD_VEC_FIELD_NAME_LENGTH = "len" -STD_VEC_FIELD_NAME_BUF = "buf" -STD_VEC_FIELD_NAMES = [STD_VEC_FIELD_NAME_BUF, - STD_VEC_FIELD_NAME_LENGTH] - -# std::collections::VecDeque<> related constants -STD_VECDEQUE_FIELD_NAME_TAIL = "tail" -STD_VECDEQUE_FIELD_NAME_HEAD = "head" -STD_VECDEQUE_FIELD_NAME_BUF = "buf" -STD_VECDEQUE_FIELD_NAMES = [STD_VECDEQUE_FIELD_NAME_TAIL, - STD_VECDEQUE_FIELD_NAME_HEAD, - STD_VECDEQUE_FIELD_NAME_BUF] - -# std::collections::BTreeSet<> related constants -STD_BTREESET_FIELD_NAMES = ["map"] - -# std::collections::BTreeMap<> related constants -STD_BTREEMAP_FIELD_NAMES = ["root", "length"] - -# std::String related constants -STD_STRING_FIELD_NAMES = ["vec"] - -# std::ffi::OsString related constants -OS_STRING_FIELD_NAMES = ["inner"] - - -class Type(object): - """ - This class provides a common interface for type-oriented operations. - Sub-classes are supposed to wrap a debugger-specific type-object and - provide implementations for the abstract methods in this class. - """ - - def __init__(self): - self.__type_kind = None - - def get_unqualified_type_name(self): - """ - Implementations of this method should return the unqualified name of the - type-object they are wrapping. Some examples: - - 'int' -> 'int' - 'std::vec::Vec' -> 'Vec' - '&std::option::Option' -> '&std::option::Option' - - As you can see, type arguments stay fully qualified. - """ - raise NotImplementedError("Override this method") - - def get_dwarf_type_kind(self): - """ - Implementations of this method should return the correct - DWARF_TYPE_CODE_* value for the wrapped type-object. - """ - raise NotImplementedError("Override this method") - - def get_fields(self): - """ - Implementations of this method should return a list of field-objects of - this type. For Rust-enums (i.e. with DWARF_TYPE_CODE_UNION) these field- - objects represent the variants of the enum. Field-objects must have a - `name` attribute that gives their name as specified in DWARF. - """ - assert ((self.get_dwarf_type_kind() == DWARF_TYPE_CODE_STRUCT) or - (self.get_dwarf_type_kind() == DWARF_TYPE_CODE_UNION)) - raise NotImplementedError("Override this method") - - def get_wrapped_value(self): - """ - Returns the debugger-specific type-object wrapped by this object. This - is sometimes needed for doing things like pointer-arithmetic in GDB. - """ - raise NotImplementedError("Override this method") - - def get_type_kind(self): - """This method returns the TYPE_KIND_* value for this type-object.""" - if self.__type_kind is None: - dwarf_type_code = self.get_dwarf_type_kind() - - if dwarf_type_code == DWARF_TYPE_CODE_STRUCT: - self.__type_kind = self.__classify_struct() - elif dwarf_type_code == DWARF_TYPE_CODE_UNION: - self.__type_kind = self.__classify_union() - elif dwarf_type_code == DWARF_TYPE_CODE_PTR: - self.__type_kind = TYPE_KIND_PTR - elif dwarf_type_code == DWARF_TYPE_CODE_ARRAY: - self.__type_kind = TYPE_KIND_FIXED_SIZE_VEC - else: - self.__type_kind = TYPE_KIND_UNKNOWN - return self.__type_kind - - def __classify_struct(self): - assert self.get_dwarf_type_kind() == DWARF_TYPE_CODE_STRUCT - - unqualified_type_name = self.get_unqualified_type_name() - - # STR SLICE - if unqualified_type_name == "&str": - return TYPE_KIND_STR_SLICE - - # REGULAR SLICE - if (unqualified_type_name.startswith(("&[", "&mut [")) and - unqualified_type_name.endswith("]") and - self.__conforms_to_field_layout(SLICE_FIELD_NAMES)): - return TYPE_KIND_SLICE - - fields = self.get_fields() - field_count = len(fields) - - # EMPTY STRUCT - if field_count == 0: - return TYPE_KIND_EMPTY - - # STD VEC - if (unqualified_type_name.startswith("Vec<") and - self.__conforms_to_field_layout(STD_VEC_FIELD_NAMES)): - return TYPE_KIND_STD_VEC - - # STD COLLECTION VECDEQUE - if (unqualified_type_name.startswith("VecDeque<") and - self.__conforms_to_field_layout(STD_VECDEQUE_FIELD_NAMES)): - return TYPE_KIND_STD_VECDEQUE - - # STD COLLECTION BTREESET - if (unqualified_type_name.startswith("BTreeSet<") and - self.__conforms_to_field_layout(STD_BTREESET_FIELD_NAMES)): - return TYPE_KIND_STD_BTREESET - - # STD COLLECTION BTREEMAP - if (unqualified_type_name.startswith("BTreeMap<") and - self.__conforms_to_field_layout(STD_BTREEMAP_FIELD_NAMES)): - return TYPE_KIND_STD_BTREEMAP - - # STD STRING - if (unqualified_type_name.startswith("String") and - self.__conforms_to_field_layout(STD_STRING_FIELD_NAMES)): - return TYPE_KIND_STD_STRING - - # OS STRING - if (unqualified_type_name == "OsString" and - self.__conforms_to_field_layout(OS_STRING_FIELD_NAMES)): - return TYPE_KIND_OS_STRING - - # ENUM VARIANTS - if fields[0].name == ENUM_DISR_FIELD_NAME: - if field_count == 1: - return TYPE_KIND_CSTYLE_VARIANT - elif self.__all_fields_conform_to_tuple_field_naming(1): - return TYPE_KIND_TUPLE_VARIANT - else: - return TYPE_KIND_STRUCT_VARIANT - - # TUPLE - if self.__all_fields_conform_to_tuple_field_naming(0): - if unqualified_type_name.startswith("("): - return TYPE_KIND_TUPLE - else: - return TYPE_KIND_TUPLE_STRUCT - - # REGULAR STRUCT - return TYPE_KIND_REGULAR_STRUCT - - def __classify_union(self): - assert self.get_dwarf_type_kind() == DWARF_TYPE_CODE_UNION - - union_members = self.get_fields() - union_member_count = len(union_members) - if union_member_count == 0: - return TYPE_KIND_EMPTY - - first_variant_name = union_members[0].name - if first_variant_name is None: - if union_member_count == 1: - return TYPE_KIND_SINGLETON_ENUM - else: - return TYPE_KIND_REGULAR_ENUM - elif first_variant_name.startswith(ENCODED_ENUM_PREFIX): - assert union_member_count == 1 - return TYPE_KIND_COMPRESSED_ENUM - else: - return TYPE_KIND_REGULAR_UNION - - def __conforms_to_field_layout(self, expected_fields): - actual_fields = self.get_fields() - actual_field_count = len(actual_fields) - - if actual_field_count != len(expected_fields): - return False - - for i in range(0, actual_field_count): - if actual_fields[i].name != expected_fields[i]: - return False - - return True - - def __all_fields_conform_to_tuple_field_naming(self, start_index): - fields = self.get_fields() - field_count = len(fields) - - for i in range(start_index, field_count): - field_name = fields[i].name - if (field_name is None) or (re.match(r"__\d+$", field_name) is None): - return False - return True - - -class Value(object): - """ - This class provides a common interface for value-oriented operations. - Sub-classes are supposed to wrap a debugger-specific value-object and - provide implementations for the abstract methods in this class. - """ - def __init__(self, ty): - self.type = ty - - def get_child_at_index(self, index): - """Returns the value of the field, array element or variant at the given index""" - raise NotImplementedError("Override this method") - - def as_integer(self): - """ - Try to convert the wrapped value into a Python integer. This should - always succeed for values that are pointers or actual integers. - """ - raise NotImplementedError("Override this method") - - def get_wrapped_value(self): - """ - Returns the debugger-specific value-object wrapped by this object. This - is sometimes needed for doing things like pointer-arithmetic in GDB. - """ - raise NotImplementedError("Override this method") - - -class EncodedEnumInfo(object): - """ - This class provides facilities for handling enum values with compressed - encoding where a non-null field in one variant doubles as the discriminant. - """ - - def __init__(self, enum_val): - assert enum_val.type.get_type_kind() == TYPE_KIND_COMPRESSED_ENUM - variant_name = enum_val.type.get_fields()[0].name - last_separator_index = variant_name.rfind("$") - start_index = len(ENCODED_ENUM_PREFIX) - indices_substring = variant_name[start_index:last_separator_index].split("$") - self.__enum_val = enum_val - self.__disr_field_indices = [int(index) for index in indices_substring] - self.__null_variant_name = variant_name[last_separator_index + 1:] - - def is_null_variant(self): - ty = self.__enum_val.type - sole_variant_val = self.__enum_val.get_child_at_index(0) - discriminant_val = sole_variant_val - for disr_field_index in self.__disr_field_indices: - discriminant_val = discriminant_val.get_child_at_index(disr_field_index) - - # If the discriminant field is a fat pointer we have to consider the - # first word as the true discriminant - if discriminant_val.type.get_dwarf_type_kind() == DWARF_TYPE_CODE_STRUCT: - discriminant_val = discriminant_val.get_child_at_index(0) - - return discriminant_val.as_integer() == 0 - - def get_non_null_variant_val(self): - return self.__enum_val.get_child_at_index(0) - - def get_null_variant_name(self): - return self.__null_variant_name - - -def get_discriminant_value_as_integer(enum_val): - assert enum_val.type.get_dwarf_type_kind() == DWARF_TYPE_CODE_UNION - # we can take any variant here because the discriminant has to be the same - # for all of them. - variant_val = enum_val.get_child_at_index(0) - disr_val = variant_val.get_child_at_index(0) - return disr_val.as_integer() - - -def extract_length_ptr_and_cap_from_std_vec(vec_val): - assert vec_val.type.get_type_kind() == TYPE_KIND_STD_VEC - length_field_index = STD_VEC_FIELD_NAMES.index(STD_VEC_FIELD_NAME_LENGTH) - buf_field_index = STD_VEC_FIELD_NAMES.index(STD_VEC_FIELD_NAME_BUF) - - length = vec_val.get_child_at_index(length_field_index).as_integer() - buf = vec_val.get_child_at_index(buf_field_index) - - vec_ptr_val = buf.get_child_at_index(0) - capacity = buf.get_child_at_index(1).as_integer() - data_ptr = vec_ptr_val.get_child_at_index(0) - assert data_ptr.type.get_dwarf_type_kind() == DWARF_TYPE_CODE_PTR - return (length, data_ptr, capacity) - - -def extract_tail_head_ptr_and_cap_from_std_vecdeque(vec_val): - assert vec_val.type.get_type_kind() == TYPE_KIND_STD_VECDEQUE - tail_field_index = STD_VECDEQUE_FIELD_NAMES.index(STD_VECDEQUE_FIELD_NAME_TAIL) - head_field_index = STD_VECDEQUE_FIELD_NAMES.index(STD_VECDEQUE_FIELD_NAME_HEAD) - buf_field_index = STD_VECDEQUE_FIELD_NAMES.index(STD_VECDEQUE_FIELD_NAME_BUF) - - tail = vec_val.get_child_at_index(tail_field_index).as_integer() - head = vec_val.get_child_at_index(head_field_index).as_integer() - buf = vec_val.get_child_at_index(buf_field_index) - - vec_ptr_val = buf.get_child_at_index(0) - capacity = buf.get_child_at_index(1).as_integer() - data_ptr = vec_ptr_val.get_child_at_index(0) - assert data_ptr.type.get_dwarf_type_kind() == DWARF_TYPE_CODE_PTR - return (tail, head, data_ptr, capacity) - - -def extract_length_and_ptr_from_slice(slice_val): - assert (slice_val.type.get_type_kind() == TYPE_KIND_SLICE or - slice_val.type.get_type_kind() == TYPE_KIND_STR_SLICE) - - length_field_index = SLICE_FIELD_NAMES.index(SLICE_FIELD_NAME_LENGTH) - ptr_field_index = SLICE_FIELD_NAMES.index(SLICE_FIELD_NAME_DATA_PTR) - - length = slice_val.get_child_at_index(length_field_index).as_integer() - data_ptr = slice_val.get_child_at_index(ptr_field_index) - - assert data_ptr.type.get_dwarf_type_kind() == DWARF_TYPE_CODE_PTR - return (length, data_ptr) - - -UNQUALIFIED_TYPE_MARKERS = frozenset(["(", "[", "&", "*"]) - - -def extract_type_name(qualified_type_name): - """Extracts the type name from a fully qualified path""" - if qualified_type_name[0] in UNQUALIFIED_TYPE_MARKERS: - return qualified_type_name - - end_of_search = qualified_type_name.find("<") - if end_of_search < 0: - end_of_search = len(qualified_type_name) - - index = qualified_type_name.rfind("::", 0, end_of_search) - if index < 0: - return qualified_type_name - else: - return qualified_type_name[index + 2:] - - -try: - compat_str = unicode # Python 2 -except NameError: - compat_str = str diff --git a/src/etc/gdb_load_rust_pretty_printers.py b/src/etc/gdb_load_rust_pretty_printers.py index fe38c49d2707d..856b5df2de70b 100644 --- a/src/etc/gdb_load_rust_pretty_printers.py +++ b/src/etc/gdb_load_rust_pretty_printers.py @@ -1,3 +1,3 @@ import gdb -import gdb_rust_pretty_printing -gdb_rust_pretty_printing.register_printers(gdb.current_objfile()) +import gdb_lookup +gdb_lookup.register_printers(gdb.current_objfile()) diff --git a/src/etc/gdb_lookup.py b/src/etc/gdb_lookup.py new file mode 100644 index 0000000000000..e94477a965208 --- /dev/null +++ b/src/etc/gdb_lookup.py @@ -0,0 +1,89 @@ +import gdb + +from gdb_providers import * +from rust_types import * + + +def register_printers(objfile): + objfile.pretty_printers.append(lookup) + + +# BACKCOMPAT: rust 1.35 +def is_hashbrown_hashmap(hash_map): + return len(hash_map.type.fields()) == 1 + + +def classify_rust_type(type): + type_class = type.code + if type_class == gdb.TYPE_CODE_STRUCT: + return classify_struct(type.tag, type.fields()) + if type_class == gdb.TYPE_CODE_UNION: + return classify_union(type.fields()) + + return RustType.OTHER + + +def check_enum_discriminant(valobj): + content = valobj[valobj.type.fields()[0]] + fields = content.type.fields() + if len(fields) > 1: + discriminant = int(content[fields[0]]) + 1 + if discriminant > len(fields): + # invalid discriminant + return False + return True + + +def lookup(valobj): + rust_type = classify_rust_type(valobj.type) + + if rust_type == RustType.STRUCT: + return StructProvider(valobj) + if rust_type == RustType.TUPLE: + return TupleProvider(valobj) + if rust_type == RustType.ENUM: + if check_enum_discriminant(valobj): + return EnumProvider(valobj) + + if rust_type == RustType.STD_STRING: + return StdStringProvider(valobj) + if rust_type == RustType.STD_OS_STRING: + return StdOsStringProvider(valobj) + if rust_type == RustType.STD_STR: + return StdStrProvider(valobj) + + if rust_type == RustType.STD_VEC: + return StdVecProvider(valobj) + if rust_type == RustType.STD_VEC_DEQUE: + return StdVecDequeProvider(valobj) + if rust_type == RustType.STD_BTREE_SET: + return StdBTreeSetProvider(valobj) + if rust_type == RustType.STD_BTREE_MAP: + return StdBTreeMapProvider(valobj) + if rust_type == RustType.STD_HASH_MAP: + if is_hashbrown_hashmap(valobj): + return StdHashMapProvider(valobj) + else: + return StdOldHashMapProvider(valobj) + if rust_type == RustType.STD_HASH_SET: + hash_map = valobj["map"] + if is_hashbrown_hashmap(hash_map): + return StdHashMapProvider(hash_map, show_values=False) + else: + return StdOldHashMapProvider(hash_map, show_values=False) + + if rust_type == RustType.STD_RC: + return StdRcProvider(valobj) + if rust_type == RustType.STD_ARC: + return StdRcProvider(valobj, is_atomic=True) + + if rust_type == RustType.STD_CELL: + return StdCellProvider(valobj) + if rust_type == RustType.STD_REF: + return StdRefProvider(valobj) + if rust_type == RustType.STD_REF_MUT: + return StdRefProvider(valobj) + if rust_type == RustType.STD_REF_CELL: + return StdRefCellProvider(valobj) + + return None diff --git a/src/etc/gdb_providers.py b/src/etc/gdb_providers.py new file mode 100644 index 0000000000000..828cde0bafaa1 --- /dev/null +++ b/src/etc/gdb_providers.py @@ -0,0 +1,406 @@ +from sys import version_info + +import gdb +from gdb import lookup_type + +if version_info[0] >= 3: + xrange = range + +ZERO_FIELD = "__0" +FIRST_FIELD = "__1" + + +def unwrap_unique_or_non_null(unique_or_nonnull): + # BACKCOMPAT: rust 1.32 + # https://github.com/rust-lang/rust/commit/7a0911528058e87d22ea305695f4047572c5e067 + ptr = unique_or_nonnull["pointer"] + return ptr if ptr.type.code == gdb.TYPE_CODE_PTR else ptr[ZERO_FIELD] + + +class StructProvider: + def __init__(self, valobj): + self.valobj = valobj + self.fields = self.valobj.type.fields() + + def to_string(self): + return self.valobj.type.name + + def children(self): + for field in self.fields: + yield field.name, self.valobj[field.name] + + +class TupleProvider: + def __init__(self, valobj): + self.valobj = valobj + self.fields = self.valobj.type.fields() + + def to_string(self): + return "size={}".format(len(self.fields)) + + def children(self): + for i, field in enumerate(self.fields): + yield str(i), self.valobj[field.name] + + @staticmethod + def display_hint(): + return "array" + + +class EnumProvider: + def __init__(self, valobj): + content = valobj[valobj.type.fields()[0]] + fields = content.type.fields() + self.empty = len(fields) == 0 + if not self.empty: + if len(fields) == 1: + discriminant = 0 + else: + discriminant = int(content[fields[0]]) + 1 + self.active_variant = content[fields[discriminant]] + self.name = fields[discriminant].name + self.full_name = "{}::{}".format(valobj.type.name, self.name) + else: + self.full_name = valobj.type.name + + def to_string(self): + return self.full_name + + def children(self): + if not self.empty: + yield self.name, self.active_variant + + +class StdStringProvider: + def __init__(self, valobj): + self.valobj = valobj + vec = valobj["vec"] + self.length = int(vec["len"]) + self.data_ptr = unwrap_unique_or_non_null(vec["buf"]["ptr"]) + + def to_string(self): + return self.data_ptr.lazy_string(encoding="utf-8", length=self.length) + + @staticmethod + def display_hint(): + return "string" + + +class StdOsStringProvider: + def __init__(self, valobj): + self.valobj = valobj + buf = self.valobj["inner"]["inner"] + is_windows = "Wtf8Buf" in buf.type.name + vec = buf[ZERO_FIELD] if is_windows else buf + + self.length = int(vec["len"]) + self.data_ptr = unwrap_unique_or_non_null(vec["buf"]["ptr"]) + + def to_string(self): + return self.data_ptr.lazy_string(encoding="utf-8", length=self.length) + + def display_hint(self): + return "string" + + +class StdStrProvider: + def __init__(self, valobj): + self.valobj = valobj + self.length = int(valobj["length"]) + self.data_ptr = valobj["data_ptr"] + + def to_string(self): + return self.data_ptr.lazy_string(encoding="utf-8", length=self.length) + + @staticmethod + def display_hint(): + return "string" + + +class StdVecProvider: + def __init__(self, valobj): + self.valobj = valobj + self.length = int(valobj["len"]) + self.data_ptr = unwrap_unique_or_non_null(valobj["buf"]["ptr"]) + + def to_string(self): + return "Vec(size={})".format(self.length) + + def children(self): + saw_inaccessible = False + for index in xrange(self.length): + element_ptr = self.data_ptr + index + if saw_inaccessible: + return + try: + # rust-lang/rust#64343: passing deref expr to `str` allows + # catching exception on garbage pointer + str(element_ptr.dereference()) + yield "[{}]".format(index), element_ptr.dereference() + except RuntimeError: + saw_inaccessible = True + yield str(index), "inaccessible" + + @staticmethod + def display_hint(): + return "array" + + +class StdVecDequeProvider: + def __init__(self, valobj): + self.valobj = valobj + self.head = int(valobj["head"]) + self.tail = int(valobj["tail"]) + self.cap = int(valobj["buf"]["cap"]) + self.data_ptr = unwrap_unique_or_non_null(valobj["buf"]["ptr"]) + if self.head >= self.tail: + self.size = self.head - self.tail + else: + self.size = self.cap + self.head - self.tail + + def to_string(self): + return "VecDeque(size={})".format(self.size) + + def children(self): + for index in xrange(0, self.size): + value = (self.data_ptr + ((self.tail + index) % self.cap)).dereference() + yield "[{}]".format(index), value + + @staticmethod + def display_hint(): + return "array" + + +class StdRcProvider: + def __init__(self, valobj, is_atomic=False): + self.valobj = valobj + self.is_atomic = is_atomic + self.ptr = unwrap_unique_or_non_null(valobj["ptr"]) + self.value = self.ptr["data" if is_atomic else "value"] + self.strong = self.ptr["strong"]["v" if is_atomic else "value"]["value"] + self.weak = self.ptr["weak"]["v" if is_atomic else "value"]["value"] - 1 + + def to_string(self): + if self.is_atomic: + return "Arc(strong={}, weak={})".format(int(self.strong), int(self.weak)) + else: + return "Rc(strong={}, weak={})".format(int(self.strong), int(self.weak)) + + def children(self): + yield "value", self.value + yield "strong", self.strong + yield "weak", self.weak + + +class StdCellProvider: + def __init__(self, valobj): + self.value = valobj["value"]["value"] + + def to_string(self): + return "Cell" + + def children(self): + yield "value", self.value + + +class StdRefProvider: + def __init__(self, valobj): + self.value = valobj["value"].dereference() + self.borrow = valobj["borrow"]["borrow"]["value"]["value"] + + def to_string(self): + borrow = int(self.borrow) + if borrow >= 0: + return "Ref(borrow={})".format(borrow) + else: + return "Ref(borrow_mut={})".format(-borrow) + + def children(self): + yield "*value", self.value + yield "borrow", self.borrow + + +class StdRefCellProvider: + def __init__(self, valobj): + self.value = valobj["value"]["value"] + self.borrow = valobj["borrow"]["value"]["value"] + + def to_string(self): + borrow = int(self.borrow) + if borrow >= 0: + return "RefCell(borrow={})".format(borrow) + else: + return "RefCell(borrow_mut={})".format(-borrow) + + def children(self): + yield "value", self.value + yield "borrow", self.borrow + + +# Yield each key (and optionally value) from a BoxedNode. +def children_of_node(boxed_node, height, want_values): + def cast_to_internal(node): + internal_type_name = str(node.type.target()).replace('LeafNode', 'InternalNode') + internal_type = lookup_type(internal_type_name) + return node.cast(internal_type.pointer()) + + node_ptr = unwrap_unique_or_non_null(boxed_node['ptr']) + node_ptr = cast_to_internal(node_ptr) if height > 0 else node_ptr + leaf = node_ptr['data'] if height > 0 else node_ptr.dereference() + keys = leaf['keys'] + values = leaf['vals'] + length = int(leaf['len']) + + for i in xrange(0, length + 1): + if height > 0: + child_ptr = node_ptr['edges'][i]['value']['value'] + for child in children_of_node(child_ptr, height - 1, want_values): + yield child + if i < length: + if want_values: + yield keys[i]['value']['value'], values[i]['value']['value'] + else: + yield keys[i]['value']['value'] + + +class StdBTreeSetProvider: + def __init__(self, valobj): + self.valobj = valobj + + def to_string(self): + return "BTreeSet(size={})".format(self.valobj["map"]["length"]) + + def children(self): + root = self.valobj["map"]["root"] + node_ptr = root["node"] + for i, child in enumerate(children_of_node(node_ptr, root["height"], want_values=False)): + yield "[{}]".format(i), child + + @staticmethod + def display_hint(): + return "array" + + +class StdBTreeMapProvider: + def __init__(self, valobj): + self.valobj = valobj + + def to_string(self): + return "BTreeMap(size={})".format(self.valobj["length"]) + + def children(self): + root = self.valobj["root"] + node_ptr = root["node"] + i = 0 + for child in children_of_node(node_ptr, root["height"], want_values=True): + yield "key{}".format(i), child[0] + yield "val{}".format(i), child[1] + i = i + 1 + + @staticmethod + def display_hint(): + return "map" + + +# BACKCOMPAT: rust 1.35 +class StdOldHashMapProvider: + def __init__(self, valobj, show_values=True): + self.valobj = valobj + self.show_values = show_values + + self.table = self.valobj["table"] + self.size = int(self.table["size"]) + self.hashes = self.table["hashes"] + self.hash_uint_type = self.hashes.type + self.hash_uint_size = self.hashes.type.sizeof + self.modulo = 2 ** self.hash_uint_size + self.data_ptr = self.hashes[ZERO_FIELD]["pointer"] + + self.capacity_mask = int(self.table["capacity_mask"]) + self.capacity = (self.capacity_mask + 1) % self.modulo + + marker = self.table["marker"].type + self.pair_type = marker.template_argument(0) + self.pair_type_size = self.pair_type.sizeof + + self.valid_indices = [] + for idx in range(self.capacity): + data_ptr = self.data_ptr.cast(self.hash_uint_type.pointer()) + address = data_ptr + idx + hash_uint = address.dereference() + hash_ptr = hash_uint[ZERO_FIELD]["pointer"] + if int(hash_ptr) != 0: + self.valid_indices.append(idx) + + def to_string(self): + if self.show_values: + return "HashMap(size={})".format(self.size) + else: + return "HashSet(size={})".format(self.size) + + def children(self): + start = int(self.data_ptr) & ~1 + + hashes = self.hash_uint_size * self.capacity + align = self.pair_type_size + len_rounded_up = (((((hashes + align) % self.modulo - 1) % self.modulo) & ~( + (align - 1) % self.modulo)) % self.modulo - hashes) % self.modulo + + pairs_offset = hashes + len_rounded_up + pairs_start = gdb.Value(start + pairs_offset).cast(self.pair_type.pointer()) + + for index in range(self.size): + table_index = self.valid_indices[index] + idx = table_index & self.capacity_mask + element = (pairs_start + idx).dereference() + if self.show_values: + yield "key{}".format(index), element[ZERO_FIELD] + yield "val{}".format(index), element[FIRST_FIELD] + else: + yield "[{}]".format(index), element[ZERO_FIELD] + + def display_hint(self): + return "map" if self.show_values else "array" + + +class StdHashMapProvider: + def __init__(self, valobj, show_values=True): + self.valobj = valobj + self.show_values = show_values + + table = self.valobj["base"]["table"] + capacity = int(table["bucket_mask"]) + 1 + ctrl = table["ctrl"]["pointer"] + + self.size = int(table["items"]) + self.data_ptr = table["data"]["pointer"] + self.pair_type = self.data_ptr.dereference().type + + self.valid_indices = [] + for idx in range(capacity): + address = ctrl + idx + value = address.dereference() + is_presented = value & 128 == 0 + if is_presented: + self.valid_indices.append(idx) + + def to_string(self): + if self.show_values: + return "HashMap(size={})".format(self.size) + else: + return "HashSet(size={})".format(self.size) + + def children(self): + pairs_start = self.data_ptr + + for index in range(self.size): + idx = self.valid_indices[index] + element = (pairs_start + idx).dereference() + if self.show_values: + yield "key{}".format(index), element[ZERO_FIELD] + yield "val{}".format(index), element[FIRST_FIELD] + else: + yield "[{}]".format(index), element[ZERO_FIELD] + + def display_hint(self): + return "map" if self.show_values else "array" diff --git a/src/etc/gdb_rust_pretty_printing.py b/src/etc/gdb_rust_pretty_printing.py deleted file mode 100755 index 0914c22eb13f0..0000000000000 --- a/src/etc/gdb_rust_pretty_printing.py +++ /dev/null @@ -1,458 +0,0 @@ -import gdb -import re -import sys -import debugger_pretty_printers_common as rustpp - -# We want a version of `range` which doesn't allocate an intermediate list, -# specifically it should use a lazy iterator. In Python 2 this was `xrange`, but -# if we're running with Python 3 then we need to use `range` instead. -if sys.version_info[0] >= 3: - xrange = range - -rust_enabled = 'set language rust' in gdb.execute('complete set language ru', to_string=True) - -# The btree pretty-printers fail in a confusing way unless -# https://sourceware.org/bugzilla/show_bug.cgi?id=21763 is fixed. -# This fix went in 8.1, so check for that. -# See https://github.com/rust-lang/rust/issues/56730 -gdb_81 = False -_match = re.search('([0-9]+)\\.([0-9]+)', gdb.VERSION) -if _match: - if int(_match.group(1)) > 8 or (int(_match.group(1)) == 8 and int(_match.group(2)) >= 1): - gdb_81 = True - -# =============================================================================== -# GDB Pretty Printing Module for Rust -# =============================================================================== - - -class GdbType(rustpp.Type): - - def __init__(self, ty): - super(GdbType, self).__init__() - self.ty = ty - self.fields = None - - def get_unqualified_type_name(self): - tag = self.ty.tag - - if tag is None: - return tag - - return rustpp.extract_type_name(tag).replace("&'static ", "&") - - def get_dwarf_type_kind(self): - if self.ty.code == gdb.TYPE_CODE_STRUCT: - return rustpp.DWARF_TYPE_CODE_STRUCT - - if self.ty.code == gdb.TYPE_CODE_UNION: - return rustpp.DWARF_TYPE_CODE_UNION - - if self.ty.code == gdb.TYPE_CODE_PTR: - return rustpp.DWARF_TYPE_CODE_PTR - - if self.ty.code == gdb.TYPE_CODE_ENUM: - return rustpp.DWARF_TYPE_CODE_ENUM - - def get_fields(self): - assert ((self.get_dwarf_type_kind() == rustpp.DWARF_TYPE_CODE_STRUCT) or - (self.get_dwarf_type_kind() == rustpp.DWARF_TYPE_CODE_UNION)) - if self.fields is None: - self.fields = list(self.ty.fields()) - return self.fields - - def get_wrapped_value(self): - return self.ty - - -class GdbValue(rustpp.Value): - def __init__(self, gdb_val): - super(GdbValue, self).__init__(GdbType(gdb_val.type)) - self.gdb_val = gdb_val - self.children = {} - - def get_child_at_index(self, index): - child = self.children.get(index) - if child is None: - gdb_field = get_field_at_index(self.gdb_val, index) - child = GdbValue(self.gdb_val[gdb_field]) - self.children[index] = child - return child - - def as_integer(self): - if self.gdb_val.type.code == gdb.TYPE_CODE_PTR: - as_str = rustpp.compat_str(self.gdb_val).split()[0] - return int(as_str, 0) - return int(self.gdb_val) - - def get_wrapped_value(self): - return self.gdb_val - - -def register_printers(objfile): - """Registers Rust pretty printers for the given objfile""" - objfile.pretty_printers.append(rust_pretty_printer_lookup_function) - - -def rust_pretty_printer_lookup_function(gdb_val): - """ - Returns the correct Rust pretty printer for the given value - if there is one - """ - - val = GdbValue(gdb_val) - type_kind = val.type.get_type_kind() - - if type_kind == rustpp.TYPE_KIND_SLICE: - return RustSlicePrinter(val) - - if type_kind == rustpp.TYPE_KIND_STD_VEC: - return RustStdVecPrinter(val) - - if type_kind == rustpp.TYPE_KIND_STD_VECDEQUE: - return RustStdVecDequePrinter(val) - - if type_kind == rustpp.TYPE_KIND_STD_BTREESET and gdb_81: - return RustStdBTreeSetPrinter(val) - - if type_kind == rustpp.TYPE_KIND_STD_BTREEMAP and gdb_81: - return RustStdBTreeMapPrinter(val) - - if type_kind == rustpp.TYPE_KIND_STD_STRING: - return RustStdStringPrinter(val) - - if type_kind == rustpp.TYPE_KIND_OS_STRING: - return RustOsStringPrinter(val) - - # Checks after this point should only be for "compiler" types -- - # things that gdb's Rust language support knows about. - if rust_enabled: - return None - - if type_kind == rustpp.TYPE_KIND_EMPTY: - return RustEmptyPrinter(val) - - if type_kind == rustpp.TYPE_KIND_REGULAR_STRUCT: - return RustStructPrinter(val, - omit_first_field=False, - omit_type_name=False, - is_tuple_like=False) - - if type_kind == rustpp.TYPE_KIND_STRUCT_VARIANT: - return RustStructPrinter(val, - omit_first_field=True, - omit_type_name=False, - is_tuple_like=False) - - if type_kind == rustpp.TYPE_KIND_STR_SLICE: - return RustStringSlicePrinter(val) - - if type_kind == rustpp.TYPE_KIND_TUPLE: - return RustStructPrinter(val, - omit_first_field=False, - omit_type_name=True, - is_tuple_like=True) - - if type_kind == rustpp.TYPE_KIND_TUPLE_STRUCT: - return RustStructPrinter(val, - omit_first_field=False, - omit_type_name=False, - is_tuple_like=True) - - if type_kind == rustpp.TYPE_KIND_CSTYLE_VARIANT: - return RustCStyleVariantPrinter(val.get_child_at_index(0)) - - if type_kind == rustpp.TYPE_KIND_TUPLE_VARIANT: - return RustStructPrinter(val, - omit_first_field=True, - omit_type_name=False, - is_tuple_like=True) - - if type_kind == rustpp.TYPE_KIND_SINGLETON_ENUM: - variant = get_field_at_index(gdb_val, 0) - return rust_pretty_printer_lookup_function(gdb_val[variant]) - - if type_kind == rustpp.TYPE_KIND_REGULAR_ENUM: - # This is a regular enum, extract the discriminant - discriminant_val = rustpp.get_discriminant_value_as_integer(val) - variant = get_field_at_index(gdb_val, discriminant_val) - return rust_pretty_printer_lookup_function(gdb_val[variant]) - - if type_kind == rustpp.TYPE_KIND_COMPRESSED_ENUM: - encoded_enum_info = rustpp.EncodedEnumInfo(val) - if encoded_enum_info.is_null_variant(): - return IdentityPrinter(encoded_enum_info.get_null_variant_name()) - - non_null_val = encoded_enum_info.get_non_null_variant_val() - return rust_pretty_printer_lookup_function(non_null_val.get_wrapped_value()) - - # No pretty printer has been found - return None - - -# =------------------------------------------------------------------------------ -# Pretty Printer Classes -# =------------------------------------------------------------------------------ -class RustEmptyPrinter(object): - def __init__(self, val): - self.__val = val - - def to_string(self): - return self.__val.type.get_unqualified_type_name() - - -class RustStructPrinter(object): - def __init__(self, val, omit_first_field, omit_type_name, is_tuple_like): - self.__val = val - self.__omit_first_field = omit_first_field - self.__omit_type_name = omit_type_name - self.__is_tuple_like = is_tuple_like - - def to_string(self): - if self.__omit_type_name: - return None - return self.__val.type.get_unqualified_type_name() - - def children(self): - cs = [] - wrapped_value = self.__val.get_wrapped_value() - - for number, field in enumerate(self.__val.type.get_fields()): - field_value = wrapped_value[field.name] - if self.__is_tuple_like: - cs.append((str(number), field_value)) - else: - cs.append((field.name, field_value)) - - if self.__omit_first_field: - cs = cs[1:] - - return cs - - def display_hint(self): - if self.__is_tuple_like: - return "array" - else: - return "" - - -class RustSlicePrinter(object): - def __init__(self, val): - self.__val = val - - @staticmethod - def display_hint(): - return "array" - - def to_string(self): - (length, data_ptr) = rustpp.extract_length_and_ptr_from_slice(self.__val) - return (self.__val.type.get_unqualified_type_name() + - ("(len: %i)" % length)) - - def children(self): - (length, data_ptr) = rustpp.extract_length_and_ptr_from_slice(self.__val) - assert data_ptr.type.get_dwarf_type_kind() == rustpp.DWARF_TYPE_CODE_PTR - raw_ptr = data_ptr.get_wrapped_value() - - for index in xrange(0, length): - yield (str(index), (raw_ptr + index).dereference()) - - -class RustStringSlicePrinter(object): - def __init__(self, val): - self.__val = val - - def to_string(self): - (length, data_ptr) = rustpp.extract_length_and_ptr_from_slice(self.__val) - raw_ptr = data_ptr.get_wrapped_value() - return raw_ptr.lazy_string(encoding="utf-8", length=length) - - def display_hint(self): - return "string" - - -class RustStdVecPrinter(object): - def __init__(self, val): - self.__val = val - - @staticmethod - def display_hint(): - return "array" - - def to_string(self): - (length, data_ptr, cap) = rustpp.extract_length_ptr_and_cap_from_std_vec(self.__val) - return (self.__val.type.get_unqualified_type_name() + - ("(len: %i, cap: %i)" % (length, cap))) - - def children(self): - saw_inaccessible = False - (length, data_ptr, cap) = rustpp.extract_length_ptr_and_cap_from_std_vec(self.__val) - gdb_ptr = data_ptr.get_wrapped_value() - for index in xrange(0, length): - if saw_inaccessible: - return - try: - # rust-lang/rust#64343: passing deref expr to `str` allows - # catching exception on garbage pointer - str((gdb_ptr + index).dereference()) - yield (str(index), (gdb_ptr + index).dereference()) - except RuntimeError: - saw_inaccessible = True - yield (str(index), "inaccessible") - - -class RustStdVecDequePrinter(object): - def __init__(self, val): - self.__val = val - - @staticmethod - def display_hint(): - return "array" - - def to_string(self): - (tail, head, data_ptr, cap) = \ - rustpp.extract_tail_head_ptr_and_cap_from_std_vecdeque(self.__val) - if head >= tail: - size = head - tail - else: - size = cap + head - tail - return (self.__val.type.get_unqualified_type_name() + - ("(len: %i, cap: %i)" % (size, cap))) - - def children(self): - (tail, head, data_ptr, cap) = \ - rustpp.extract_tail_head_ptr_and_cap_from_std_vecdeque(self.__val) - gdb_ptr = data_ptr.get_wrapped_value() - if head >= tail: - size = head - tail - else: - size = cap + head - tail - for index in xrange(0, size): - yield (str(index), (gdb_ptr + ((tail + index) % cap)).dereference()) - - -# Yield each key (and optionally value) from a BoxedNode. -def children_of_node(boxed_node, height, want_values): - node_ptr = boxed_node['ptr']['pointer'] - if height > 0: - type_name = str(node_ptr.type.target()).replace('LeafNode', 'InternalNode') - node_type = gdb.lookup_type(type_name) - node_ptr = node_ptr.cast(node_type.pointer()) - leaf = node_ptr['data'] - else: - leaf = node_ptr.dereference() - keys = leaf['keys'] - if want_values: - values = leaf['vals'] - length = int(leaf['len']) - for i in xrange(0, length + 1): - if height > 0: - child_ptr = node_ptr['edges'][i]['value']['value'] - for child in children_of_node(child_ptr, height - 1, want_values): - yield child - if i < length: - if want_values: - yield (keys[i]['value']['value'], values[i]['value']['value']) - else: - yield keys[i]['value']['value'] - - -class RustStdBTreeSetPrinter(object): - def __init__(self, val): - self.__val = val - - @staticmethod - def display_hint(): - return "array" - - def to_string(self): - return (self.__val.type.get_unqualified_type_name() + - ("(len: %i)" % self.__val.get_wrapped_value()['map']['length'])) - - def children(self): - root = self.__val.get_wrapped_value()['map']['root'] - node_ptr = root['node'] - i = 0 - for child in children_of_node(node_ptr, root['height'], False): - yield (str(i), child) - i = i + 1 - - -class RustStdBTreeMapPrinter(object): - def __init__(self, val): - self.__val = val - - @staticmethod - def display_hint(): - return "map" - - def to_string(self): - return (self.__val.type.get_unqualified_type_name() + - ("(len: %i)" % self.__val.get_wrapped_value()['length'])) - - def children(self): - root = self.__val.get_wrapped_value()['root'] - node_ptr = root['node'] - i = 0 - for child in children_of_node(node_ptr, root['height'], True): - yield (str(i), child[0]) - yield (str(i), child[1]) - i = i + 1 - - -class RustStdStringPrinter(object): - def __init__(self, val): - self.__val = val - - def to_string(self): - vec = self.__val.get_child_at_index(0) - (length, data_ptr, cap) = rustpp.extract_length_ptr_and_cap_from_std_vec(vec) - return data_ptr.get_wrapped_value().lazy_string(encoding="utf-8", - length=length) - - def display_hint(self): - return "string" - - -class RustOsStringPrinter(object): - def __init__(self, val): - self.__val = val - - def to_string(self): - buf = self.__val.get_child_at_index(0) - vec = buf.get_child_at_index(0) - if vec.type.get_unqualified_type_name() == "Wtf8Buf": - vec = vec.get_child_at_index(0) - - (length, data_ptr, cap) = rustpp.extract_length_ptr_and_cap_from_std_vec( - vec) - return data_ptr.get_wrapped_value().lazy_string(length=length) - - def display_hint(self): - return "string" - - -class RustCStyleVariantPrinter(object): - def __init__(self, val): - assert val.type.get_dwarf_type_kind() == rustpp.DWARF_TYPE_CODE_ENUM - self.__val = val - - def to_string(self): - return str(self.__val.get_wrapped_value()) - - -class IdentityPrinter(object): - def __init__(self, string): - self.string = string - - def to_string(self): - return self.string - - -def get_field_at_index(gdb_val, index): - i = 0 - for field in gdb_val.type.fields(): - if i == index: - return field - i += 1 - return None diff --git a/src/etc/lldb_lookup.py b/src/etc/lldb_lookup.py new file mode 100644 index 0000000000000..e393cf38ec7ce --- /dev/null +++ b/src/etc/lldb_lookup.py @@ -0,0 +1,111 @@ +import lldb + +from lldb_providers import * +from rust_types import RustType, classify_struct, classify_union + + +# BACKCOMPAT: rust 1.35 +def is_hashbrown_hashmap(hash_map): + return len(hash_map.type.fields) == 1 + + +def classify_rust_type(type): + type_class = type.GetTypeClass() + if type_class == lldb.eTypeClassStruct: + return classify_struct(type.name, type.fields) + if type_class == lldb.eTypeClassUnion: + return classify_union(type.fields) + + return RustType.OTHER + + +def summary_lookup(valobj, dict): + # type: (SBValue, dict) -> str + """Returns the summary provider for the given value""" + rust_type = classify_rust_type(valobj.GetType()) + + if rust_type == RustType.STD_STRING: + return StdStringSummaryProvider(valobj, dict) + if rust_type == RustType.STD_OS_STRING: + return StdOsStringSummaryProvider(valobj, dict) + if rust_type == RustType.STD_STR: + return StdStrSummaryProvider(valobj, dict) + + if rust_type == RustType.STD_VEC: + return SizeSummaryProvider(valobj, dict) + if rust_type == RustType.STD_VEC_DEQUE: + return SizeSummaryProvider(valobj, dict) + + if rust_type == RustType.STD_HASH_MAP: + return SizeSummaryProvider(valobj, dict) + if rust_type == RustType.STD_HASH_SET: + return SizeSummaryProvider(valobj, dict) + + if rust_type == RustType.STD_RC: + return StdRcSummaryProvider(valobj, dict) + if rust_type == RustType.STD_ARC: + return StdRcSummaryProvider(valobj, dict) + + if rust_type == RustType.STD_REF: + return StdRefSummaryProvider(valobj, dict) + if rust_type == RustType.STD_REF_MUT: + return StdRefSummaryProvider(valobj, dict) + if rust_type == RustType.STD_REF_CELL: + return StdRefSummaryProvider(valobj, dict) + + return "" + + +def synthetic_lookup(valobj, dict): + # type: (SBValue, dict) -> object + """Returns the synthetic provider for the given value""" + rust_type = classify_rust_type(valobj.GetType()) + + if rust_type == RustType.STRUCT: + return StructSyntheticProvider(valobj, dict) + if rust_type == RustType.STRUCT_VARIANT: + return StructSyntheticProvider(valobj, dict, is_variant=True) + if rust_type == RustType.TUPLE: + return TupleSyntheticProvider(valobj, dict) + if rust_type == RustType.TUPLE_VARIANT: + return TupleSyntheticProvider(valobj, dict, is_variant=True) + if rust_type == RustType.EMPTY: + return EmptySyntheticProvider(valobj, dict) + if rust_type == RustType.REGULAR_ENUM: + discriminant = valobj.GetChildAtIndex(0).GetChildAtIndex(0).GetValueAsUnsigned() + return synthetic_lookup(valobj.GetChildAtIndex(discriminant), dict) + if rust_type == RustType.SINGLETON_ENUM: + return synthetic_lookup(valobj.GetChildAtIndex(0), dict) + + if rust_type == RustType.STD_VEC: + return StdVecSyntheticProvider(valobj, dict) + if rust_type == RustType.STD_VEC_DEQUE: + return StdVecDequeSyntheticProvider(valobj, dict) + + if rust_type == RustType.STD_HASH_MAP: + if is_hashbrown_hashmap(valobj): + return StdHashMapSyntheticProvider(valobj, dict) + else: + return StdOldHashMapSyntheticProvider(valobj, dict) + if rust_type == RustType.STD_HASH_SET: + hash_map = valobj.GetChildAtIndex(0) + if is_hashbrown_hashmap(hash_map): + return StdHashMapSyntheticProvider(hash_map, dict, show_values=False) + else: + return StdOldHashMapSyntheticProvider(hash_map, dict, show_values=False) + + if rust_type == RustType.STD_RC: + return StdRcSyntheticProvider(valobj, dict) + if rust_type == RustType.STD_ARC: + return StdRcSyntheticProvider(valobj, dict, is_atomic=True) + + if rust_type == RustType.STD_CELL: + return StdCellSyntheticProvider(valobj, dict) + if rust_type == RustType.STD_REF: + return StdRefSyntheticProvider(valobj, dict) + if rust_type == RustType.STD_REF_MUT: + return StdRefSyntheticProvider(valobj, dict) + if rust_type == RustType.STD_REF_CELL: + return StdRefSyntheticProvider(valobj, dict, is_cell=True) + + return DefaultSynthteticProvider(valobj, dict) diff --git a/src/etc/lldb_providers.py b/src/etc/lldb_providers.py new file mode 100644 index 0000000000000..8104970f3006b --- /dev/null +++ b/src/etc/lldb_providers.py @@ -0,0 +1,678 @@ +import sys + +from lldb import SBValue, SBData, SBError, eBasicTypeLong, eBasicTypeUnsignedLong, \ + eBasicTypeUnsignedChar + +# from lldb.formatters import Logger + +#################################################################################################### +# This file contains two kinds of pretty-printers: summary and synthetic. +# +# Important classes from LLDB module: +# SBValue: the value of a variable, a register, or an expression +# SBType: the data type; each SBValue has a corresponding SBType +# +# Summary provider is a function with the type `(SBValue, dict) -> str`. +# The first parameter is the object encapsulating the actual variable being displayed; +# The second parameter is an internal support parameter used by LLDB, and you should not touch it. +# +# Synthetic children is the way to provide a children-based representation of the object's value. +# Synthetic provider is a class that implements the following interface: +# +# class SyntheticChildrenProvider: +# def __init__(self, SBValue, dict) +# def num_children(self) +# def get_child_index(self, str) +# def get_child_at_index(self, int) +# def update(self) +# def has_children(self) +# def get_value(self) +# +# +# You can find more information and examples here: +# 1. https://lldb.llvm.org/varformats.html +# 2. https://lldb.llvm.org/python-reference.html +# 3. https://lldb.llvm.org/python_reference/lldb.formatters.cpp.libcxx-pysrc.html +# 4. https://github.com/llvm-mirror/lldb/tree/master/examples/summaries/cocoa +#################################################################################################### + +PY3 = sys.version_info[0] == 3 + + +class ValueBuilder: + def __init__(self, valobj): + # type: (SBValue) -> ValueBuilder + self.valobj = valobj + process = valobj.GetProcess() + self.endianness = process.GetByteOrder() + self.pointer_size = process.GetAddressByteSize() + + def from_int(self, name, value): + # type: (str, int) -> SBValue + type = self.valobj.GetType().GetBasicType(eBasicTypeLong) + data = SBData.CreateDataFromSInt64Array(self.endianness, self.pointer_size, [value]) + return self.valobj.CreateValueFromData(name, data, type) + + def from_uint(self, name, value): + # type: (str, int) -> SBValue + type = self.valobj.GetType().GetBasicType(eBasicTypeUnsignedLong) + data = SBData.CreateDataFromUInt64Array(self.endianness, self.pointer_size, [value]) + return self.valobj.CreateValueFromData(name, data, type) + + +def unwrap_unique_or_non_null(unique_or_nonnull): + # BACKCOMPAT: rust 1.32 + # https://github.com/rust-lang/rust/commit/7a0911528058e87d22ea305695f4047572c5e067 + ptr = unique_or_nonnull.GetChildMemberWithName("pointer") + return ptr if ptr.TypeIsPointerType() else ptr.GetChildAtIndex(0) + + +class DefaultSynthteticProvider: + def __init__(self, valobj, dict): + # type: (SBValue, dict) -> DefaultSynthteticProvider + # logger = Logger.Logger() + # logger >> "Default synthetic provider for " + str(valobj.GetName()) + self.valobj = valobj + + def num_children(self): + # type: () -> int + return self.valobj.GetNumChildren() + + def get_child_index(self, name): + # type: (str) -> int + return self.valobj.GetIndexOfChildWithName(name) + + def get_child_at_index(self, index): + # type: (int) -> SBValue + return self.valobj.GetChildAtIndex(index) + + def update(self): + # type: () -> None + pass + + def has_children(self): + # type: () -> bool + return self.valobj.MightHaveChildren() + + +class EmptySyntheticProvider: + def __init__(self, valobj, dict): + # type: (SBValue, dict) -> EmptySyntheticProvider + # logger = Logger.Logger() + # logger >> "[EmptySyntheticProvider] for " + str(valobj.GetName()) + self.valobj = valobj + + def num_children(self): + # type: () -> int + return 0 + + def get_child_index(self, name): + # type: (str) -> int + return None + + def get_child_at_index(self, index): + # type: (int) -> SBValue + return None + + def update(self): + # type: () -> None + pass + + def has_children(self): + # type: () -> bool + return False + + +def SizeSummaryProvider(valobj, dict): + # type: (SBValue, dict) -> str + return 'size=' + str(valobj.GetNumChildren()) + + +def vec_to_string(vec): + length = vec.GetNumChildren() + chars = [vec.GetChildAtIndex(i).GetValueAsUnsigned() for i in range(length)] + return bytes(chars).decode(errors='replace') if PY3 else "".join(chr(char) for char in chars) + + +def StdStringSummaryProvider(valobj, dict): + # type: (SBValue, dict) -> str + # logger = Logger.Logger() + # logger >> "[StdStringSummaryProvider] for " + str(valobj.GetName()) + vec = valobj.GetChildAtIndex(0) + return '"%s"' % vec_to_string(vec) + + +def StdOsStringSummaryProvider(valobj, dict): + # type: (SBValue, dict) -> str + # logger = Logger.Logger() + # logger >> "[StdOsStringSummaryProvider] for " + str(valobj.GetName()) + buf = valobj.GetChildAtIndex(0).GetChildAtIndex(0) + is_windows = "Wtf8Buf" in buf.type.name + vec = buf.GetChildAtIndex(0) if is_windows else buf + return '"%s"' % vec_to_string(vec) + + +def StdStrSummaryProvider(valobj, dict): + # type: (SBValue, dict) -> str + # logger = Logger.Logger() + # logger >> "[StdStrSummaryProvider] for " + str(valobj.GetName()) + + length = valobj.GetChildMemberWithName("length").GetValueAsUnsigned() + if length == 0: + return '""' + + data_ptr = valobj.GetChildMemberWithName("data_ptr") + + start = data_ptr.GetValueAsUnsigned() + error = SBError() + process = data_ptr.GetProcess() + data = process.ReadMemory(start, length, error) + data = data.decode(encoding='UTF-8') if PY3 else data + return '"%s"' % data + + +class StructSyntheticProvider: + """Pretty-printer for structs and struct enum variants""" + + def __init__(self, valobj, dict, is_variant=False): + # type: (SBValue, dict, bool) -> StructSyntheticProvider + # logger = Logger.Logger() + self.valobj = valobj + self.is_variant = is_variant + self.type = valobj.GetType() + self.fields = {} + + if is_variant: + self.fields_count = self.type.GetNumberOfFields() - 1 + real_fields = self.type.fields[1:] + else: + self.fields_count = self.type.GetNumberOfFields() + real_fields = self.type.fields + + for number, field in enumerate(real_fields): + self.fields[field.name] = number + + def num_children(self): + # type: () -> int + return self.fields_count + + def get_child_index(self, name): + # type: (str) -> int + return self.fields.get(name, -1) + + def get_child_at_index(self, index): + # type: (int) -> SBValue + if self.is_variant: + field = self.type.GetFieldAtIndex(index + 1) + else: + field = self.type.GetFieldAtIndex(index) + return self.valobj.GetChildMemberWithName(field.name) + + def update(self): + # type: () -> None + pass + + def has_children(self): + # type: () -> bool + return True + + +class TupleSyntheticProvider: + """Pretty-printer for tuples and tuple enum variants""" + + def __init__(self, valobj, dict, is_variant=False): + # type: (SBValue, dict, bool) -> TupleSyntheticProvider + # logger = Logger.Logger() + self.valobj = valobj + self.is_variant = is_variant + self.type = valobj.GetType() + + if is_variant: + self.size = self.type.GetNumberOfFields() - 1 + else: + self.size = self.type.GetNumberOfFields() + + def num_children(self): + # type: () -> int + return self.size + + def get_child_index(self, name): + # type: (str) -> int + if name.isdigit(): + return int(name) + else: + return -1 + + def get_child_at_index(self, index): + # type: (int) -> SBValue + if self.is_variant: + field = self.type.GetFieldAtIndex(index + 1) + else: + field = self.type.GetFieldAtIndex(index) + element = self.valobj.GetChildMemberWithName(field.name) + return self.valobj.CreateValueFromData(str(index), element.GetData(), element.GetType()) + + def update(self): + # type: () -> None + pass + + def has_children(self): + # type: () -> bool + return True + + +class StdVecSyntheticProvider: + """Pretty-printer for alloc::vec::Vec + + struct Vec { buf: RawVec, len: usize } + struct RawVec { ptr: Unique, cap: usize, ... } + rust 1.31.1: struct Unique { pointer: NonZero<*const T>, ... } + rust 1.33.0: struct Unique { pointer: *const T, ... } + struct NonZero(T) + """ + + def __init__(self, valobj, dict): + # type: (SBValue, dict) -> StdVecSyntheticProvider + # logger = Logger.Logger() + # logger >> "[StdVecSyntheticProvider] for " + str(valobj.GetName()) + self.valobj = valobj + self.update() + + def num_children(self): + # type: () -> int + return self.length + + def get_child_index(self, name): + # type: (str) -> int + index = name.lstrip('[').rstrip(']') + if index.isdigit(): + return int(index) + else: + return -1 + + def get_child_at_index(self, index): + # type: (int) -> SBValue + start = self.data_ptr.GetValueAsUnsigned() + address = start + index * self.element_type_size + element = self.data_ptr.CreateValueFromAddress("[%s]" % index, address, self.element_type) + return element + + def update(self): + # type: () -> None + self.length = self.valobj.GetChildMemberWithName("len").GetValueAsUnsigned() + self.buf = self.valobj.GetChildMemberWithName("buf") + + self.data_ptr = unwrap_unique_or_non_null(self.buf.GetChildMemberWithName("ptr")) + + self.element_type = self.data_ptr.GetType().GetPointeeType() + self.element_type_size = self.element_type.GetByteSize() + + def has_children(self): + # type: () -> bool + return True + + +class StdVecDequeSyntheticProvider: + """Pretty-printer for alloc::collections::vec_deque::VecDeque + + struct VecDeque { tail: usize, head: usize, buf: RawVec } + """ + + def __init__(self, valobj, dict): + # type: (SBValue, dict) -> StdVecDequeSyntheticProvider + # logger = Logger.Logger() + # logger >> "[StdVecDequeSyntheticProvider] for " + str(valobj.GetName()) + self.valobj = valobj + self.update() + + def num_children(self): + # type: () -> int + return self.size + + def get_child_index(self, name): + # type: (str) -> int + index = name.lstrip('[').rstrip(']') + if index.isdigit() and self.tail <= index and (self.tail + index) % self.cap < self.head: + return int(index) + else: + return -1 + + def get_child_at_index(self, index): + # type: (int) -> SBValue + start = self.data_ptr.GetValueAsUnsigned() + address = start + ((index + self.tail) % self.cap) * self.element_type_size + element = self.data_ptr.CreateValueFromAddress("[%s]" % index, address, self.element_type) + return element + + def update(self): + # type: () -> None + self.head = self.valobj.GetChildMemberWithName("head").GetValueAsUnsigned() + self.tail = self.valobj.GetChildMemberWithName("tail").GetValueAsUnsigned() + self.buf = self.valobj.GetChildMemberWithName("buf") + self.cap = self.buf.GetChildMemberWithName("cap").GetValueAsUnsigned() + if self.head >= self.tail: + self.size = self.head - self.tail + else: + self.size = self.cap + self.head - self.tail + + self.data_ptr = unwrap_unique_or_non_null(self.buf.GetChildMemberWithName("ptr")) + + self.element_type = self.data_ptr.GetType().GetPointeeType() + self.element_type_size = self.element_type.GetByteSize() + + def has_children(self): + # type: () -> bool + return True + + +# BACKCOMPAT: rust 1.35 +class StdOldHashMapSyntheticProvider: + """Pretty-printer for std::collections::hash::map::HashMap + + struct HashMap {..., table: RawTable, ... } + struct RawTable { capacity_mask: usize, size: usize, hashes: TaggedHashUintPtr, ... } + """ + + def __init__(self, valobj, dict, show_values=True): + # type: (SBValue, dict, bool) -> StdOldHashMapSyntheticProvider + self.valobj = valobj + self.show_values = show_values + self.update() + + def num_children(self): + # type: () -> int + return self.size + + def get_child_index(self, name): + # type: (str) -> int + index = name.lstrip('[').rstrip(']') + if index.isdigit(): + return int(index) + else: + return -1 + + def get_child_at_index(self, index): + # type: (int) -> SBValue + # logger = Logger.Logger() + start = self.data_ptr.GetValueAsUnsigned() & ~1 + + # See `libstd/collections/hash/table.rs:raw_bucket_at + hashes = self.hash_uint_size * self.capacity + align = self.pair_type_size + # See `libcore/alloc.rs:padding_needed_for` + len_rounded_up = (((((hashes + align) % self.modulo - 1) % self.modulo) & ~( + (align - 1) % self.modulo)) % self.modulo - hashes) % self.modulo + # len_rounded_up = ((hashes + align - 1) & ~(align - 1)) - hashes + + pairs_offset = hashes + len_rounded_up + pairs_start = start + pairs_offset + + table_index = self.valid_indices[index] + idx = table_index & self.capacity_mask + address = pairs_start + idx * self.pair_type_size + element = self.data_ptr.CreateValueFromAddress("[%s]" % index, address, self.pair_type) + if self.show_values: + return element + else: + key = element.GetChildAtIndex(0) + return self.valobj.CreateValueFromData("[%s]" % index, key.GetData(), key.GetType()) + + def update(self): + # type: () -> None + # logger = Logger.Logger() + + self.table = self.valobj.GetChildMemberWithName("table") # type: SBValue + self.size = self.table.GetChildMemberWithName("size").GetValueAsUnsigned() + self.hashes = self.table.GetChildMemberWithName("hashes") + self.hash_uint_type = self.hashes.GetType() + self.hash_uint_size = self.hashes.GetType().GetByteSize() + self.modulo = 2 ** self.hash_uint_size + self.data_ptr = self.hashes.GetChildAtIndex(0).GetChildAtIndex(0) + + self.capacity_mask = self.table.GetChildMemberWithName("capacity_mask").GetValueAsUnsigned() + self.capacity = (self.capacity_mask + 1) % self.modulo + + marker = self.table.GetChildMemberWithName("marker").GetType() # type: SBType + self.pair_type = marker.template_args[0] + self.pair_type_size = self.pair_type.GetByteSize() + + self.valid_indices = [] + for idx in range(self.capacity): + address = self.data_ptr.GetValueAsUnsigned() + idx * self.hash_uint_size + hash_uint = self.data_ptr.CreateValueFromAddress("[%s]" % idx, address, + self.hash_uint_type) + hash_ptr = hash_uint.GetChildAtIndex(0).GetChildAtIndex(0) + if hash_ptr.GetValueAsUnsigned() != 0: + self.valid_indices.append(idx) + + # logger >> "Valid indices: {}".format(str(self.valid_indices)) + + def has_children(self): + # type: () -> bool + return True + + +class StdHashMapSyntheticProvider: + """Pretty-printer for hashbrown's HashMap""" + + def __init__(self, valobj, dict, show_values=True): + # type: (SBValue, dict, bool) -> StdHashMapSyntheticProvider + self.valobj = valobj + self.show_values = show_values + self.update() + + def num_children(self): + # type: () -> int + return self.size + + def get_child_index(self, name): + # type: (str) -> int + index = name.lstrip('[').rstrip(']') + if index.isdigit(): + return int(index) + else: + return -1 + + def get_child_at_index(self, index): + # type: (int) -> SBValue + pairs_start = self.data_ptr.GetValueAsUnsigned() + idx = self.valid_indices[index] + address = pairs_start + idx * self.pair_type_size + element = self.data_ptr.CreateValueFromAddress("[%s]" % index, address, self.pair_type) + if self.show_values: + return element + else: + key = element.GetChildAtIndex(0) + return self.valobj.CreateValueFromData("[%s]" % index, key.GetData(), key.GetType()) + + def update(self): + # type: () -> None + table = self.valobj.GetChildMemberWithName("base").GetChildMemberWithName("table") + capacity = table.GetChildMemberWithName("bucket_mask").GetValueAsUnsigned() + 1 + ctrl = table.GetChildMemberWithName("ctrl").GetChildAtIndex(0) + + self.size = table.GetChildMemberWithName("items").GetValueAsUnsigned() + self.data_ptr = table.GetChildMemberWithName("data").GetChildAtIndex(0) + self.pair_type = self.data_ptr.Dereference().GetType() + self.pair_type_size = self.pair_type.GetByteSize() + + u8_type = self.valobj.GetTarget().GetBasicType(eBasicTypeUnsignedChar) + u8_type_size = self.valobj.GetTarget().GetBasicType(eBasicTypeUnsignedChar).GetByteSize() + + self.valid_indices = [] + for idx in range(capacity): + address = ctrl.GetValueAsUnsigned() + idx * u8_type_size + value = ctrl.CreateValueFromAddress("ctrl[%s]" % idx, address, + u8_type).GetValueAsUnsigned() + is_present = value & 128 == 0 + if is_present: + self.valid_indices.append(idx) + + def has_children(self): + # type: () -> bool + return True + + +def StdRcSummaryProvider(valobj, dict): + # type: (SBValue, dict) -> str + strong = valobj.GetChildMemberWithName("strong").GetValueAsUnsigned() + weak = valobj.GetChildMemberWithName("weak").GetValueAsUnsigned() + return "strong={}, weak={}".format(strong, weak) + + +class StdRcSyntheticProvider: + """Pretty-printer for alloc::rc::Rc and alloc::sync::Arc + + struct Rc { ptr: NonNull>, ... } + rust 1.31.1: struct NonNull { pointer: NonZero<*const T> } + rust 1.33.0: struct NonNull { pointer: *const T } + struct NonZero(T) + struct RcBox { strong: Cell, weak: Cell, value: T } + struct Cell { value: UnsafeCell } + struct UnsafeCell { value: T } + + struct Arc { ptr: NonNull>, ... } + struct ArcInner { strong: atomic::AtomicUsize, weak: atomic::AtomicUsize, data: T } + struct AtomicUsize { v: UnsafeCell } + """ + + def __init__(self, valobj, dict, is_atomic=False): + # type: (SBValue, dict, bool) -> StdRcSyntheticProvider + self.valobj = valobj + + self.ptr = unwrap_unique_or_non_null(self.valobj.GetChildMemberWithName("ptr")) + + self.value = self.ptr.GetChildMemberWithName("data" if is_atomic else "value") + + self.strong = self.ptr.GetChildMemberWithName("strong").GetChildAtIndex( + 0).GetChildMemberWithName("value") + self.weak = self.ptr.GetChildMemberWithName("weak").GetChildAtIndex( + 0).GetChildMemberWithName("value") + + self.value_builder = ValueBuilder(valobj) + + self.update() + + def num_children(self): + # type: () -> int + # Actually there are 3 children, but only the `value` should be shown as a child + return 1 + + def get_child_index(self, name): + # type: (str) -> int + if name == "value": + return 0 + if name == "strong": + return 1 + if name == "weak": + return 2 + return -1 + + def get_child_at_index(self, index): + # type: (int) -> SBValue + if index == 0: + return self.value + if index == 1: + return self.value_builder.from_uint("strong", self.strong_count) + if index == 2: + return self.value_builder.from_uint("weak", self.weak_count) + + return None + + def update(self): + # type: () -> None + self.strong_count = self.strong.GetValueAsUnsigned() + self.weak_count = self.weak.GetValueAsUnsigned() - 1 + + def has_children(self): + # type: () -> bool + return True + + +class StdCellSyntheticProvider: + """Pretty-printer for std::cell::Cell""" + + def __init__(self, valobj, dict): + # type: (SBValue, dict) -> StdCellSyntheticProvider + self.valobj = valobj + self.value = valobj.GetChildMemberWithName("value").GetChildAtIndex(0) + + def num_children(self): + # type: () -> int + return 1 + + def get_child_index(self, name): + # type: (str) -> int + if name == "value": + return 0 + return -1 + + def get_child_at_index(self, index): + # type: (int) -> SBValue + if index == 0: + return self.value + return None + + def update(self): + # type: () -> None + pass + + def has_children(self): + # type: () -> bool + return True + + +def StdRefSummaryProvider(valobj, dict): + # type: (SBValue, dict) -> str + borrow = valobj.GetChildMemberWithName("borrow").GetValueAsSigned() + return "borrow={}".format(borrow) if borrow >= 0 else "borrow_mut={}".format(-borrow) + + +class StdRefSyntheticProvider: + """Pretty-printer for std::cell::Ref, std::cell::RefMut, and std::cell::RefCell""" + + def __init__(self, valobj, dict, is_cell=False): + # type: (SBValue, dict, bool) -> StdRefSyntheticProvider + self.valobj = valobj + + borrow = valobj.GetChildMemberWithName("borrow") + value = valobj.GetChildMemberWithName("value") + if is_cell: + self.borrow = borrow.GetChildMemberWithName("value").GetChildMemberWithName("value") + self.value = value.GetChildMemberWithName("value") + else: + self.borrow = borrow.GetChildMemberWithName("borrow").GetChildMemberWithName( + "value").GetChildMemberWithName("value") + self.value = value.Dereference() + + self.value_builder = ValueBuilder(valobj) + + self.update() + + def num_children(self): + # type: () -> int + # Actually there are 2 children, but only the `value` should be shown as a child + return 1 + + def get_child_index(self, name): + if name == "value": + return 0 + if name == "borrow": + return 1 + return -1 + + def get_child_at_index(self, index): + # type: (int) -> SBValue + if index == 0: + return self.value + if index == 1: + return self.value_builder.from_int("borrow", self.borrow_count) + return None + + def update(self): + # type: () -> None + self.borrow_count = self.borrow.GetValueAsSigned() + + def has_children(self): + # type: () -> bool + return True diff --git a/src/etc/lldb_rust_formatters.py b/src/etc/lldb_rust_formatters.py deleted file mode 100644 index 0c4021b36fb6f..0000000000000 --- a/src/etc/lldb_rust_formatters.py +++ /dev/null @@ -1,305 +0,0 @@ -import lldb -import debugger_pretty_printers_common as rustpp - -# =============================================================================== -# LLDB Pretty Printing Module for Rust -# =============================================================================== - - -class LldbType(rustpp.Type): - - def __init__(self, ty): - super(LldbType, self).__init__() - self.ty = ty - self.fields = None - - def get_unqualified_type_name(self): - qualified_name = self.ty.GetName() - - if qualified_name is None: - return qualified_name - - return rustpp.extract_type_name(qualified_name).replace("&'static ", "&") - - def get_dwarf_type_kind(self): - type_class = self.ty.GetTypeClass() - - if type_class == lldb.eTypeClassStruct: - return rustpp.DWARF_TYPE_CODE_STRUCT - - if type_class == lldb.eTypeClassUnion: - return rustpp.DWARF_TYPE_CODE_UNION - - if type_class == lldb.eTypeClassPointer: - return rustpp.DWARF_TYPE_CODE_PTR - - if type_class == lldb.eTypeClassArray: - return rustpp.DWARF_TYPE_CODE_ARRAY - - if type_class == lldb.eTypeClassEnumeration: - return rustpp.DWARF_TYPE_CODE_ENUM - - return None - - def get_fields(self): - assert ((self.get_dwarf_type_kind() == rustpp.DWARF_TYPE_CODE_STRUCT) or - (self.get_dwarf_type_kind() == rustpp.DWARF_TYPE_CODE_UNION)) - if self.fields is None: - self.fields = list(self.ty.fields) - return self.fields - - def get_wrapped_value(self): - return self.ty - - -class LldbValue(rustpp.Value): - def __init__(self, lldb_val): - ty = lldb_val.type - wty = LldbType(ty) - super(LldbValue, self).__init__(wty) - self.lldb_val = lldb_val - self.children = {} - - def get_child_at_index(self, index): - child = self.children.get(index) - if child is None: - lldb_field = self.lldb_val.GetChildAtIndex(index) - child = LldbValue(lldb_field) - self.children[index] = child - return child - - def as_integer(self): - return self.lldb_val.GetValueAsUnsigned() - - def get_wrapped_value(self): - return self.lldb_val - - -def print_val(lldb_val, internal_dict): - val = LldbValue(lldb_val) - type_kind = val.type.get_type_kind() - - if (type_kind == rustpp.TYPE_KIND_REGULAR_STRUCT or - type_kind == rustpp.TYPE_KIND_REGULAR_UNION or - type_kind == rustpp.TYPE_KIND_EMPTY): - return print_struct_val(val, - internal_dict, - omit_first_field=False, - omit_type_name=False, - is_tuple_like=False) - - if type_kind == rustpp.TYPE_KIND_STRUCT_VARIANT: - return print_struct_val(val, - internal_dict, - omit_first_field=True, - omit_type_name=False, - is_tuple_like=False) - - if type_kind == rustpp.TYPE_KIND_SLICE: - return print_vec_slice_val(val, internal_dict) - - if type_kind == rustpp.TYPE_KIND_STR_SLICE: - return print_str_slice_val(val, internal_dict) - - if type_kind == rustpp.TYPE_KIND_STD_VEC: - return print_std_vec_val(val, internal_dict) - - if type_kind == rustpp.TYPE_KIND_STD_STRING: - return print_std_string_val(val, internal_dict) - - if type_kind == rustpp.TYPE_KIND_TUPLE: - return print_struct_val(val, - internal_dict, - omit_first_field=False, - omit_type_name=True, - is_tuple_like=True) - - if type_kind == rustpp.TYPE_KIND_TUPLE_STRUCT: - return print_struct_val(val, - internal_dict, - omit_first_field=False, - omit_type_name=False, - is_tuple_like=True) - - if type_kind == rustpp.TYPE_KIND_CSTYLE_VARIANT: - return val.type.get_unqualified_type_name() - - if type_kind == rustpp.TYPE_KIND_TUPLE_VARIANT: - return print_struct_val(val, - internal_dict, - omit_first_field=True, - omit_type_name=False, - is_tuple_like=True) - - if type_kind == rustpp.TYPE_KIND_SINGLETON_ENUM: - return print_val(lldb_val.GetChildAtIndex(0), internal_dict) - - if type_kind == rustpp.TYPE_KIND_PTR: - return print_pointer_val(val, internal_dict) - - if type_kind == rustpp.TYPE_KIND_FIXED_SIZE_VEC: - return print_fixed_size_vec_val(val, internal_dict) - - if type_kind == rustpp.TYPE_KIND_REGULAR_ENUM: - # This is a regular enum, extract the discriminant - discriminant_val = rustpp.get_discriminant_value_as_integer(val) - return print_val(lldb_val.GetChildAtIndex(discriminant_val), internal_dict) - - if type_kind == rustpp.TYPE_KIND_COMPRESSED_ENUM: - encoded_enum_info = rustpp.EncodedEnumInfo(val) - if encoded_enum_info.is_null_variant(): - return encoded_enum_info.get_null_variant_name() - - non_null_val = encoded_enum_info.get_non_null_variant_val() - return print_val(non_null_val.get_wrapped_value(), internal_dict) - - # No pretty printer has been found - return lldb_val.GetValue() - - -# =--------------------------------------------------------------------------------------- -# Type-Specialized Printing Functions -# =--------------------------------------------------------------------------------------- - -def print_struct_val(val, internal_dict, omit_first_field, omit_type_name, is_tuple_like): - """ - Prints a struct, tuple, or tuple struct value with Rust syntax. - Ignores any fields before field_start_index. - """ - assert (val.type.get_dwarf_type_kind() == rustpp.DWARF_TYPE_CODE_STRUCT or - val.type.get_dwarf_type_kind() == rustpp.DWARF_TYPE_CODE_UNION) - - if omit_type_name: - type_name = "" - else: - type_name = val.type.get_unqualified_type_name() - - if is_tuple_like: - template = "%(type_name)s(%(body)s)" - separator = ", " - else: - template = "%(type_name)s {\n%(body)s\n}" - separator = ", \n" - - fields = val.type.get_fields() - - def render_child(child_index): - this = "" - if not is_tuple_like: - field_name = fields[child_index].name - this += field_name + ": " - - field_val = val.get_child_at_index(child_index) - - if not field_val.get_wrapped_value().IsValid(): - field = fields[child_index] - # LLDB is not good at handling zero-sized values, so we have to help - # it a little - if field.GetType().GetByteSize() == 0: - return this + rustpp.extract_type_name(field.GetType().GetName()) - else: - return this + "" - - return this + print_val(field_val.get_wrapped_value(), internal_dict) - - if omit_first_field: - field_start_index = 1 - else: - field_start_index = 0 - - body = separator.join([render_child(idx) for idx in range(field_start_index, len(fields))]) - - return template % {"type_name": type_name, - "body": body} - - -def print_pointer_val(val, internal_dict): - """Prints a pointer value with Rust syntax""" - assert val.type.get_dwarf_type_kind() == rustpp.DWARF_TYPE_CODE_PTR - sigil = "&" - type_name = val.type.get_unqualified_type_name() - if type_name and type_name[0:1] in ["&", "*"]: - sigil = type_name[0:1] - - return sigil + hex(val.as_integer()) - - -def print_fixed_size_vec_val(val, internal_dict): - assert val.type.get_dwarf_type_kind() == rustpp.DWARF_TYPE_CODE_ARRAY - lldb_val = val.get_wrapped_value() - - output = "[" - - for i in range(lldb_val.num_children): - output += print_val(lldb_val.GetChildAtIndex(i), internal_dict) - if i != lldb_val.num_children - 1: - output += ", " - - output += "]" - return output - - -def print_vec_slice_val(val, internal_dict): - (length, data_ptr) = rustpp.extract_length_and_ptr_from_slice(val) - return "&[%s]" % print_array_of_values(val.get_wrapped_value().GetName(), - data_ptr, - length, - internal_dict) - - -def print_std_vec_val(val, internal_dict): - (length, data_ptr, cap) = rustpp.extract_length_ptr_and_cap_from_std_vec(val) - return "vec![%s]" % print_array_of_values(val.get_wrapped_value().GetName(), - data_ptr, - length, - internal_dict) - - -def print_str_slice_val(val, internal_dict): - (length, data_ptr) = rustpp.extract_length_and_ptr_from_slice(val) - return read_utf8_string(data_ptr, length) - - -def print_std_string_val(val, internal_dict): - vec = val.get_child_at_index(0) - (length, data_ptr, cap) = rustpp.extract_length_ptr_and_cap_from_std_vec(vec) - return read_utf8_string(data_ptr, length) - -# =----------------------------------------------------------------------- -# Helper Functions -# =----------------------------------------------------------------------- - - -def print_array_of_values(array_name, data_ptr_val, length, internal_dict): - """Prints a contiguous memory range, interpreting it as values of the - pointee-type of data_ptr_val.""" - - data_ptr_type = data_ptr_val.type - assert data_ptr_type.get_dwarf_type_kind() == rustpp.DWARF_TYPE_CODE_PTR - - element_type = data_ptr_type.get_wrapped_value().GetPointeeType() - element_type_size = element_type.GetByteSize() - - start_address = data_ptr_val.as_integer() - raw_value = data_ptr_val.get_wrapped_value() - - def render_element(i): - address = start_address + i * element_type_size - element_val = raw_value.CreateValueFromAddress(array_name + ("[%s]" % i), - address, - element_type) - return print_val(element_val, internal_dict) - - return ', '.join([render_element(i) for i in range(length)]) - - -def read_utf8_string(ptr_val, byte_count): - if byte_count == 0: - return '""' - error = lldb.SBError() - process = ptr_val.get_wrapped_value().GetProcess() - data = process.ReadMemory(ptr_val.as_integer(), byte_count, error) - if error.Success(): - return '"%s"' % data.decode(encoding='UTF-8') - else: - return '' % error.GetCString() diff --git a/src/etc/rust-lldb b/src/etc/rust-lldb index 7b9b40e6b4a0a..1364e20fb1cd5 100755 --- a/src/etc/rust-lldb +++ b/src/etc/rust-lldb @@ -31,12 +31,10 @@ EOF fi # Prepare commands that will be loaded before any file on the command line has been loaded -script_import="command script import \"$RUSTC_SYSROOT/lib/rustlib/etc/lldb_rust_formatters.py\"" -category_definition="type summary add --no-value --python-function lldb_rust_formatters.print_val -x \".*\" --category Rust" +script_import="command script import \"$RUSTC_SYSROOT/lib/rustlib/etc/lldb_lookup.py\"" +synthetic_definition="type synthetic add -l lldb_lookup.synthetic_lookup -x \".*\" --category Rust" +summary_definition="type summary add -F lldb_lookup.summary_lookup -e -x -h \".*\" --category Rust" category_enable="type category enable Rust" # Call LLDB with the commands added to the argument list -exec "$lldb" --one-line-before-file "$script_import" \ - --one-line-before-file "$category_definition" \ - --one-line-before-file "$category_enable" \ - "$@" +exec "$lldb" -O "$script_import" -O "$synthetic_definition" -O "$summary_definition" -O "$category_enable" "$@" diff --git a/src/etc/rust_types.py b/src/etc/rust_types.py new file mode 100644 index 0000000000000..5854b9cc35ad0 --- /dev/null +++ b/src/etc/rust_types.py @@ -0,0 +1,110 @@ +import re + + +class RustType(object): + OTHER = "Other" + STRUCT = "Struct" + TUPLE = "Tuple" + CSTYLE_VARIANT = "CStyleVariant" + TUPLE_VARIANT = "TupleVariant" + STRUCT_VARIANT = "StructVariant" + ENUM = "Enum" + EMPTY = "Empty" + SINGLETON_ENUM = "SingletonEnum" + REGULAR_ENUM = "RegularEnum" + COMPRESSED_ENUM = "CompressedEnum" + REGULAR_UNION = "RegularUnion" + + STD_STRING = "StdString" + STD_OS_STRING = "StdOsString" + STD_STR = "StdStr" + STD_VEC = "StdVec" + STD_VEC_DEQUE = "StdVecDeque" + STD_BTREE_SET = "StdBTreeSet" + STD_BTREE_MAP = "StdBTreeMap" + STD_HASH_MAP = "StdHashMap" + STD_HASH_SET = "StdHashSet" + STD_RC = "StdRc" + STD_ARC = "StdArc" + STD_CELL = "StdCell" + STD_REF = "StdRef" + STD_REF_MUT = "StdRefMut" + STD_REF_CELL = "StdRefCell" + + +STD_STRING_REGEX = re.compile(r"^(alloc::(\w+::)+)String$") +STD_STR_REGEX = re.compile(r"^&str$") +STD_OS_STRING_REGEX = re.compile(r"^(std::ffi::(\w+::)+)OsString$") +STD_VEC_REGEX = re.compile(r"^(alloc::(\w+::)+)Vec<.+>$") +STD_VEC_DEQUE_REGEX = re.compile(r"^(alloc::(\w+::)+)VecDeque<.+>$") +STD_BTREE_SET_REGEX = re.compile(r"^(alloc::(\w+::)+)BTreeSet<.+>$") +STD_BTREE_MAP_REGEX = re.compile(r"^(alloc::(\w+::)+)BTreeMap<.+>$") +STD_HASH_MAP_REGEX = re.compile(r"^(std::collections::(\w+::)+)HashMap<.+>$") +STD_HASH_SET_REGEX = re.compile(r"^(std::collections::(\w+::)+)HashSet<.+>$") +STD_RC_REGEX = re.compile(r"^(alloc::(\w+::)+)Rc<.+>$") +STD_ARC_REGEX = re.compile(r"^(alloc::(\w+::)+)Arc<.+>$") +STD_CELL_REGEX = re.compile(r"^(core::(\w+::)+)Cell<.+>$") +STD_REF_REGEX = re.compile(r"^(core::(\w+::)+)Ref<.+>$") +STD_REF_MUT_REGEX = re.compile(r"^(core::(\w+::)+)RefMut<.+>$") +STD_REF_CELL_REGEX = re.compile(r"^(core::(\w+::)+)RefCell<.+>$") + +TUPLE_ITEM_REGEX = re.compile(r"__\d+$") + +ENCODED_ENUM_PREFIX = "RUST$ENCODED$ENUM$" +ENUM_DISR_FIELD_NAME = "<>" + +STD_TYPE_TO_REGEX = { + RustType.STD_STRING: STD_STRING_REGEX, + RustType.STD_OS_STRING: STD_OS_STRING_REGEX, + RustType.STD_STR: STD_STR_REGEX, + RustType.STD_VEC: STD_VEC_REGEX, + RustType.STD_VEC_DEQUE: STD_VEC_DEQUE_REGEX, + RustType.STD_HASH_MAP: STD_HASH_MAP_REGEX, + RustType.STD_HASH_SET: STD_HASH_SET_REGEX, + RustType.STD_BTREE_SET: STD_BTREE_SET_REGEX, + RustType.STD_BTREE_MAP: STD_BTREE_MAP_REGEX, + RustType.STD_RC: STD_RC_REGEX, + RustType.STD_ARC: STD_ARC_REGEX, + RustType.STD_REF: STD_REF_REGEX, + RustType.STD_REF_MUT: STD_REF_MUT_REGEX, + RustType.STD_REF_CELL: STD_REF_CELL_REGEX, + RustType.STD_CELL: STD_CELL_REGEX, +} + +def is_tuple_fields(fields): + # type: (list) -> bool + return all(TUPLE_ITEM_REGEX.match(str(field.name)) for field in fields) + + +def classify_struct(name, fields): + if len(fields) == 0: + return RustType.EMPTY + + for ty, regex in STD_TYPE_TO_REGEX.items(): + if regex.match(name): + return ty + + if fields[0].name == ENUM_DISR_FIELD_NAME: + return RustType.ENUM + + if is_tuple_fields(fields): + return RustType.TUPLE + + return RustType.STRUCT + + +def classify_union(fields): + if len(fields) == 0: + return RustType.EMPTY + + first_variant_name = fields[0].name + if first_variant_name is None: + if len(fields) == 1: + return RustType.SINGLETON_ENUM + else: + return RustType.REGULAR_ENUM + elif first_variant_name.startswith(ENCODED_ENUM_PREFIX): + assert len(fields) == 1 + return RustType.COMPRESSED_ENUM + else: + return RustType.REGULAR_UNION diff --git a/src/libcore/str/pattern.rs b/src/libcore/str/pattern.rs index ef64d8b0fdf88..6c826e5dcdec0 100644 --- a/src/libcore/str/pattern.rs +++ b/src/libcore/str/pattern.rs @@ -1050,7 +1050,7 @@ impl TwoWaySearcher { // &v[..period]. If it is, we use "Algorithm CP1". Otherwise we use // "Algorithm CP2", which is optimized for when the period of the needle // is large. - if &needle[..crit_pos] == &needle[period..period + crit_pos] { + if needle[..crit_pos] == needle[period..period + crit_pos] { // short period case -- the period is exact // compute a separate critical factorization for the reversed needle // x = u' v' where |v'| < period(x). diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index de2ec53e51e78..dabd79c5c81e5 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -581,6 +581,20 @@ impl<'tcx, N> Vtable<'tcx, N> { } } + pub fn borrow_nested_obligations(&self) -> &[N] { + match &self { + VtableImpl(i) => &i.nested[..], + VtableParam(n) => &n[..], + VtableBuiltin(i) => &i.nested[..], + VtableAutoImpl(d) => &d.nested[..], + VtableClosure(c) => &c.nested[..], + VtableGenerator(c) => &c.nested[..], + VtableObject(d) => &d.nested[..], + VtableFnPointer(d) => &d.nested[..], + VtableTraitAlias(d) => &d.nested[..], + } + } + pub fn map(self, f: F) -> Vtable<'tcx, M> where F: FnMut(N) -> M, diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs index 6c5458e6e58a6..2599ad8ba7b9d 100644 --- a/src/librustc/ty/error.rs +++ b/src/librustc/ty/error.rs @@ -341,7 +341,7 @@ impl<'tcx> TyCtxt<'tcx> { db.note("distinct uses of `impl Trait` result in different opaque types"); let e_str = values.expected.to_string(); let f_str = values.found.to_string(); - if &e_str == &f_str && &e_str == "impl std::future::Future" { + if e_str == f_str && &e_str == "impl std::future::Future" { // FIXME: use non-string based check. db.help( "if both `Future`s have the same `Output` type, consider \ diff --git a/src/librustc/ty/print/pretty.rs b/src/librustc/ty/print/pretty.rs index 0726bf30d3b34..3512b24ec4877 100644 --- a/src/librustc/ty/print/pretty.rs +++ b/src/librustc/ty/print/pretty.rs @@ -136,7 +136,7 @@ impl RegionHighlightMode { pub fn highlighting_region(&mut self, region: ty::Region<'_>, number: usize) { let num_slots = self.highlight_regions.len(); let first_avail_slot = - self.highlight_regions.iter_mut().filter(|s| s.is_none()).next().unwrap_or_else(|| { + self.highlight_regions.iter_mut().find(|s| s.is_none()).unwrap_or_else(|| { bug!("can only highlight {} placeholders at a time", num_slots,) }); *first_avail_slot = Some((*region, number)); diff --git a/src/librustc_codegen_ssa/base.rs b/src/librustc_codegen_ssa/base.rs index e9431d94863ef..d6e1ab8909c59 100644 --- a/src/librustc_codegen_ssa/base.rs +++ b/src/librustc_codegen_ssa/base.rs @@ -437,10 +437,10 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( // listing. let main_ret_ty = cx.tcx().erase_regions(&main_ret_ty.no_bound_vars().unwrap()); - if cx.get_defined_value("main").is_some() { + if cx.get_declared_value("main").is_some() { // FIXME: We should be smart and show a better diagnostic here. cx.sess() - .struct_span_err(sp, "entry symbol `main` defined multiple times") + .struct_span_err(sp, "entry symbol `main` declared multiple times") .help("did you use `#[no_mangle]` on `fn main`? Use `#[start]` instead") .emit(); cx.sess().abort_if_errors(); diff --git a/src/librustc_infer/infer/error_reporting/mod.rs b/src/librustc_infer/infer/error_reporting/mod.rs index 008658dff425b..fd103c4c3369b 100644 --- a/src/librustc_infer/infer/error_reporting/mod.rs +++ b/src/librustc_infer/infer/error_reporting/mod.rs @@ -745,7 +745,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { .join(", "); if !lifetimes.is_empty() { if sub.regions().count() < len { - value.push_normal(lifetimes + &", "); + value.push_normal(lifetimes + ", "); } else { value.push_normal(lifetimes); } diff --git a/src/librustc_infer/infer/error_reporting/note.rs b/src/librustc_infer/infer/error_reporting/note.rs index 7a7cfdecbaf7d..5c0caa48d0e77 100644 --- a/src/librustc_infer/infer/error_reporting/note.rs +++ b/src/librustc_infer/infer/error_reporting/note.rs @@ -645,8 +645,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { self.tcx.sess, span, E0491, - "in type `{}`, reference has a longer lifetime \ - than the data it references", + "in type `{}`, reference has a longer lifetime than the data it references", self.ty_to_string(ty) ); note_and_explain_region( diff --git a/src/librustc_infer/traits/coherence.rs b/src/librustc_infer/traits/coherence.rs index 43c0fbc27e620..d94231653abd4 100644 --- a/src/librustc_infer/traits/coherence.rs +++ b/src/librustc_infer/traits/coherence.rs @@ -399,8 +399,7 @@ fn orphan_check_trait_ref<'tcx>( let local_type = trait_ref .input_types() .flat_map(|ty| uncover_fundamental_ty(tcx, ty, in_crate)) - .filter(|ty| ty_is_non_local_constructor(ty, in_crate).is_none()) - .next(); + .find(|ty| ty_is_non_local_constructor(ty, in_crate).is_none()); debug!("orphan_check_trait_ref: uncovered ty local_type: `{:?}`", local_type); diff --git a/src/librustc_infer/traits/error_reporting/mod.rs b/src/librustc_infer/traits/error_reporting/mod.rs index 2fc7c17897739..9bfa219695096 100644 --- a/src/librustc_infer/traits/error_reporting/mod.rs +++ b/src/librustc_infer/traits/error_reporting/mod.rs @@ -1442,7 +1442,7 @@ pub fn suggest_constraining_type_param( const MSG_RESTRICT_TYPE: &str = "consider restricting this type parameter with"; const MSG_RESTRICT_TYPE_FURTHER: &str = "consider further restricting this type parameter with"; - let param = generics.params.iter().filter(|p| p.name.ident().as_str() == param_name).next(); + let param = generics.params.iter().find(|p| p.name.ident().as_str() == param_name); let param = if let Some(param) = param { param diff --git a/src/librustc_parse/lexer/tokentrees.rs b/src/librustc_parse/lexer/tokentrees.rs index c28b59a790801..20a7fcb650a2e 100644 --- a/src/librustc_parse/lexer/tokentrees.rs +++ b/src/librustc_parse/lexer/tokentrees.rs @@ -93,10 +93,8 @@ impl<'a> TokenTreesReader<'a> { } if let Some((delim, _)) = self.open_braces.last() { - if let Some((_, open_sp, close_sp)) = self - .matching_delim_spans - .iter() - .filter(|(d, open_sp, close_sp)| { + if let Some((_, open_sp, close_sp)) = + self.matching_delim_spans.iter().find(|(d, open_sp, close_sp)| { if let Some(close_padding) = sm.span_to_margin(*close_sp) { if let Some(open_padding) = sm.span_to_margin(*open_sp) { return delim == d && close_padding != open_padding; @@ -104,7 +102,6 @@ impl<'a> TokenTreesReader<'a> { } false }) - .next() // these are in reverse order as they get inserted on close, but { // we want the last open/first close diff --git a/src/librustc_parse/parser/expr.rs b/src/librustc_parse/parser/expr.rs index 3ae97ed5f8822..b8f67e73bc3f7 100644 --- a/src/librustc_parse/parser/expr.rs +++ b/src/librustc_parse/parser/expr.rs @@ -225,12 +225,8 @@ impl<'a> Parser<'a> { // Make sure that the span of the parent node is larger than the span of lhs and rhs, // including the attributes. - let lhs_span = lhs - .attrs - .iter() - .filter(|a| a.style == AttrStyle::Outer) - .next() - .map_or(lhs_span, |a| a.span); + let lhs_span = + lhs.attrs.iter().find(|a| a.style == AttrStyle::Outer).map_or(lhs_span, |a| a.span); let span = lhs_span.to(rhs.span); lhs = match op { AssocOp::Add diff --git a/src/librustc_parse/parser/generics.rs b/src/librustc_parse/parser/generics.rs index 0984263bb283e..4d9a3266567f3 100644 --- a/src/librustc_parse/parser/generics.rs +++ b/src/librustc_parse/parser/generics.rs @@ -1,7 +1,6 @@ use super::Parser; use rustc_errors::PResult; -use rustc_span::source_map::DUMMY_SP; use rustc_span::symbol::{kw, sym}; use syntax::ast::{self, Attribute, GenericBounds, GenericParam, GenericParamKind, WhereClause}; use syntax::token; @@ -160,7 +159,10 @@ impl<'a> Parser<'a> { }; Ok(ast::Generics { params, - where_clause: WhereClause { predicates: Vec::new(), span: DUMMY_SP }, + where_clause: WhereClause { + predicates: Vec::new(), + span: self.prev_span.shrink_to_hi(), + }, span, }) } diff --git a/src/librustc_span/symbol.rs b/src/librustc_span/symbol.rs index b8e5ea97f4e47..d6232f32f4c1b 100644 --- a/src/librustc_span/symbol.rs +++ b/src/librustc_span/symbol.rs @@ -1023,6 +1023,14 @@ impl Symbol { pub fn as_u32(self) -> u32 { self.0.as_u32() } + + /// This method is supposed to be used in error messages, so it's expected to be + /// identical to printing the original identifier token written in source code + /// (`token_to_string`, `Ident::to_string`), except that symbols don't keep the rawness flag + /// or edition, so we have to guess the rawness using the global edition. + pub fn to_ident_string(self) -> String { + Ident::with_dummy_span(self).to_string() + } } impl fmt::Debug for Symbol { diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 78c05a51e4fbd..6b7f85bcffb2c 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -2358,10 +2358,11 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { break; } } - for binding in segment.generic_args().bindings { + + // Only emit the first error to avoid overloading the user with error messages. + if let [binding, ..] = segment.generic_args().bindings { has_err = true; Self::prohibit_assoc_ty_binding(self.tcx(), binding.span); - break; } } has_err diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index de824648a25d9..b09522bbd33da 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -14,7 +14,7 @@ use crate::check::FnCtxt; use rustc::ty::subst::Subst; use rustc::ty::subst::{InternalSubsts, SubstsRef}; use rustc::ty::GenericParamDefKind; -use rustc::ty::{self, ToPolyTraitRef, ToPredicate, TraitRef, Ty, TypeFoldable, WithConstness}; +use rustc::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TypeFoldable, WithConstness}; use rustc_data_structures::sync::Lrc; use rustc_errors::{Applicability, DiagnosticBuilder}; use rustc_hir as hir; @@ -67,7 +67,7 @@ pub enum MethodError<'tcx> { // could lead to matches if satisfied, and a list of not-in-scope traits which may work. pub struct NoMatchData<'tcx> { pub static_candidates: Vec, - pub unsatisfied_predicates: Vec>, + pub unsatisfied_predicates: Vec<(ty::Predicate<'tcx>, Option>)>, pub out_of_scope_traits: Vec, pub lev_candidate: Option, pub mode: probe::Mode, @@ -76,7 +76,7 @@ pub struct NoMatchData<'tcx> { impl<'tcx> NoMatchData<'tcx> { pub fn new( static_candidates: Vec, - unsatisfied_predicates: Vec>, + unsatisfied_predicates: Vec<(ty::Predicate<'tcx>, Option>)>, out_of_scope_traits: Vec, lev_candidate: Option, mode: probe::Mode, diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index ea90aef486839..3e2826907b880 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -14,8 +14,7 @@ use rustc::session::config::nightly_options; use rustc::ty::subst::{InternalSubsts, Subst, SubstsRef}; use rustc::ty::GenericParamDefKind; use rustc::ty::{ - self, ParamEnvAnd, ToPolyTraitRef, ToPredicate, TraitRef, Ty, TyCtxt, TypeFoldable, - WithConstness, + self, ParamEnvAnd, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness, }; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::sync::Lrc; @@ -78,7 +77,7 @@ struct ProbeContext<'a, 'tcx> { /// Collects near misses when trait bounds for type parameters are unsatisfied and is only used /// for error reporting - unsatisfied_predicates: Vec>, + unsatisfied_predicates: Vec<(ty::Predicate<'tcx>, Option>)>, is_suggestion: IsSuggestion, } @@ -1224,7 +1223,10 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { &self, self_ty: Ty<'tcx>, probes: ProbesIter, - possibly_unsatisfied_predicates: &mut Vec>, + possibly_unsatisfied_predicates: &mut Vec<( + ty::Predicate<'tcx>, + Option>, + )>, unstable_candidates: Option<&mut Vec<(&'b Candidate<'tcx>, Symbol)>>, ) -> Option> where @@ -1343,7 +1345,10 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { &self, self_ty: Ty<'tcx>, probe: &Candidate<'tcx>, - possibly_unsatisfied_predicates: &mut Vec>, + possibly_unsatisfied_predicates: &mut Vec<( + ty::Predicate<'tcx>, + Option>, + )>, ) -> ProbeResult { debug!("consider_probe: self_ty={:?} probe={:?}", self_ty, probe); @@ -1398,21 +1403,45 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { let predicate = trait_ref.without_const().to_predicate(); let obligation = traits::Obligation::new(cause, self.param_env, predicate); if !self.predicate_may_hold(&obligation) { - if self.probe(|_| self.select_trait_candidate(trait_ref).is_err()) { + if self.probe(|_| { + match self.select_trait_candidate(trait_ref) { + Err(_) => return true, + Ok(Some(vtable)) + if !vtable.borrow_nested_obligations().is_empty() => + { + for obligation in vtable.borrow_nested_obligations() { + // Determine exactly which obligation wasn't met, so + // that we can give more context in the error. + if !self.predicate_may_hold(&obligation) { + result = ProbeResult::NoMatch; + let o = self.resolve_vars_if_possible(obligation); + let predicate = + self.resolve_vars_if_possible(&predicate); + let p = if predicate == o.predicate { + // Avoid "`MyStruct: Foo` which is required by + // `MyStruct: Foo`" in E0599. + None + } else { + Some(predicate) + }; + possibly_unsatisfied_predicates.push((o.predicate, p)); + } + } + } + _ => { + // Some nested subobligation of this predicate + // failed. + result = ProbeResult::NoMatch; + let predicate = self.resolve_vars_if_possible(&predicate); + possibly_unsatisfied_predicates.push((predicate, None)); + } + } + false + }) { // This candidate's primary obligation doesn't even // select - don't bother registering anything in // `potentially_unsatisfied_predicates`. return ProbeResult::NoMatch; - } else { - // Some nested subobligation of this predicate - // failed. - // - // FIXME: try to find the exact nested subobligation - // and point at it rather than reporting the entire - // trait-ref? - result = ProbeResult::NoMatch; - let trait_ref = self.resolve_vars_if_possible(&trait_ref); - possibly_unsatisfied_predicates.push(trait_ref); } } vec![] @@ -1429,9 +1458,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { let o = self.resolve_vars_if_possible(&o); if !self.predicate_may_hold(&o) { result = ProbeResult::NoMatch; - if let &ty::Predicate::Trait(ref pred, _) = &o.predicate { - possibly_unsatisfied_predicates.push(pred.skip_binder().trait_ref); - } + possibly_unsatisfied_predicates.push((o.predicate, None)); } } diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index ea83b40a1cb6b..44f87319ebf4f 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -7,7 +7,7 @@ use rustc::hir::map as hir_map; use rustc::hir::map::Map; use rustc::ty::print::with_crate_prefix; use rustc::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness}; -use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Namespace, Res}; @@ -16,6 +16,7 @@ use rustc_hir::intravisit; use rustc_hir::{ExprKind, Node, QPath}; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::traits::Obligation; +use rustc_span::symbol::kw; use rustc_span::{source_map, FileName, Span}; use syntax::ast; use syntax::util::lev_distance; @@ -496,7 +497,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if !static_sources.is_empty() { err.note( "found the following associated functions; to be used as methods, \ - functions must have a `self` parameter", + functions must have a `self` parameter", ); err.span_label(span, "this is an associated function, not a method"); } @@ -534,22 +535,159 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { report_candidates(span, &mut err, static_sources, sugg_span); } + let mut restrict_type_params = false; if !unsatisfied_predicates.is_empty() { + let def_span = + |def_id| self.tcx.sess.source_map().def_span(self.tcx.def_span(def_id)); + let mut type_params = FxHashMap::default(); + let mut bound_spans = vec![]; + let mut collect_type_param_suggestions = + |self_ty: Ty<'_>, parent_pred: &ty::Predicate<'_>, obligation: &str| { + if let (ty::Param(_), ty::Predicate::Trait(p, _)) = + (&self_ty.kind, parent_pred) + { + if let ty::Adt(def, _) = p.skip_binder().trait_ref.self_ty().kind { + let id = self.tcx.hir().as_local_hir_id(def.did).unwrap(); + let node = self.tcx.hir().get(id); + match node { + hir::Node::Item(hir::Item { kind, .. }) => { + if let Some(g) = kind.generics() { + let key = match &g.where_clause.predicates[..] { + [.., pred] => { + (pred.span().shrink_to_hi(), false) + } + [] => ( + g.where_clause + .span_for_predicates_or_empty_place(), + true, + ), + }; + type_params + .entry(key) + .or_insert_with(FxHashSet::default) + .insert(obligation.to_owned()); + } + } + _ => {} + } + } + } + }; + let mut bound_span_label = |self_ty: Ty<'_>, obligation: &str, quiet: &str| { + let msg = format!( + "doesn't satisfy `{}`", + if obligation.len() > 50 { quiet } else { obligation } + ); + match &self_ty.kind { + // Point at the type that couldn't satisfy the bound. + ty::Adt(def, _) => bound_spans.push((def_span(def.did), msg)), + // Point at the trait object that couldn't satisfy the bound. + ty::Dynamic(preds, _) => { + for pred in *preds.skip_binder() { + match pred { + ty::ExistentialPredicate::Trait(tr) => { + bound_spans.push((def_span(tr.def_id), msg.clone())) + } + ty::ExistentialPredicate::Projection(_) + | ty::ExistentialPredicate::AutoTrait(_) => {} + } + } + } + // Point at the closure that couldn't satisfy the bound. + ty::Closure(def_id, _) => bound_spans + .push((def_span(*def_id), format!("doesn't satisfy `{}`", quiet))), + _ => {} + } + }; + let mut format_pred = |pred| { + match pred { + ty::Predicate::Projection(pred) => { + // `::Item = String`. + let trait_ref = + pred.skip_binder().projection_ty.trait_ref(self.tcx); + let assoc = self + .tcx + .associated_item(pred.skip_binder().projection_ty.item_def_id); + let ty = pred.skip_binder().ty; + let obligation = format!("{}::{} = {}", trait_ref, assoc.ident, ty); + let quiet = format!( + "<_ as {}>::{} = {}", + trait_ref.print_only_trait_path(), + assoc.ident, + ty + ); + bound_span_label(trait_ref.self_ty(), &obligation, &quiet); + Some((obligation, trait_ref.self_ty())) + } + ty::Predicate::Trait(poly_trait_ref, _) => { + let p = poly_trait_ref.skip_binder().trait_ref; + let self_ty = p.self_ty(); + let path = p.print_only_trait_path(); + let obligation = format!("{}: {}", self_ty, path); + let quiet = format!("_: {}", path); + bound_span_label(self_ty, &obligation, &quiet); + Some((obligation, self_ty)) + } + _ => None, + } + }; let mut bound_list = unsatisfied_predicates .iter() - .map(|p| format!("`{} : {}`", p.self_ty(), p.print_only_trait_path())) - .collect::>(); - bound_list.sort(); - bound_list.dedup(); // #35677 - let bound_list = bound_list.join("\n"); - err.note(&format!( - "the method `{}` exists but the following trait bounds \ - were not satisfied:\n{}", - item_name, bound_list - )); + .filter_map(|(pred, parent_pred)| { + format_pred(*pred).map(|(p, self_ty)| match parent_pred { + None => format!("`{}`", p), + Some(parent_pred) => match format_pred(*parent_pred) { + None => format!("`{}`", p), + Some((parent_p, _)) => { + collect_type_param_suggestions(self_ty, parent_pred, &p); + format!("`{}`\nwhich is required by `{}`", p, parent_p) + } + }, + }) + }) + .enumerate() + .collect::>(); + for ((span, empty_where), obligations) in type_params.into_iter() { + restrict_type_params = true; + err.span_suggestion_verbose( + span, + &format!( + "consider restricting the type parameter{s} to satisfy the \ + trait bound{s}", + s = pluralize!(obligations.len()) + ), + format!( + "{} {}", + if empty_where { " where" } else { "," }, + obligations.into_iter().collect::>().join(", ") + ), + Applicability::MaybeIncorrect, + ); + } + + bound_list.sort_by(|(_, a), (_, b)| a.cmp(&b)); // Sort alphabetically. + bound_list.dedup_by(|(_, a), (_, b)| a == b); // #35677 + bound_list.sort_by_key(|(pos, _)| *pos); // Keep the original predicate order. + bound_spans.sort(); + bound_spans.dedup(); + for (span, msg) in bound_spans.into_iter() { + err.span_label(span, &msg); + } + if !bound_list.is_empty() { + let bound_list = bound_list + .into_iter() + .map(|(_, path)| path) + .collect::>() + .join("\n"); + err.note(&format!( + "the method `{}` exists but the following trait bounds were not \ + satisfied:\n{}", + item_name, bound_list + )); + } } - if actual.is_numeric() && actual.is_fresh() { + if actual.is_numeric() && actual.is_fresh() || restrict_type_params { } else { self.suggest_traits_to_import( &mut err, @@ -558,6 +696,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { item_name, source, out_of_scope_traits, + &unsatisfied_predicates, ); } @@ -757,6 +896,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { item_name: ast::Ident, source: SelfSource<'b>, valid_out_of_scope_traits: Vec, + unsatisfied_predicates: &[(ty::Predicate<'tcx>, Option>)], ) { if self.suggest_valid_traits(err, valid_out_of_scope_traits) { return; @@ -764,6 +904,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let type_is_local = self.type_derefs_to_local(span, rcvr_ty, source); + let mut arbitrary_rcvr = vec![]; // There are no traits implemented, so lets suggest some traits to // implement, by finding ones that have the item name, and are // legal to implement. @@ -776,16 +917,71 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // this isn't perfect (that is, there are cases when // implementing a trait would be legal but is rejected // here). - (type_is_local || info.def_id.is_local()) + !unsatisfied_predicates.iter().any(|(p, _)| match p { + // Hide traits if they are present in predicates as they can be fixed without + // having to implement them. + ty::Predicate::Trait(t, _) => t.def_id() != info.def_id, + ty::Predicate::Projection(p) => p.item_def_id() != info.def_id, + _ => true, + }) && (type_is_local || info.def_id.is_local()) && self .associated_item(info.def_id, item_name, Namespace::ValueNS) .filter(|item| { + if let ty::AssocKind::Method = item.kind { + let id = self.tcx.hir().as_local_hir_id(item.def_id); + if let Some(hir::Node::TraitItem(hir::TraitItem { + kind: hir::TraitItemKind::Method(fn_sig, method), + .. + })) = id.map(|id| self.tcx.hir().get(id)) + { + let self_first_arg = match method { + hir::TraitMethod::Required([ident, ..]) => { + ident.name == kw::SelfLower + } + hir::TraitMethod::Provided(body_id) => { + match &self.tcx.hir().body(*body_id).params[..] { + [hir::Param { + pat: + hir::Pat { + kind: + hir::PatKind::Binding( + _, + _, + ident, + .., + ), + .. + }, + .. + }, ..] => ident.name == kw::SelfLower, + _ => false, + } + } + _ => false, + }; + + if !fn_sig.decl.implicit_self.has_implicit_self() + && self_first_arg + { + if let Some(ty) = fn_sig.decl.inputs.get(0) { + arbitrary_rcvr.push(ty.span); + } + return false; + } + } + } // We only want to suggest public or local traits (#45781). item.vis == ty::Visibility::Public || info.def_id.is_local() }) .is_some() }) .collect::>(); + for span in &arbitrary_rcvr { + err.span_label( + *span, + "the method might not be found because of this arbitrary self type", + ); + } if !candidates.is_empty() { // Sort from most relevant to least relevant. @@ -808,7 +1004,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let message = |action| { format!( "the following {traits_define} an item `{name}`, perhaps you need to {action} \ - {one_of_them}:", + {one_of_them}:", traits_define = if candidates.len() == 1 { "trait defines" } else { "traits define" }, action = action, @@ -906,19 +1102,38 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } if !suggested { - let mut msg = message(if let Some(param) = param_type { + let action = if let Some(param) = param_type { format!("restrict type parameter `{}` with", param) } else { + // FIXME: it might only need to be imported into scope, not implemented. "implement".to_string() - }); - for (i, trait_info) in candidates.iter().enumerate() { - msg.push_str(&format!( - "\ncandidate #{}: `{}`", - i + 1, - self.tcx.def_path_str(trait_info.def_id), - )); + }; + let mut use_note = true; + if let [trait_info] = &candidates[..] { + if let Some(span) = self.tcx.hir().span_if_local(trait_info.def_id) { + err.span_note( + self.tcx.sess.source_map().def_span(span), + &format!( + "`{}` defines an item `{}`, perhaps you need to {} it", + self.tcx.def_path_str(trait_info.def_id), + item_name, + action + ), + ); + use_note = false + } + } + if use_note { + let mut msg = message(action); + for (i, trait_info) in candidates.iter().enumerate() { + msg.push_str(&format!( + "\ncandidate #{}: `{}`", + i + 1, + self.tcx.def_path_str(trait_info.def_id), + )); + } + err.note(&msg[..]); } - err.note(&msg[..]); } } } diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 2f220cbc9be8c..4f58116e4fea8 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -565,8 +565,7 @@ impl Attributes { let inner_docs = attrs .iter() - .filter(|a| a.doc_str().is_some()) - .next() + .find(|a| a.doc_str().is_some()) .map_or(true, |a| a.style == AttrStyle::Inner); Attributes { diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 8c4e65765d32f..43d3ad218295a 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -283,7 +283,7 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt .filter_map(|lint| { // We don't want to whitelist *all* lints so let's // ignore those ones. - if whitelisted_lints.iter().any(|l| &lint.name == l) { + if whitelisted_lints.iter().any(|l| lint.name == l) { None } else { Some((lint::LintId::of(lint), lint::Allow)) diff --git a/src/test/debuginfo/gdb-pretty-struct-and-enums.rs b/src/test/debuginfo/gdb-pretty-struct-and-enums.rs index 7d2b4c95a05d8..cb46b0a84bfed 100644 --- a/src/test/debuginfo/gdb-pretty-struct-and-enums.rs +++ b/src/test/debuginfo/gdb-pretty-struct-and-enums.rs @@ -8,8 +8,8 @@ // gdb-command: run // gdb-command: print regular_struct -// gdbg-check:$1 = RegularStruct = {the_first_field = 101, the_second_field = 102.5, the_third_field = false} -// gdbr-check:$1 = gdb_pretty_struct_and_enums::RegularStruct {the_first_field: 101, the_second_field: 102.5, the_third_field: false} +// gdbg-check:$1 = {the_first_field = 101, the_second_field = 102.5, the_third_field = false} +// gdbr-check:$1 = gdb_pretty_struct_and_enums::RegularStruct = {the_first_field = 101, the_second_field = 102.5, the_third_field = false} // gdb-command: print empty_struct // gdbg-check:$2 = EmptyStruct diff --git a/src/test/debuginfo/pretty-huge-vec.rs b/src/test/debuginfo/pretty-huge-vec.rs index 2e3386b7a360e..d79c9425a42cd 100644 --- a/src/test/debuginfo/pretty-huge-vec.rs +++ b/src/test/debuginfo/pretty-huge-vec.rs @@ -10,10 +10,10 @@ // gdb-command: run // gdb-command: print vec -// gdb-check:$1 = Vec(len: 1000000000, cap: 1000000000) = {[...]...} +// gdb-check:$1 = Vec(size=1000000000) = {[...]...} // gdb-command: print slice -// gdb-check:$2 = &[u8](len: 1000000000) = {[...]...} +// gdb-check:$2 = &[u8] = {data_ptr = [...]"\000", length = 1000000000} #![allow(unused_variables)] diff --git a/src/test/debuginfo/pretty-std-collections.rs b/src/test/debuginfo/pretty-std-collections.rs index f8997fad9a53f..3a7cc3b5d3b85 100644 --- a/src/test/debuginfo/pretty-std-collections.rs +++ b/src/test/debuginfo/pretty-std-collections.rs @@ -15,21 +15,29 @@ // gdb-command: run // gdb-command: print btree_set -// gdb-check:$1 = BTreeSet(len: 15) = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14} +// gdb-check:$1 = BTreeSet(size=15) = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14} // gdb-command: print btree_map -// gdb-check:$2 = BTreeMap(len: 15) = {[0] = 0, [1] = 1, [2] = 2, [3] = 3, [4] = 4, [5] = 5, [6] = 6, [7] = 7, [8] = 8, [9] = 9, [10] = 10, [11] = 11, [12] = 12, [13] = 13, [14] = 14} +// gdb-check:$2 = BTreeMap(size=15) = {[0] = 0, [1] = 1, [2] = 2, [3] = 3, [4] = 4, [5] = 5, [6] = 6, [7] = 7, [8] = 8, [9] = 9, [10] = 10, [11] = 11, [12] = 12, [13] = 13, [14] = 14} // gdb-command: print vec_deque -// gdb-check:$3 = VecDeque(len: 3, cap: 8) = {5, 3, 7} +// gdb-check:$3 = VecDeque(size=3) = {5, 3, 7} // gdb-command: print vec_deque2 -// gdb-check:$4 = VecDeque(len: 7, cap: 8) = {2, 3, 4, 5, 6, 7, 8} +// gdb-check:$4 = VecDeque(size=7) = {2, 3, 4, 5, 6, 7, 8} + +// gdb-command: print hash_map +// gdb-check:$5 = HashMap(size=4) = {[...][1] = 10[...]} + +// gdb-command: print hash_set +// gdb-check:$6 = HashSet(size=4) = {[...]10[...]} #![allow(unused_variables)] use std::collections::BTreeSet; use std::collections::BTreeMap; use std::collections::VecDeque; +use std::collections::HashMap; +use std::collections::HashSet; fn main() { @@ -60,6 +68,18 @@ fn main() { vec_deque2.pop_front(); vec_deque2.push_back(8); + // HashMap + let mut hash_map = HashMap::new(); + for i in 1..5 { + hash_map.insert(i, i * 10); + } + + // HashSet + let mut hash_set = HashSet::new(); + for i in 1..5 { + hash_set.insert(i * 10); + } + zzz(); // #break } diff --git a/src/test/debuginfo/pretty-uninitialized-vec.rs b/src/test/debuginfo/pretty-uninitialized-vec.rs index 37aae65d42b69..26cfc358d97a2 100644 --- a/src/test/debuginfo/pretty-uninitialized-vec.rs +++ b/src/test/debuginfo/pretty-uninitialized-vec.rs @@ -10,7 +10,7 @@ // gdb-command: run // gdb-command: print vec -// gdb-check:$1 = Vec(len: [...], cap: [...])[...] +// gdb-check:$1 = Vec(size=0)[...] #![allow(unused_variables)] diff --git a/src/test/debuginfo/rc_arc.rs b/src/test/debuginfo/rc_arc.rs new file mode 100644 index 0000000000000..01128d69b2541 --- /dev/null +++ b/src/test/debuginfo/rc_arc.rs @@ -0,0 +1,35 @@ +// compile-flags:-g + +// === GDB TESTS ================================================================================== + +// gdb-command:run + +// gdb-command:print r +// gdb-check:[...]$1 = Rc(strong=2, weak=1) = {value = 42, strong = 2, weak = 1} +// gdb-command:print a +// gdb-check:[...]$2 = Arc(strong=2, weak=1) = {value = 42, strong = 2, weak = 1} + + +// === LLDB TESTS ================================================================================== + +// lldb-command:run + +// lldb-command:print r +// lldb-check:[...]$0 = strong=2, weak=1 { value = 42 } +// lldb-command:print a +// lldb-check:[...]$1 = strong=2, weak=1 { data = 42 } + +use std::rc::Rc; +use std::sync::Arc; + +fn main() { + let r = Rc::new(42); + let r1 = Rc::clone(&r); + let w1 = Rc::downgrade(&r); + + let a = Arc::new(42); + let a1 = Arc::clone(&a); + let w2 = Arc::downgrade(&a); + + print!(""); // #break +} diff --git a/src/test/ui/associated-const/associated-const-no-item.stderr b/src/test/ui/associated-const/associated-const-no-item.stderr index d96cf67b87578..fe27da5ac645f 100644 --- a/src/test/ui/associated-const/associated-const-no-item.stderr +++ b/src/test/ui/associated-const/associated-const-no-item.stderr @@ -5,8 +5,11 @@ LL | const X: i32 = ::ID; | ^^ associated item not found in `i32` | = help: items from traits can only be used if the trait is implemented and in scope - = note: the following trait defines an item `ID`, perhaps you need to implement it: - candidate #1: `Foo` +note: `Foo` defines an item `ID`, perhaps you need to implement it + --> $DIR/associated-const-no-item.rs:1:1 + | +LL | trait Foo { + | ^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/auto-ref-slice-plus-ref.stderr b/src/test/ui/auto-ref-slice-plus-ref.stderr index a0739a7a90b0a..50ca5cad4bc68 100644 --- a/src/test/ui/auto-ref-slice-plus-ref.stderr +++ b/src/test/ui/auto-ref-slice-plus-ref.stderr @@ -5,8 +5,11 @@ LL | a.test_mut(); | ^^^^^^^^ help: there is a method with a similar name: `get_mut` | = help: items from traits can only be used if the trait is implemented and in scope - = note: the following trait defines an item `test_mut`, perhaps you need to implement it: - candidate #1: `MyIter` +note: `MyIter` defines an item `test_mut`, perhaps you need to implement it + --> $DIR/auto-ref-slice-plus-ref.rs:14:1 + | +LL | trait MyIter { + | ^^^^^^^^^^^^ error[E0599]: no method named `test` found for struct `std::vec::Vec<{integer}>` in the current scope --> $DIR/auto-ref-slice-plus-ref.rs:8:7 @@ -15,8 +18,11 @@ LL | a.test(); | ^^^^ method not found in `std::vec::Vec<{integer}>` | = help: items from traits can only be used if the trait is implemented and in scope - = note: the following trait defines an item `test`, perhaps you need to implement it: - candidate #1: `MyIter` +note: `MyIter` defines an item `test`, perhaps you need to implement it + --> $DIR/auto-ref-slice-plus-ref.rs:14:1 + | +LL | trait MyIter { + | ^^^^^^^^^^^^ error[E0599]: no method named `test` found for array `[{integer}; 1]` in the current scope --> $DIR/auto-ref-slice-plus-ref.rs:10:11 @@ -25,8 +31,11 @@ LL | ([1]).test(); | ^^^^ method not found in `[{integer}; 1]` | = help: items from traits can only be used if the trait is implemented and in scope - = note: the following trait defines an item `test`, perhaps you need to implement it: - candidate #1: `MyIter` +note: `MyIter` defines an item `test`, perhaps you need to implement it + --> $DIR/auto-ref-slice-plus-ref.rs:14:1 + | +LL | trait MyIter { + | ^^^^^^^^^^^^ error[E0599]: no method named `test` found for reference `&[{integer}; 1]` in the current scope --> $DIR/auto-ref-slice-plus-ref.rs:11:12 @@ -35,8 +44,11 @@ LL | (&[1]).test(); | ^^^^ method not found in `&[{integer}; 1]` | = help: items from traits can only be used if the trait is implemented and in scope - = note: the following trait defines an item `test`, perhaps you need to implement it: - candidate #1: `MyIter` +note: `MyIter` defines an item `test`, perhaps you need to implement it + --> $DIR/auto-ref-slice-plus-ref.rs:14:1 + | +LL | trait MyIter { + | ^^^^^^^^^^^^ error: aborting due to 4 previous errors diff --git a/src/test/ui/consts/too_generic_eval_ice.stderr b/src/test/ui/consts/too_generic_eval_ice.stderr index fd68cb9c6cf85..8836de0023c9d 100644 --- a/src/test/ui/consts/too_generic_eval_ice.stderr +++ b/src/test/ui/consts/too_generic_eval_ice.stderr @@ -8,8 +8,8 @@ LL | [5; Self::HOST_SIZE] == [6; 0] | ^^^^^^^^^ associated item not found in `Foo` | = note: the method `HOST_SIZE` exists but the following trait bounds were not satisfied: - `A : std::marker::Sized` - `B : std::marker::Sized` + `A: std::marker::Sized` + `B: std::marker::Sized` error[E0277]: the size for values of type `A` cannot be known at compilation time --> $DIR/too_generic_eval_ice.rs:7:13 diff --git a/src/test/ui/derives/derive-assoc-type-not-impl.stderr b/src/test/ui/derives/derive-assoc-type-not-impl.stderr index 2083a1d65220f..c4c85773fbc1d 100644 --- a/src/test/ui/derives/derive-assoc-type-not-impl.stderr +++ b/src/test/ui/derives/derive-assoc-type-not-impl.stderr @@ -2,13 +2,20 @@ error[E0599]: no method named `clone` found for struct `Bar` in the cu --> $DIR/derive-assoc-type-not-impl.rs:18:30 | LL | struct Bar { - | ------------------ method `clone` not found for this + | ------------------ + | | + | method `clone` not found for this + | doesn't satisfy `Bar: std::clone::Clone` +... +LL | struct NotClone; + | ---------------- doesn't satisfy `NotClone: std::clone::Clone` ... LL | Bar:: { x: 1 }.clone(); | ^^^^^ method not found in `Bar` | = note: the method `clone` exists but the following trait bounds were not satisfied: - `Bar : std::clone::Clone` + `NotClone: std::clone::Clone` + which is required by `Bar: std::clone::Clone` = help: items from traits can only be used if the trait is implemented and in scope = note: the following trait defines an item `clone`, perhaps you need to implement it: candidate #1: `std::clone::Clone` diff --git a/src/test/ui/duplicate/dupe-symbols-7.rs b/src/test/ui/duplicate/dupe-symbols-7.rs index 89a32c61620fd..633ca4c318952 100644 --- a/src/test/ui/duplicate/dupe-symbols-7.rs +++ b/src/test/ui/duplicate/dupe-symbols-7.rs @@ -1,7 +1,7 @@ // build-fail // -// error-pattern: entry symbol `main` defined multiple times +// error-pattern: entry symbol `main` declared multiple times // FIXME https://github.com/rust-lang/rust/issues/59774 // normalize-stderr-test "thread.*panicked.*Metadata module not compiled.*\n" -> "" diff --git a/src/test/ui/duplicate/dupe-symbols-7.stderr b/src/test/ui/duplicate/dupe-symbols-7.stderr index 608ae27110aa0..2ea5521e09533 100644 --- a/src/test/ui/duplicate/dupe-symbols-7.stderr +++ b/src/test/ui/duplicate/dupe-symbols-7.stderr @@ -1,4 +1,4 @@ -error: entry symbol `main` defined multiple times +error: entry symbol `main` declared multiple times --> $DIR/dupe-symbols-7.rs:12:1 | LL | fn main(){} diff --git a/src/test/ui/duplicate/dupe-symbols-8.rs b/src/test/ui/duplicate/dupe-symbols-8.rs new file mode 100644 index 0000000000000..ce7fa24a9fe6b --- /dev/null +++ b/src/test/ui/duplicate/dupe-symbols-8.rs @@ -0,0 +1,12 @@ +// build-fail +// error-pattern: entry symbol `main` declared multiple times +// +// See #67946. + +#![allow(warnings)] +fn main() { + extern "Rust" { + fn main(); + } + unsafe { main(); } +} diff --git a/src/test/ui/duplicate/dupe-symbols-8.stderr b/src/test/ui/duplicate/dupe-symbols-8.stderr new file mode 100644 index 0000000000000..f001201b8d0cf --- /dev/null +++ b/src/test/ui/duplicate/dupe-symbols-8.stderr @@ -0,0 +1,15 @@ +error: entry symbol `main` declared multiple times + --> $DIR/dupe-symbols-8.rs:7:1 + | +LL | / fn main() { +LL | | extern "Rust" { +LL | | fn main(); +LL | | } +LL | | unsafe { main(); } +LL | | } + | |_^ + | + = help: did you use `#[no_mangle]` on `fn main`? Use `#[start]` instead + +error: aborting due to previous error + diff --git a/src/test/ui/impl-trait/issues/issue-21659-show-relevant-trait-impls-3.stderr b/src/test/ui/impl-trait/issues/issue-21659-show-relevant-trait-impls-3.stderr index 57417975474f7..64cce056a2688 100644 --- a/src/test/ui/impl-trait/issues/issue-21659-show-relevant-trait-impls-3.stderr +++ b/src/test/ui/impl-trait/issues/issue-21659-show-relevant-trait-impls-3.stderr @@ -8,8 +8,11 @@ LL | f1.foo(1usize); | ^^^ method not found in `Bar` | = help: items from traits can only be used if the trait is implemented and in scope - = note: the following trait defines an item `foo`, perhaps you need to implement it: - candidate #1: `Foo` +note: `Foo` defines an item `foo`, perhaps you need to implement it + --> $DIR/issue-21659-show-relevant-trait-impls-3.rs:1:1 + | +LL | trait Foo { + | ^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/impl-trait/no-method-suggested-traits.stderr b/src/test/ui/impl-trait/no-method-suggested-traits.stderr index da25617e18759..c0ca341385df5 100644 --- a/src/test/ui/impl-trait/no-method-suggested-traits.stderr +++ b/src/test/ui/impl-trait/no-method-suggested-traits.stderr @@ -126,8 +126,11 @@ LL | 1u64.method2(); | ^^^^^^^ method not found in `u64` | = help: items from traits can only be used if the trait is implemented and in scope - = note: the following trait defines an item `method2`, perhaps you need to implement it: - candidate #1: `foo::Bar` +note: `foo::Bar` defines an item `method2`, perhaps you need to implement it + --> $DIR/no-method-suggested-traits.rs:8:5 + | +LL | pub trait Bar { + | ^^^^^^^^^^^^^ error[E0599]: no method named `method2` found for struct `std::rc::Rc<&mut std::boxed::Box<&u64>>` in the current scope --> $DIR/no-method-suggested-traits.rs:47:44 @@ -136,8 +139,11 @@ LL | std::rc::Rc::new(&mut Box::new(&1u64)).method2(); | ^^^^^^^ method not found in `std::rc::Rc<&mut std::boxed::Box<&u64>>` | = help: items from traits can only be used if the trait is implemented and in scope - = note: the following trait defines an item `method2`, perhaps you need to implement it: - candidate #1: `foo::Bar` +note: `foo::Bar` defines an item `method2`, perhaps you need to implement it + --> $DIR/no-method-suggested-traits.rs:8:5 + | +LL | pub trait Bar { + | ^^^^^^^^^^^^^ error[E0599]: no method named `method2` found for struct `no_method_suggested_traits::Foo` in the current scope --> $DIR/no-method-suggested-traits.rs:50:37 @@ -146,8 +152,11 @@ LL | no_method_suggested_traits::Foo.method2(); | ^^^^^^^ method not found in `no_method_suggested_traits::Foo` | = help: items from traits can only be used if the trait is implemented and in scope - = note: the following trait defines an item `method2`, perhaps you need to implement it: - candidate #1: `foo::Bar` +note: `foo::Bar` defines an item `method2`, perhaps you need to implement it + --> $DIR/no-method-suggested-traits.rs:8:5 + | +LL | pub trait Bar { + | ^^^^^^^^^^^^^ error[E0599]: no method named `method2` found for struct `std::rc::Rc<&mut std::boxed::Box<&no_method_suggested_traits::Foo>>` in the current scope --> $DIR/no-method-suggested-traits.rs:52:71 @@ -156,8 +165,11 @@ LL | std::rc::Rc::new(&mut Box::new(&no_method_suggested_traits::Foo)).metho | ^^^^^^^ method not found in `std::rc::Rc<&mut std::boxed::Box<&no_method_suggested_traits::Foo>>` | = help: items from traits can only be used if the trait is implemented and in scope - = note: the following trait defines an item `method2`, perhaps you need to implement it: - candidate #1: `foo::Bar` +note: `foo::Bar` defines an item `method2`, perhaps you need to implement it + --> $DIR/no-method-suggested-traits.rs:8:5 + | +LL | pub trait Bar { + | ^^^^^^^^^^^^^ error[E0599]: no method named `method2` found for enum `no_method_suggested_traits::Bar` in the current scope --> $DIR/no-method-suggested-traits.rs:54:40 @@ -166,8 +178,11 @@ LL | no_method_suggested_traits::Bar::X.method2(); | ^^^^^^^ method not found in `no_method_suggested_traits::Bar` | = help: items from traits can only be used if the trait is implemented and in scope - = note: the following trait defines an item `method2`, perhaps you need to implement it: - candidate #1: `foo::Bar` +note: `foo::Bar` defines an item `method2`, perhaps you need to implement it + --> $DIR/no-method-suggested-traits.rs:8:5 + | +LL | pub trait Bar { + | ^^^^^^^^^^^^^ error[E0599]: no method named `method2` found for struct `std::rc::Rc<&mut std::boxed::Box<&no_method_suggested_traits::Bar>>` in the current scope --> $DIR/no-method-suggested-traits.rs:56:74 @@ -176,8 +191,11 @@ LL | std::rc::Rc::new(&mut Box::new(&no_method_suggested_traits::Bar::X)).me | ^^^^^^^ method not found in `std::rc::Rc<&mut std::boxed::Box<&no_method_suggested_traits::Bar>>` | = help: items from traits can only be used if the trait is implemented and in scope - = note: the following trait defines an item `method2`, perhaps you need to implement it: - candidate #1: `foo::Bar` +note: `foo::Bar` defines an item `method2`, perhaps you need to implement it + --> $DIR/no-method-suggested-traits.rs:8:5 + | +LL | pub trait Bar { + | ^^^^^^^^^^^^^ error[E0599]: no method named `method3` found for struct `Foo` in the current scope --> $DIR/no-method-suggested-traits.rs:59:9 diff --git a/src/test/ui/issues/issue-21596.stderr b/src/test/ui/issues/issue-21596.stderr index efde16167b71b..3e0a532b2b8f3 100644 --- a/src/test/ui/issues/issue-21596.stderr +++ b/src/test/ui/issues/issue-21596.stderr @@ -7,7 +7,8 @@ LL | println!("{}", z.to_string()); = note: try using `<*const T>::as_ref()` to get a reference to the type behind the pointer: https://doc.rust-lang.org/std/primitive.pointer.html#method.as_ref = note: using `<*const T>::as_ref()` on a pointer which is unaligned or points to invalid or uninitialized memory is undefined behavior = note: the method `to_string` exists but the following trait bounds were not satisfied: - `*const u8 : std::string::ToString` + `*const u8: std::fmt::Display` + which is required by `*const u8: std::string::ToString` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-31173.rs b/src/test/ui/issues/issue-31173.rs index 26195318380d2..25be266c52893 100644 --- a/src/test/ui/issues/issue-31173.rs +++ b/src/test/ui/issues/issue-31173.rs @@ -1,3 +1,7 @@ +// FIXME: missing sysroot spans (#53081) +// ignore-i586-unknown-linux-gnu +// ignore-i586-unknown-linux-musl +// ignore-i686-unknown-linux-musl use std::vec::IntoIter; pub fn get_tok(it: &mut IntoIter) { diff --git a/src/test/ui/issues/issue-31173.stderr b/src/test/ui/issues/issue-31173.stderr index a614b96ac1439..20bfdeea4b1fa 100644 --- a/src/test/ui/issues/issue-31173.stderr +++ b/src/test/ui/issues/issue-31173.stderr @@ -1,5 +1,5 @@ -error[E0271]: type mismatch resolving `, [closure@$DIR/issue-31173.rs:6:39: 9:6 found_e:_]> as std::iter::Iterator>::Item == &_` - --> $DIR/issue-31173.rs:10:10 +error[E0271]: type mismatch resolving `, [closure@$DIR/issue-31173.rs:10:39: 13:6 found_e:_]> as std::iter::Iterator>::Item == &_` + --> $DIR/issue-31173.rs:14:10 | LL | .cloned() | ^^^^^^ expected `u8`, found reference @@ -7,15 +7,25 @@ LL | .cloned() = note: expected type `u8` found reference `&_` -error[E0599]: no method named `collect` found for struct `std::iter::Cloned, [closure@$DIR/issue-31173.rs:6:39: 9:6 found_e:_]>>` in the current scope - --> $DIR/issue-31173.rs:14:10 +error[E0599]: no method named `collect` found for struct `std::iter::Cloned, [closure@$DIR/issue-31173.rs:10:39: 13:6 found_e:_]>>` in the current scope + --> $DIR/issue-31173.rs:18:10 | LL | .collect(); - | ^^^^^^^ method not found in `std::iter::Cloned, [closure@$DIR/issue-31173.rs:6:39: 9:6 found_e:_]>>` + | ^^^^^^^ method not found in `std::iter::Cloned, [closure@$DIR/issue-31173.rs:10:39: 13:6 found_e:_]>>` + | + ::: $SRC_DIR/libcore/iter/adapters/mod.rs:LL:COL + | +LL | pub struct Cloned { + | -------------------- doesn't satisfy `_: std::iter::Iterator` +... +LL | pub struct TakeWhile { + | -------------------------- doesn't satisfy `<_ as std::iter::Iterator>::Item = &_` | = note: the method `collect` exists but the following trait bounds were not satisfied: - `&mut std::iter::Cloned, [closure@$DIR/issue-31173.rs:6:39: 9:6 found_e:_]>> : std::iter::Iterator` - `std::iter::Cloned, [closure@$DIR/issue-31173.rs:6:39: 9:6 found_e:_]>> : std::iter::Iterator` + `, [closure@$DIR/issue-31173.rs:10:39: 13:6 found_e:_]> as std::iter::Iterator>::Item = &_` + which is required by `std::iter::Cloned, [closure@$DIR/issue-31173.rs:10:39: 13:6 found_e:_]>>: std::iter::Iterator` + `std::iter::Cloned, [closure@$DIR/issue-31173.rs:10:39: 13:6 found_e:_]>>: std::iter::Iterator` + which is required by `&mut std::iter::Cloned, [closure@$DIR/issue-31173.rs:10:39: 13:6 found_e:_]>>: std::iter::Iterator` error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-35677.stderr b/src/test/ui/issues/issue-35677.stderr index a998f95d306cb..978221e502f80 100644 --- a/src/test/ui/issues/issue-35677.stderr +++ b/src/test/ui/issues/issue-35677.stderr @@ -5,8 +5,8 @@ LL | this.is_subset(other) | ^^^^^^^^^ method not found in `&std::collections::HashSet` | = note: the method `is_subset` exists but the following trait bounds were not satisfied: - `T : std::cmp::Eq` - `T : std::hash::Hash` + `T: std::cmp::Eq` + `T: std::hash::Hash` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-50264-inner-deref-trait/option-as_deref.stderr b/src/test/ui/issues/issue-50264-inner-deref-trait/option-as_deref.stderr index f91f6e891ed90..5db521536a804 100644 --- a/src/test/ui/issues/issue-50264-inner-deref-trait/option-as_deref.stderr +++ b/src/test/ui/issues/issue-50264-inner-deref-trait/option-as_deref.stderr @@ -5,7 +5,8 @@ LL | let _result = &Some(42).as_deref(); | ^^^^^^^^ help: there is a method with a similar name: `as_ref` | = note: the method `as_deref` exists but the following trait bounds were not satisfied: - `{integer} : std::ops::Deref` + `{integer}: std::ops::Deref` + `<{integer} as std::ops::Deref>::Target = _` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-50264-inner-deref-trait/option-as_deref_mut.stderr b/src/test/ui/issues/issue-50264-inner-deref-trait/option-as_deref_mut.stderr index 583236345cac1..f2133c8c84d21 100644 --- a/src/test/ui/issues/issue-50264-inner-deref-trait/option-as_deref_mut.stderr +++ b/src/test/ui/issues/issue-50264-inner-deref-trait/option-as_deref_mut.stderr @@ -5,7 +5,8 @@ LL | let _result = &mut Some(42).as_deref_mut(); | ^^^^^^^^^^^^ method not found in `std::option::Option<{integer}>` | = note: the method `as_deref_mut` exists but the following trait bounds were not satisfied: - `{integer} : std::ops::DerefMut` + `{integer}: std::ops::DerefMut` + `<{integer} as std::ops::Deref>::Target = _` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref.stderr b/src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref.stderr index fae11fe62b16c..2dfc6d53750e7 100644 --- a/src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref.stderr +++ b/src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref.stderr @@ -5,7 +5,8 @@ LL | let _result = &Ok(42).as_deref(); | ^^^^^^^^ help: there is a method with a similar name: `as_ref` | = note: the method `as_deref` exists but the following trait bounds were not satisfied: - `{integer} : std::ops::Deref` + `{integer}: std::ops::Deref` + `<{integer} as std::ops::Deref>::Target = _` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref_err.stderr b/src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref_err.stderr index 1d98361c46198..1d65c57e5e9ec 100644 --- a/src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref_err.stderr +++ b/src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref_err.stderr @@ -5,7 +5,8 @@ LL | let _result = &Err(41).as_deref_err(); | ^^^^^^^^^^^^ help: there is a method with a similar name: `as_deref_mut` | = note: the method `as_deref_err` exists but the following trait bounds were not satisfied: - `{integer} : std::ops::Deref` + `{integer}: std::ops::Deref` + `<{integer} as std::ops::Deref>::Target = _` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref_mut.stderr b/src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref_mut.stderr index 2c6231fb3b589..2f4bf0c94b5cb 100644 --- a/src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref_mut.stderr +++ b/src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref_mut.stderr @@ -5,7 +5,8 @@ LL | let _result = &mut Ok(42).as_deref_mut(); | ^^^^^^^^^^^^ help: there is a method with a similar name: `as_deref_err` | = note: the method `as_deref_mut` exists but the following trait bounds were not satisfied: - `{integer} : std::ops::DerefMut` + `{integer}: std::ops::DerefMut` + `<{integer} as std::ops::Deref>::Target = _` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref_mut_err.stderr b/src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref_mut_err.stderr index 950a050ea9f81..b76d36c804e5f 100644 --- a/src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref_mut_err.stderr +++ b/src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref_mut_err.stderr @@ -5,7 +5,8 @@ LL | let _result = &mut Err(41).as_deref_mut_err(); | ^^^^^^^^^^^^^^^^ help: there is a method with a similar name: `as_deref_mut` | = note: the method `as_deref_mut_err` exists but the following trait bounds were not satisfied: - `{integer} : std::ops::DerefMut` + `{integer}: std::ops::DerefMut` + `<{integer} as std::ops::Deref>::Target = _` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-5153.stderr b/src/test/ui/issues/issue-5153.stderr index 4680c8b131c50..93aaf4b9d8237 100644 --- a/src/test/ui/issues/issue-5153.stderr +++ b/src/test/ui/issues/issue-5153.stderr @@ -1,12 +1,11 @@ error[E0599]: no method named `foo` found for reference `&dyn Foo` in the current scope --> $DIR/issue-5153.rs:10:27 | +LL | fn foo(self: Box); + | --------- the method might not be found because of this arbitrary self type +... LL | (&5isize as &dyn Foo).foo(); | ^^^ method not found in `&dyn Foo` - | - = help: items from traits can only be used if the trait is implemented and in scope - = note: the following trait defines an item `foo`, perhaps you need to implement it: - candidate #1: `Foo` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-57362-1.stderr b/src/test/ui/issues/issue-57362-1.stderr index ad596db13ccfd..5c611cd43d3cc 100644 --- a/src/test/ui/issues/issue-57362-1.stderr +++ b/src/test/ui/issues/issue-57362-1.stderr @@ -6,8 +6,11 @@ LL | a.f(); | = note: `a` is a function, perhaps you wish to call it = help: items from traits can only be used if the trait is implemented and in scope - = note: the following trait defines an item `f`, perhaps you need to implement it: - candidate #1: `Trait` +note: `Trait` defines an item `f`, perhaps you need to implement it + --> $DIR/issue-57362-1.rs:8:1 + | +LL | trait Trait { + | ^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-57362-2.stderr b/src/test/ui/issues/issue-57362-2.stderr index 3528084f6ceb4..2edc009746455 100644 --- a/src/test/ui/issues/issue-57362-2.stderr +++ b/src/test/ui/issues/issue-57362-2.stderr @@ -5,8 +5,11 @@ LL | let x = ::make_g(); | ^^^^^^ function or associated item not found in `for<'r> fn(&'r ())` | = help: items from traits can only be used if the trait is implemented and in scope - = note: the following trait defines an item `make_g`, perhaps you need to implement it: - candidate #1: `X` +note: `X` defines an item `make_g`, perhaps you need to implement it + --> $DIR/issue-57362-2.rs:8:1 + | +LL | trait X { + | ^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/methods/method-call-err-msg.stderr b/src/test/ui/methods/method-call-err-msg.stderr index ab1ef5b9d5aed..4678642dd6d0c 100644 --- a/src/test/ui/methods/method-call-err-msg.stderr +++ b/src/test/ui/methods/method-call-err-msg.stderr @@ -35,17 +35,20 @@ error[E0599]: no method named `take` found for struct `Foo` in the current scope --> $DIR/method-call-err-msg.rs:19:7 | LL | pub struct Foo; - | --------------- method `take` not found for this + | --------------- + | | + | method `take` not found for this + | doesn't satisfy `Foo: std::iter::Iterator` ... LL | .take() | ^^^^ method not found in `Foo` | = note: the method `take` exists but the following trait bounds were not satisfied: - `&mut Foo : std::iter::Iterator` + `Foo: std::iter::Iterator` + which is required by `&mut Foo: std::iter::Iterator` = help: items from traits can only be used if the trait is implemented and in scope - = note: the following traits define an item `take`, perhaps you need to implement one of them: - candidate #1: `std::io::Read` - candidate #2: `std::iter::Iterator` + = note: the following trait defines an item `take`, perhaps you need to implement it: + candidate #1: `std::iter::Iterator` error[E0061]: this function takes 3 arguments but 0 arguments were supplied --> $DIR/method-call-err-msg.rs:21:7 diff --git a/src/test/ui/mismatched_types/issue-36053-2.rs b/src/test/ui/mismatched_types/issue-36053-2.rs index 9035e3380b0c5..36211b4ce701d 100644 --- a/src/test/ui/mismatched_types/issue-36053-2.rs +++ b/src/test/ui/mismatched_types/issue-36053-2.rs @@ -1,3 +1,7 @@ +// FIXME: missing sysroot spans (#53081) +// ignore-i586-unknown-linux-gnu +// ignore-i586-unknown-linux-musl +// ignore-i686-unknown-linux-musl // Regression test for #36053. ICE was caused due to obligations // being added to a special, dedicated fulfillment cx during // a probe. diff --git a/src/test/ui/mismatched_types/issue-36053-2.stderr b/src/test/ui/mismatched_types/issue-36053-2.stderr index f8d677b99d693..f8c0470172d19 100644 --- a/src/test/ui/mismatched_types/issue-36053-2.stderr +++ b/src/test/ui/mismatched_types/issue-36053-2.stderr @@ -1,15 +1,27 @@ -error[E0599]: no method named `count` found for struct `std::iter::Filter>, [closure@$DIR/issue-36053-2.rs:7:39: 7:53]>` in the current scope - --> $DIR/issue-36053-2.rs:7:55 +error[E0599]: no method named `count` found for struct `std::iter::Filter>, [closure@$DIR/issue-36053-2.rs:11:39: 11:53]>` in the current scope + --> $DIR/issue-36053-2.rs:11:55 | LL | once::<&str>("str").fuse().filter(|a: &str| true).count(); - | ^^^^^ method not found in `std::iter::Filter>, [closure@$DIR/issue-36053-2.rs:7:39: 7:53]>` + | -------------- ^^^^^ method not found in `std::iter::Filter>, [closure@$DIR/issue-36053-2.rs:11:39: 11:53]>` + | | + | doesn't satisfy `<_ as std::ops::FnOnce<(&&str,)>>::Output = bool` + | doesn't satisfy `_: std::ops::FnMut<(&&str,)>` + | + ::: $SRC_DIR/libcore/iter/adapters/mod.rs:LL:COL + | +LL | pub struct Filter { + | ----------------------- doesn't satisfy `_: std::iter::Iterator` | = note: the method `count` exists but the following trait bounds were not satisfied: - `&mut std::iter::Filter>, [closure@$DIR/issue-36053-2.rs:7:39: 7:53]> : std::iter::Iterator` - `std::iter::Filter>, [closure@$DIR/issue-36053-2.rs:7:39: 7:53]> : std::iter::Iterator` + `<[closure@$DIR/issue-36053-2.rs:11:39: 11:53] as std::ops::FnOnce<(&&str,)>>::Output = bool` + which is required by `std::iter::Filter>, [closure@$DIR/issue-36053-2.rs:11:39: 11:53]>: std::iter::Iterator` + `[closure@$DIR/issue-36053-2.rs:11:39: 11:53]: std::ops::FnMut<(&&str,)>` + which is required by `std::iter::Filter>, [closure@$DIR/issue-36053-2.rs:11:39: 11:53]>: std::iter::Iterator` + `std::iter::Filter>, [closure@$DIR/issue-36053-2.rs:11:39: 11:53]>: std::iter::Iterator` + which is required by `&mut std::iter::Filter>, [closure@$DIR/issue-36053-2.rs:11:39: 11:53]>: std::iter::Iterator` error[E0631]: type mismatch in closure arguments - --> $DIR/issue-36053-2.rs:7:32 + --> $DIR/issue-36053-2.rs:11:32 | LL | once::<&str>("str").fuse().filter(|a: &str| true).count(); | ^^^^^^ -------------- found signature of `for<'r> fn(&'r str) -> _` diff --git a/src/test/ui/mismatched_types/method-help-unsatisfied-bound.stderr b/src/test/ui/mismatched_types/method-help-unsatisfied-bound.stderr index bbfb00050566a..5ab191b927049 100644 --- a/src/test/ui/mismatched_types/method-help-unsatisfied-bound.stderr +++ b/src/test/ui/mismatched_types/method-help-unsatisfied-bound.stderr @@ -1,11 +1,14 @@ error[E0599]: no method named `unwrap` found for enum `std::result::Result<(), Foo>` in the current scope --> $DIR/method-help-unsatisfied-bound.rs:5:7 | +LL | struct Foo; + | ----------- doesn't satisfy `Foo: std::fmt::Debug` +... LL | a.unwrap(); | ^^^^^^ method not found in `std::result::Result<(), Foo>` | = note: the method `unwrap` exists but the following trait bounds were not satisfied: - `Foo : std::fmt::Debug` + `Foo: std::fmt::Debug` error: aborting due to previous error diff --git a/src/test/ui/never_type/issue-2149.stderr b/src/test/ui/never_type/issue-2149.stderr index 9645244751dab..3cdd6372ec18c 100644 --- a/src/test/ui/never_type/issue-2149.stderr +++ b/src/test/ui/never_type/issue-2149.stderr @@ -13,8 +13,11 @@ LL | ["hi"].bind(|x| [x] ); | ^^^^ method not found in `[&str; 1]` | = help: items from traits can only be used if the trait is implemented and in scope - = note: the following trait defines an item `bind`, perhaps you need to implement it: - candidate #1: `VecMonad` +note: `VecMonad` defines an item `bind`, perhaps you need to implement it + --> $DIR/issue-2149.rs:1:1 + | +LL | trait VecMonad { + | ^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/object-pointer-types.stderr b/src/test/ui/object-pointer-types.stderr index 855894b4495c6..021aa8670f78f 100644 --- a/src/test/ui/object-pointer-types.stderr +++ b/src/test/ui/object-pointer-types.stderr @@ -1,22 +1,20 @@ error[E0599]: no method named `owned` found for reference `&dyn Foo` in the current scope --> $DIR/object-pointer-types.rs:11:7 | +LL | fn owned(self: Box); + | --------- the method might not be found because of this arbitrary self type +... LL | x.owned(); | ^^^^^ method not found in `&dyn Foo` - | - = help: items from traits can only be used if the trait is implemented and in scope - = note: the following trait defines an item `owned`, perhaps you need to implement it: - candidate #1: `Foo` error[E0599]: no method named `owned` found for mutable reference `&mut dyn Foo` in the current scope --> $DIR/object-pointer-types.rs:17:7 | +LL | fn owned(self: Box); + | --------- the method might not be found because of this arbitrary self type +... LL | x.owned(); | ^^^^^ method not found in `&mut dyn Foo` - | - = help: items from traits can only be used if the trait is implemented and in scope - = note: the following trait defines an item `owned`, perhaps you need to implement it: - candidate #1: `Foo` error[E0599]: no method named `managed` found for struct `std::boxed::Box<(dyn Foo + 'static)>` in the current scope --> $DIR/object-pointer-types.rs:23:7 diff --git a/src/test/ui/self/point-at-arbitrary-self-type-trait-method.stderr b/src/test/ui/self/point-at-arbitrary-self-type-trait-method.stderr index 28a7b68a6821f..37873031da3e9 100644 --- a/src/test/ui/self/point-at-arbitrary-self-type-trait-method.stderr +++ b/src/test/ui/self/point-at-arbitrary-self-type-trait-method.stderr @@ -2,16 +2,14 @@ error[E0599]: no method named `foo` found for struct `A` in the current scope --> $DIR/point-at-arbitrary-self-type-trait-method.rs:9:7 | LL | trait B { fn foo(self: Box); } - | --- the method is available for `std::boxed::Box` here + | --- --------- the method might not be found because of this arbitrary self type + | | + | the method is available for `std::boxed::Box` here LL | struct A; | --------- method `foo` not found for this ... LL | A.foo() | ^^^ method not found in `A` - | - = help: items from traits can only be used if the trait is implemented and in scope - = note: the following trait defines an item `foo`, perhaps you need to implement it: - candidate #1: `B` error: aborting due to previous error diff --git a/src/test/ui/specialization/defaultimpl/specialization-trait-not-implemented.stderr b/src/test/ui/specialization/defaultimpl/specialization-trait-not-implemented.stderr index 19809778a5e36..a55d79ee03534 100644 --- a/src/test/ui/specialization/defaultimpl/specialization-trait-not-implemented.stderr +++ b/src/test/ui/specialization/defaultimpl/specialization-trait-not-implemented.stderr @@ -2,16 +2,22 @@ error[E0599]: no method named `foo_one` found for struct `MyStruct` in the curre --> $DIR/specialization-trait-not-implemented.rs:22:29 | LL | struct MyStruct; - | ---------------- method `foo_one` not found for this + | ---------------- + | | + | method `foo_one` not found for this + | doesn't satisfy `MyStruct: Foo` ... LL | println!("{}", MyStruct.foo_one()); | ^^^^^^^ method not found in `MyStruct` | = note: the method `foo_one` exists but the following trait bounds were not satisfied: - `MyStruct : Foo` + `MyStruct: Foo` = help: items from traits can only be used if the trait is implemented and in scope - = note: the following trait defines an item `foo_one`, perhaps you need to implement it: - candidate #1: `Foo` +note: `Foo` defines an item `foo_one`, perhaps you need to implement it + --> $DIR/specialization-trait-not-implemented.rs:7:1 + | +LL | trait Foo { + | ^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/suggestions/missing-trait-bounds-for-method-call.rs b/src/test/ui/suggestions/missing-trait-bounds-for-method-call.rs new file mode 100644 index 0000000000000..fefdf149f556c --- /dev/null +++ b/src/test/ui/suggestions/missing-trait-bounds-for-method-call.rs @@ -0,0 +1,31 @@ +#[derive(Default, PartialEq)] +struct Foo { + bar: Box<[T]>, +} + +trait Bar { + fn foo(&self) {} +} + +impl Bar for Foo {} + +impl Foo { + fn bar(&self) { + self.foo(); + //~^ ERROR no method named `foo` found for reference `&Foo` in the current scope + } +} + +struct Fin where T: Bar { + bar: Box<[T]>, +} + +impl Bar for Fin {} + +impl Fin { + fn bar(&self) { + self.foo(); + //~^ ERROR no method named `foo` found for reference `&Fin` in the current scope + } +} +fn main() {} diff --git a/src/test/ui/suggestions/missing-trait-bounds-for-method-call.stderr b/src/test/ui/suggestions/missing-trait-bounds-for-method-call.stderr new file mode 100644 index 0000000000000..c6d94826c0c86 --- /dev/null +++ b/src/test/ui/suggestions/missing-trait-bounds-for-method-call.stderr @@ -0,0 +1,39 @@ +error[E0599]: no method named `foo` found for reference `&Foo` in the current scope + --> $DIR/missing-trait-bounds-for-method-call.rs:14:14 + | +LL | struct Foo { + | ------------- doesn't satisfy `Foo: Bar` +... +LL | self.foo(); + | ^^^ method not found in `&Foo` + | + = note: the method `foo` exists but the following trait bounds were not satisfied: + `T: Bar` + which is required by `Foo: Bar` + `T: std::default::Default` + which is required by `Foo: Bar` +help: consider restricting the type parameters to satisfy the trait bounds + | +LL | struct Foo where T: Bar, T: std::default::Default { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0599]: no method named `foo` found for reference `&Fin` in the current scope + --> $DIR/missing-trait-bounds-for-method-call.rs:27:14 + | +LL | struct Fin where T: Bar { + | -------------------------- doesn't satisfy `Fin: Bar` +... +LL | self.foo(); + | ^^^ method not found in `&Fin` + | + = note: the method `foo` exists but the following trait bounds were not satisfied: + `T: std::default::Default` + which is required by `Fin: Bar` +help: consider restricting the type parameter to satisfy the trait bound + | +LL | struct Fin where T: Bar, T: std::default::Default { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0599`. diff --git a/src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr b/src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr index 8dc041ace3662..57a389cbb49b5 100644 --- a/src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr +++ b/src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr @@ -30,9 +30,15 @@ error[E0599]: no method named `write_fmt` found for struct `std::io::BufWriter<& | LL | writeln!(fp, "hello world").unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ method not found in `std::io::BufWriter<&dyn std::io::Write>` + | + ::: $SRC_DIR/libstd/io/buffered.rs:LL:COL + | +LL | pub struct BufWriter { + | ------------------------------ doesn't satisfy `_: std::io::Write` | = note: the method `write_fmt` exists but the following trait bounds were not satisfied: - `std::io::BufWriter<&dyn std::io::Write> : std::io::Write` + `&dyn std::io::Write: std::io::Write` + which is required by `std::io::BufWriter<&dyn std::io::Write>: std::io::Write` = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 4 previous errors diff --git a/src/test/ui/traits/trait-item-privacy.stderr b/src/test/ui/traits/trait-item-privacy.stderr index 072328ab50c70..2c0591c95f690 100644 --- a/src/test/ui/traits/trait-item-privacy.stderr +++ b/src/test/ui/traits/trait-item-privacy.stderr @@ -8,8 +8,11 @@ LL | S.a(); | ^ method not found in `S` | = help: items from traits can only be used if the trait is implemented and in scope - = note: the following trait defines an item `a`, perhaps you need to implement it: - candidate #1: `method::A` +note: `method::A` defines an item `a`, perhaps you need to implement it + --> $DIR/trait-item-privacy.rs:6:5 + | +LL | trait A { + | ^^^^^^^ error[E0599]: no method named `b` found for struct `S` in the current scope --> $DIR/trait-item-privacy.rs:68:7 @@ -49,8 +52,11 @@ LL | S::a(&S); | ^ function or associated item not found in `S` | = help: items from traits can only be used if the trait is implemented and in scope - = note: the following trait defines an item `a`, perhaps you need to implement it: - candidate #1: `method::A` +note: `method::A` defines an item `a`, perhaps you need to implement it + --> $DIR/trait-item-privacy.rs:6:5 + | +LL | trait A { + | ^^^^^^^ error[E0599]: no function or associated item named `b` found for struct `S` in the current scope --> $DIR/trait-item-privacy.rs:80:8 @@ -83,8 +89,11 @@ LL | S::A; | ^ associated item not found in `S` | = help: items from traits can only be used if the trait is implemented and in scope - = note: the following trait defines an item `A`, perhaps you need to implement it: - candidate #1: `assoc_const::A` +note: `assoc_const::A` defines an item `A`, perhaps you need to implement it + --> $DIR/trait-item-privacy.rs:24:5 + | +LL | trait A { + | ^^^^^^^ error[E0599]: no associated item named `B` found for struct `S` in the current scope --> $DIR/trait-item-privacy.rs:98:8 diff --git a/src/test/ui/trivial-bounds/trivial-bounds-leak.stderr b/src/test/ui/trivial-bounds/trivial-bounds-leak.stderr index acf309ac60872..4e153081d9fe9 100644 --- a/src/test/ui/trivial-bounds/trivial-bounds-leak.stderr +++ b/src/test/ui/trivial-bounds/trivial-bounds-leak.stderr @@ -15,8 +15,11 @@ LL | 3i32.test(); | ^^^^ method not found in `i32` | = help: items from traits can only be used if the trait is implemented and in scope - = note: the following trait defines an item `test`, perhaps you need to implement it: - candidate #1: `Foo` +note: `Foo` defines an item `test`, perhaps you need to implement it + --> $DIR/trivial-bounds-leak.rs:4:1 + | +LL | pub trait Foo { + | ^^^^^^^^^^^^^ error[E0277]: the trait bound `i32: Foo` is not satisfied --> $DIR/trivial-bounds-leak.rs:25:15 diff --git a/src/test/ui/union/union-derive-clone.stderr b/src/test/ui/union/union-derive-clone.stderr index 12b5321331a79..01c8e8471aac2 100644 --- a/src/test/ui/union/union-derive-clone.stderr +++ b/src/test/ui/union/union-derive-clone.stderr @@ -11,16 +11,20 @@ error[E0599]: no method named `clone` found for union `U5` in the c --> $DIR/union-derive-clone.rs:37:15 | LL | union U5 { - | ----------- method `clone` not found for this + | ----------- + | | + | method `clone` not found for this + | doesn't satisfy `U5: std::clone::Clone` +... +LL | struct CloneNoCopy; + | ------------------- doesn't satisfy `CloneNoCopy: std::marker::Copy` ... LL | let w = u.clone(); | ^^^^^ method not found in `U5` | = note: the method `clone` exists but the following trait bounds were not satisfied: - `U5 : std::clone::Clone` - = help: items from traits can only be used if the trait is implemented and in scope - = note: the following trait defines an item `clone`, perhaps you need to implement it: - candidate #1: `std::clone::Clone` + `CloneNoCopy: std::marker::Copy` + which is required by `U5: std::clone::Clone` error: aborting due to 2 previous errors diff --git a/src/test/ui/unique-object-noncopyable.stderr b/src/test/ui/unique-object-noncopyable.stderr index 92cda6482c0d9..286008188fceb 100644 --- a/src/test/ui/unique-object-noncopyable.stderr +++ b/src/test/ui/unique-object-noncopyable.stderr @@ -1,14 +1,25 @@ error[E0599]: no method named `clone` found for struct `std::boxed::Box` in the current scope --> $DIR/unique-object-noncopyable.rs:24:16 | +LL | trait Foo { + | --------- + | | + | doesn't satisfy `dyn Foo: std::clone::Clone` + | doesn't satisfy `dyn Foo: std::marker::Sized` +... LL | let _z = y.clone(); | ^^^^^ method not found in `std::boxed::Box` + | + ::: $SRC_DIR/liballoc/boxed.rs:LL:COL + | +LL | pub struct Box(Unique); + | ------------------------------------- doesn't satisfy `std::boxed::Box: std::clone::Clone` | = note: the method `clone` exists but the following trait bounds were not satisfied: - `std::boxed::Box : std::clone::Clone` - = help: items from traits can only be used if the trait is implemented and in scope - = note: the following trait defines an item `clone`, perhaps you need to implement it: - candidate #1: `std::clone::Clone` + `dyn Foo: std::marker::Sized` + which is required by `std::boxed::Box: std::clone::Clone` + `dyn Foo: std::clone::Clone` + which is required by `std::boxed::Box: std::clone::Clone` error: aborting due to previous error diff --git a/src/test/ui/unique-pinned-nocopy.stderr b/src/test/ui/unique-pinned-nocopy.stderr index e5c3eaccbd3ec..32f751fbcf7c3 100644 --- a/src/test/ui/unique-pinned-nocopy.stderr +++ b/src/test/ui/unique-pinned-nocopy.stderr @@ -1,11 +1,20 @@ error[E0599]: no method named `clone` found for struct `std::boxed::Box` in the current scope --> $DIR/unique-pinned-nocopy.rs:12:16 | +LL | struct R { + | -------- doesn't satisfy `R: std::clone::Clone` +... LL | let _j = i.clone(); | ^^^^^ method not found in `std::boxed::Box` + | + ::: $SRC_DIR/liballoc/boxed.rs:LL:COL + | +LL | pub struct Box(Unique); + | ------------------------------------- doesn't satisfy `std::boxed::Box: std::clone::Clone` | = note: the method `clone` exists but the following trait bounds were not satisfied: - `std::boxed::Box : std::clone::Clone` + `R: std::clone::Clone` + which is required by `std::boxed::Box: std::clone::Clone` = help: items from traits can only be used if the trait is implemented and in scope = note: the following trait defines an item `clone`, perhaps you need to implement it: candidate #1: `std::clone::Clone` diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs index a61b940398704..6c58195a8d339 100644 --- a/src/tools/compiletest/src/main.rs +++ b/src/tools/compiletest/src/main.rs @@ -468,11 +468,13 @@ fn common_inputs_stamp(config: &Config) -> Stamp { // Relevant pretty printer files let pretty_printer_files = [ - "src/etc/debugger_pretty_printers_common.py", + "src/etc/rust_types.py", "src/etc/gdb_load_rust_pretty_printers.py", - "src/etc/gdb_rust_pretty_printing.py", + "src/etc/gdb_lookup.py", + "src/etc/gdb_providers.py", "src/etc/lldb_batchmode.py", - "src/etc/lldb_rust_formatters.py", + "src/etc/lldb_lookup.py", + "src/etc/lldb_providers.py", ]; for file in &pretty_printer_files { let path = rust_src_dir.join(file); diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index ac808b1f14e13..e61461dad14f4 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -1055,15 +1055,16 @@ impl<'test> TestCx<'test> { // Switch LLDB into "Rust mode" let rust_src_root = self.config.find_rust_src_root().expect("Could not find Rust source root"); - let rust_pp_module_rel_path = Path::new("./src/etc/lldb_rust_formatters.py"); + let rust_pp_module_rel_path = Path::new("./src/etc/lldb_lookup.py"); let rust_pp_module_abs_path = rust_src_root.join(rust_pp_module_rel_path).to_str().unwrap().to_owned(); script_str .push_str(&format!("command script import {}\n", &rust_pp_module_abs_path[..])[..]); - script_str.push_str("type summary add --no-value "); - script_str.push_str("--python-function lldb_rust_formatters.print_val "); - script_str.push_str("-x \".*\" --category Rust\n"); + script_str.push_str("type synthetic add -l lldb_lookup.synthetic_lookup -x '.*' "); + script_str.push_str("--category Rust\n"); + script_str.push_str("type summary add -l lldb_lookup.summary_lookup -x '.*' "); + script_str.push_str("--category Rust\n"); script_str.push_str("type category enable Rust\n"); // Set breakpoints on every line that contains the string "#break" diff --git a/src/tools/publish_toolstate.py b/src/tools/publish_toolstate.py index 81d44a3df2598..5fbb986286ade 100755 --- a/src/tools/publish_toolstate.py +++ b/src/tools/publish_toolstate.py @@ -131,7 +131,6 @@ def issue( assignees, relevant_pr_number, relevant_pr_user, - pr_reviewer, ): # Open an issue about the toolstate failure. if status == 'test-fail': @@ -147,11 +146,11 @@ def issue( cc @{}, do you think you would have time to do the follow-up work? If so, that would be great! - cc @{}, the PR reviewer, and nominating for compiler team prioritization. + And nominating for compiler team prioritization. ''').format( relevant_pr_number, tool, status_description, - REPOS.get(tool), relevant_pr_user, pr_reviewer + REPOS.get(tool), relevant_pr_user )), 'title': '`{}` no longer builds after {}'.format(tool, relevant_pr_number), 'assignees': list(assignees), @@ -236,7 +235,7 @@ def update_latest( try: issue( tool, create_issue_for_status, MAINTAINERS.get(tool, ''), - relevant_pr_number, relevant_pr_user, pr_reviewer, + relevant_pr_number, relevant_pr_user, ) except urllib2.HTTPError as e: # network errors will simply end up not creating an issue, but that's better