From d0bc6a1f49f2802d603acf086ed54d976a79d703 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Tue, 3 Nov 2015 22:48:28 -0800 Subject: [PATCH 1/7] Don't chain method calls in #[derive(Debug)] Closes #29540 --- src/libsyntax/ext/deriving/debug.rs | 59 ++-- src/test/run-pass/issue-29540.rs | 501 ++++++++++++++++++++++++++++ 2 files changed, 536 insertions(+), 24 deletions(-) create mode 100644 src/test/run-pass/issue-29540.rs diff --git a/src/libsyntax/ext/deriving/debug.rs b/src/libsyntax/ext/deriving/debug.rs index 537375f70845d..8a180e6c093b5 100644 --- a/src/libsyntax/ext/deriving/debug.rs +++ b/src/libsyntax/ext/deriving/debug.rs @@ -72,34 +72,40 @@ fn show_substructure(cx: &mut ExtCtxt, span: Span, let span = Span { expn_id: cx.backtrace(), .. span }; let name = cx.expr_lit(span, ast::Lit_::LitStr(ident.name.as_str(), ast::StrStyle::CookedStr)); - let mut expr = substr.nonself_args[0].clone(); + let builder = token::str_to_ident("builder"); + let builder_expr = cx.expr_ident(span, builder.clone()); - match *substr.fields { - Struct(ref fields) | EnumMatching(_, _, ref fields) => { + let fmt = substr.nonself_args[0].clone(); + let stmts = match *substr.fields { + Struct(ref fields) | EnumMatching(_, _, ref fields) => { + let mut stmts = vec![]; if fields.is_empty() || fields[0].name.is_none() { // tuple struct/"normal" variant - expr = cx.expr_method_call(span, - expr, - token::str_to_ident("debug_tuple"), - vec![name]); + let expr = cx.expr_method_call(span, + fmt, + token::str_to_ident("debug_tuple"), + vec![name]); + stmts.push(cx.stmt_let(span, true, builder, expr)); for field in fields { // Use double indirection to make sure this works for unsized types let field = cx.expr_addr_of(field.span, field.self_.clone()); let field = cx.expr_addr_of(field.span, field); - expr = cx.expr_method_call(span, - expr, - token::str_to_ident("field"), - vec![field]); + let expr = cx.expr_method_call(span, + builder_expr.clone(), + token::str_to_ident("field"), + vec![field]); + stmts.push(cx.stmt_expr(expr)); } } else { // normal struct/struct variant - expr = cx.expr_method_call(span, - expr, - token::str_to_ident("debug_struct"), - vec![name]); + let expr = cx.expr_method_call(span, + fmt, + token::str_to_ident("debug_struct"), + vec![name]); + stmts.push(cx.stmt_let(span, true, builder, expr)); for field in fields { let name = cx.expr_lit(field.span, ast::Lit_::LitStr( @@ -109,18 +115,23 @@ fn show_substructure(cx: &mut ExtCtxt, span: Span, // Use double indirection to make sure this works for unsized types let field = cx.expr_addr_of(field.span, field.self_.clone()); let field = cx.expr_addr_of(field.span, field); - expr = cx.expr_method_call(span, - expr, - token::str_to_ident("field"), - vec![name, field]); + let expr = cx.expr_method_call(span, + builder_expr.clone(), + token::str_to_ident("field"), + vec![name, field]); + stmts.push(cx.stmt_expr(expr)); } } + stmts } _ => unreachable!() - } + }; + + let expr = cx.expr_method_call(span, + builder_expr, + token::str_to_ident("finish"), + vec![]); - cx.expr_method_call(span, - expr, - token::str_to_ident("finish"), - vec![]) + let block = cx.block(span, stmts, Some(expr)); + cx.expr_block(block) } diff --git a/src/test/run-pass/issue-29540.rs b/src/test/run-pass/issue-29540.rs new file mode 100644 index 0000000000000..285cf5763cc3a --- /dev/null +++ b/src/test/run-pass/issue-29540.rs @@ -0,0 +1,501 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[derive(Debug)] +pub struct Config { + pub name: String, + pub cluster: String, + pub debug_none: String, + pub debug_lockdep: String, + pub debug_context: String, + pub debug_crush: String, + pub debug_mds: String, + pub debug_mds_balancer: String, + pub debug_mds_locker: String, + pub debug_mds_log: String, + pub debug_mds_log_expire: String, + pub debug_mds_migrator: String, + pub debug_buffer: String, + pub debug_timer: String, + pub debug_filer: String, + pub debug_striper: String, + pub debug_objecter: String, + pub debug_rados: String, + pub debug_rbd: String, + pub debug_journaler: String, + pub debug_objectcacher: String, + pub debug_client: String, + pub debug_osd: String, + pub debug_optracker: String, + pub debug_objclass: String, + pub debug_filestore: String, + pub debug_keyvaluestore: String, + pub debug_journal: String, + pub debug_ms: String, + pub debug_mon: String, + pub debug_monc: String, + pub debug_paxos: String, + pub debug_tp: String, + pub debug_auth: String, + pub debug_crypto: String, + pub debug_finisher: String, + pub debug_heartbeatmap: String, + pub debug_perfcounter: String, + pub debug_rgw: String, + pub debug_civetweb: String, + pub debug_javaclient: String, + pub debug_asok: String, + pub debug_throttle: String, + pub host: String, + pub fsid: String, + pub public_addr: String, + pub cluster_addr: String, + pub public_network: String, + pub cluster_network: String, + pub num_client: String, + pub monmap: String, + pub mon_host: String, + pub lockdep: String, + pub run_dir: String, + pub admin_socket: String, + pub daemonize: String, + pub pid_file: String, + pub chdir: String, + pub max_open_files: String, + pub restapi_log_level: String, + pub restapi_base_url: String, + pub fatal_signal_handlers: String, + pub log_file: String, + pub log_max_new: String, + pub log_max_recent: String, + pub log_to_stderr: String, + pub err_to_stderr: String, + pub log_to_syslog: String, + pub err_to_syslog: String, + pub log_flush_on_exit: String, + pub log_stop_at_utilization: String, + pub clog_to_monitors: String, + pub clog_to_syslog: String, + pub clog_to_syslog_level: String, + pub clog_to_syslog_facility: String, + pub mon_cluster_log_to_syslog: String, + pub mon_cluster_log_to_syslog_level: String, + pub mon_cluster_log_to_syslog_facility: String, + pub mon_cluster_log_file: String, + pub mon_cluster_log_file_level: String, + pub key: String, + pub keyfile: String, + pub keyring: String, + pub heartbeat_interval: String, + pub heartbeat_file: String, + pub heartbeat_inject_failure: String, + pub perf: String, + pub ms_tcp_nodelay: String, + pub ms_tcp_rcvbuf: String, + pub ms_initial_backoff: String, + pub ms_max_backoff: String, + pub ms_nocrc: String, + pub ms_die_on_bad_msg: String, + pub ms_die_on_unhandled_msg: String, + pub ms_die_on_old_message: String, + pub ms_dispatch_throttle_bytes: String, + pub ms_bind_ipv6: String, + pub ms_bind_port_min: String, + pub ms_bind_port_max: String, + pub ms_rwthread_stack_bytes: String, + pub ms_tcp_read_timeout: String, + pub ms_pq_max_tokens_per_priority: String, + pub ms_pq_min_cost: String, + pub ms_inject_socket_failures: String, + pub ms_inject_delay_type: String, + pub ms_inject_delay_msg_type: String, + pub ms_inject_delay_max: String, + pub ms_inject_delay_probability: String, + pub ms_inject_internal_delays: String, + pub ms_dump_on_send: String, + pub inject_early_sigterm: String, + pub mon_data: String, + pub mon_initial_members: String, + pub mon_sync_fs_threshold: String, + pub mon_compact_on_start: String, + pub mon_compact_on_bootstrap: String, + pub mon_compact_on_trim: String, + pub mon_tick_interval: String, + pub mon_subscribe_interval: String, + pub mon_delta_reset_interval: String, + pub mon_osd_laggy_halflife: String, + pub mon_osd_laggy_weight: String, + pub mon_osd_adjust_heartbeat_grace: String, + pub mon_osd_adjust_down_out_interval: String, + pub mon_osd_auto_mark_in: String, + pub mon_osd_auto_mark_auto_out_in: String, + pub mon_osd_auto_mark_new_in: String, + pub mon_osd_down_out_interval: String, + pub mon_osd_down_out_subtree_limit: String, + pub mon_osd_min_up_ratio: String, + pub mon_osd_min_in_ratio: String, + pub mon_osd_max_op_age: String, + pub mon_osd_max_split_count: String, + pub mon_osd_allow_primary_temp: String, + pub mon_osd_allow_primary_affinity: String, + pub mon_stat_smooth_intervals: String, + pub mon_lease: String, + pub mon_lease_renew_interval: String, + pub mon_lease_ack_timeout: String, + pub mon_clock_drift_allowed: String, + pub mon_clock_drift_warn_backoff: String, + pub mon_timecheck_interval: String, + pub mon_accept_timeout: String, + pub mon_pg_create_interval: String, + pub mon_pg_stuck_threshold: String, + pub mon_pg_warn_min_per_osd: String, + pub mon_pg_warn_max_object_skew: String, + pub mon_pg_warn_min_objects: String, + pub mon_pg_warn_min_pool_objects: String, + pub mon_cache_target_full_warn_ratio: String, + pub mon_osd_full_ratio: String, + pub mon_osd_nearfull_ratio: String, + pub mon_globalid_prealloc: String, + pub mon_osd_report_timeout: String, + pub mon_force_standby_active: String, + pub mon_warn_on_old_mons: String, + pub mon_warn_on_legacy_crush_tunables: String, + pub mon_warn_on_osd_down_out_interval_zero: String, + pub mon_warn_on_cache_pools_without_hit_sets: String, + pub mon_min_osdmap_epochs: String, + pub mon_max_pgmap_epochs: String, + pub mon_max_log_epochs: String, + pub mon_max_mdsmap_epochs: String, + pub mon_max_osd: String, + pub mon_probe_timeout: String, + pub mon_slurp_timeout: String, + pub mon_slurp_bytes: String, + pub mon_client_bytes: String, + pub mon_daemon_bytes: String, + pub mon_max_log_entries_per_event: String, + pub mon_health_data_update_interval: String, + pub mon_data_avail_crit: String, + pub mon_data_avail_warn: String, + pub mon_config_key_max_entry_size: String, + pub mon_sync_timeout: String, + pub mon_sync_max_payload_size: String, + pub mon_sync_debug: String, + pub mon_sync_debug_leader: String, + pub mon_sync_debug_provider: String, + pub mon_sync_debug_provider_fallback: String, + pub mon_inject_sync_get_chunk_delay: String, + pub mon_osd_min_down_reporters: String, + pub mon_osd_min_down_reports: String, + pub mon_osd_force_trim_to: String, + pub mon_mds_force_trim_to: String, + pub mon_advanced_debug_mode: String, + pub mon_debug_dump_transactions: String, + pub mon_debug_dump_location: String, + pub mon_sync_provider_kill_at: String, + pub mon_sync_requester_kill_at: String, + pub mon_leveldb_write_buffer_size: String, + pub mon_leveldb_cache_size: String, + pub mon_leveldb_block_size: String, + pub mon_leveldb_bloom_size: String, + pub mon_leveldb_max_open_files: String, + pub mon_leveldb_compression: String, + pub mon_leveldb_paranoid: String, + pub mon_leveldb_log: String, + pub mon_leveldb_size_warn: String, + pub mon_force_quorum_join: String, + pub paxos_stash_full_interval: String, + pub paxos_max_join_drift: String, + pub paxos_propose_interval: String, + pub paxos_min_wait: String, + pub paxos_min: String, + pub paxos_trim_min: String, + pub paxos_trim_max: String, + pub paxos_service_trim_min: String, + pub paxos_service_trim_max: String, + pub paxos_kill_at: String, + pub clock_offset: String, + pub auth_cluster_required: String, + pub auth_service_required: String, + pub auth_client_required: String, + pub auth_supported: String, + pub cephx_require_signatures: String, + pub cephx_cluster_require_signatures: String, + pub cephx_service_require_signatures: String, + pub cephx_sign_messages: String, + pub auth_mon_ticket_ttl: String, + pub auth_service_ticket_ttl: String, + pub auth_debug: String, + pub mon_client_hunt_interval: String, + pub mon_client_ping_interval: String, + pub mon_client_ping_timeout: String, + pub mon_client_hunt_interval_backoff: String, + pub mon_client_hunt_interval_max_multiple: String, + pub mon_client_max_log_entries_per_message: String, + pub mon_max_pool_pg_num: String, + pub mon_pool_quota_warn_threshold: String, + pub mon_pool_quota_crit_threshold: String, + pub client_cache_size: String, + pub client_cache_mid: String, + pub client_use_random_mds: String, + pub client_mount_timeout: String, + pub client_tick_interval: String, + pub client_trace: String, + pub client_readahead_min: String, + pub client_readahead_max_bytes: String, + pub client_readahead_max_periods: String, + pub client_snapdir: String, + pub client_mountpoint: String, + pub client_notify_timeout: String, + pub osd_client_watch_timeout: String, + pub client_caps_release_delay: String, + pub client_oc: String, + pub client_oc_size: String, + pub client_oc_max_dirty: String, + pub client_oc_target_dirty: String, + pub client_oc_max_dirty_age: String, + pub client_oc_max_objects: String, + pub client_debug_force_sync_read: String, + pub client_debug_inject_tick_delay: String, + pub client_max_inline_size: String, + pub fuse_use_invalidate_cb: String, + pub fuse_allow_other: String, + pub fuse_default_permissions: String, + pub fuse_big_writes: String, + pub fuse_atomic_o_trunc: String, + pub fuse_debug: String, + pub fuse_multithreaded: String, + pub crush_location: String, + pub objecter_tick_interval: String, + pub objecter_timeout: String, + pub objecter_inflight_op_bytes: String, + pub objecter_inflight_ops: String, + pub journaler_allow_split_entries: String, + pub journaler_write_head_interval: String, + pub journaler_prefetch_periods: String, + pub journaler_prezero_periods: String, + pub journaler_batch_interval: String, + pub journaler_batch_max: String, + pub mds_data: String, + pub mds_max_file_size: String, + pub mds_cache_size: String, + pub mds_cache_mid: String, + pub mds_mem_max: String, + pub mds_dir_max_commit_size: String, + pub mds_decay_halflife: String, + pub mds_beacon_interval: String, + pub mds_beacon_grace: String, + pub mds_enforce_unique_name: String, + pub mds_blacklist_interval: String, + pub mds_session_timeout: String, + pub mds_freeze_tree_timeout: String, + pub mds_session_autoclose: String, + pub mds_reconnect_timeout: String, + pub mds_tick_interval: String, + pub mds_dirstat_min_interval: String, + pub mds_scatter_nudge_interval: String, + pub mds_client_prealloc_inos: String, + pub mds_early_reply: String, + pub mds_default_dir_hash: String, + pub mds_log: String, + pub mds_log_skip_corrupt_events: String, + pub mds_log_max_events: String, + pub mds_log_segment_size: String, + pub mds_log_max_segments: String, + pub mds_log_max_expiring: String, + pub mds_bal_sample_interval: String, + pub mds_bal_replicate_threshold: String, + pub mds_bal_unreplicate_threshold: String, + pub mds_bal_frag: String, + pub mds_bal_split_size: String, + pub mds_bal_split_rd: String, + pub mds_bal_split_wr: String, + pub mds_bal_split_bits: String, + pub mds_bal_merge_size: String, + pub mds_bal_merge_rd: String, + pub mds_bal_merge_wr: String, + pub mds_bal_interval: String, + pub mds_bal_fragment_interval: String, + pub mds_bal_idle_threshold: String, + pub mds_bal_max: String, + pub mds_bal_max_until: String, + pub mds_bal_mode: String, + pub mds_bal_min_rebalance: String, + pub mds_bal_min_start: String, + pub mds_bal_need_min: String, + pub mds_bal_need_max: String, + pub mds_bal_midchunk: String, + pub mds_bal_minchunk: String, + pub mds_bal_target_removal_min: String, + pub mds_bal_target_removal_max: String, + pub mds_replay_interval: String, + pub mds_shutdown_check: String, + pub mds_thrash_exports: String, + pub mds_thrash_fragments: String, + pub mds_dump_cache_on_map: String, + pub mds_dump_cache_after_rejoin: String, + pub mds_verify_scatter: String, + pub mds_debug_scatterstat: String, + pub mds_debug_frag: String, + pub mds_debug_auth_pins: String, + pub mds_debug_subtrees: String, + pub mds_kill_mdstable_at: String, + pub mds_kill_export_at: String, + pub mds_kill_import_at: String, + pub mds_kill_link_at: String, + pub mds_kill_rename_at: String, + pub mds_kill_openc_at: String, + pub mds_kill_journal_at: String, + pub mds_kill_journal_expire_at: String, + pub mds_kill_journal_replay_at: String, + pub mds_kill_create_at: String, + pub mds_open_remote_link_mode: String, + pub mds_inject_traceless_reply_probability: String, + pub mds_wipe_sessions: String, + pub mds_wipe_ino_prealloc: String, + pub mds_skip_ino: String, + pub max_mds: String, + pub mds_standby_for_name: String, + pub mds_standby_for_rank: String, + pub mds_standby_replay: String, + pub osd_compact_leveldb_on_mount: String, + pub osd_max_backfills: String, + pub osd_backfill_full_ratio: String, + pub osd_backfill_retry_interval: String, + pub osd_agent_max_ops: String, + pub osd_agent_min_evict_effort: String, + pub osd_agent_quantize_effort: String, + pub osd_agent_delay_time: String, + pub osd_agent_hist_halflife: String, + pub osd_agent_slop: String, + pub osd_uuid: String, + pub osd_data: String, + pub osd_journal: String, + pub osd_journal_size: String, + pub osd_max_write_size: String, + pub osd_max_pgls: String, + pub osd_client_message_size_cap: String, + pub osd_client_message_cap: String, + pub osd_pg_bits: String, + pub osd_pgp_bits: String, + pub osd_crush_chooseleaf_type: String, + pub osd_pool_default_crush_rule: String, + pub osd_pool_default_crush_replicated_ruleset: String, + pub osd_pool_erasure_code_stripe_width: String, + pub osd_pool_default_size: String, + pub osd_pool_default_min_size: String, + pub osd_pool_default_pg_num: String, + pub osd_pool_default_pgp_num: String, + pub osd_pool_default_erasure_code_directory: String, + pub osd_pool_default_erasure_code_profile: String, + pub osd_erasure_code_plugins: String, + pub osd_pool_default_flags: String, + pub osd_pool_default_flag_hashpspool: String, + pub osd_pool_default_hit_set_bloom_fpp: String, + pub osd_pool_default_cache_target_dirty_ratio: String, + pub osd_pool_default_cache_target_full_ratio: String, + pub osd_pool_default_cache_min_flush_age: String, + pub osd_pool_default_cache_min_evict_age: String, + pub osd_hit_set_min_size: String, + pub osd_hit_set_max_size: String, + pub osd_hit_set_namespace: String, + pub osd_tier_default_cache_mode: String, + pub osd_tier_default_cache_hit_set_count: String, + pub osd_tier_default_cache_hit_set_period: String, + pub osd_tier_default_cache_hit_set_type: String, + pub osd_map_dedup: String, + pub osd_map_max_advance: String, + pub osd_map_cache_size: String, + pub osd_map_message_max: String, + pub osd_map_share_max_epochs: String, + pub osd_op_threads: String, + pub osd_peering_wq_batch_size: String, + pub osd_op_pq_max_tokens_per_priority: String, + pub osd_op_pq_min_cost: String, + pub osd_disk_threads: String, + pub osd_disk_thread_ioprio_class: String, + pub osd_disk_thread_ioprio_priority: String, + pub osd_recovery_threads: String, + pub osd_recover_clone_overlap: String, + pub osd_recover_clone_overlap_limit: String, + pub osd_backfill_scan_min: String, + pub osd_backfill_scan_max: String, + pub osd_op_thread_timeout: String, + pub osd_recovery_thread_timeout: String, + pub osd_snap_trim_thread_timeout: String, + pub osd_snap_trim_sleep: String, + pub osd_scrub_thread_timeout: String, + pub osd_scrub_finalize_thread_timeout: String, + pub osd_scrub_invalid_stats: String, + pub osd_remove_thread_timeout: String, + pub osd_command_thread_timeout: String, + pub osd_age: String, + pub osd_age_time: String, + pub osd_heartbeat_addr: String, + pub osd_heartbeat_interval: String, + pub osd_heartbeat_grace: String, + pub osd_heartbeat_min_peers: String, + pub osd_pg_max_concurrent_snap_trims: String, + pub osd_heartbeat_min_healthy_ratio: String, + pub osd_mon_heartbeat_interval: String, + pub osd_mon_report_interval_max: String, + pub osd_mon_report_interval_min: String, + pub osd_pg_stat_report_interval_max: String, + pub osd_mon_ack_timeout: String, + pub osd_default_data_pool_replay_window: String, + pub osd_preserve_trimmed_log: String, + pub osd_auto_mark_unfound_lost: String, + pub osd_recovery_delay_start: String, + pub osd_recovery_max_active: String, + pub osd_recovery_max_single_start: String, + pub osd_recovery_max_chunk: String, + pub osd_copyfrom_max_chunk: String, + pub osd_push_per_object_cost: String, + pub osd_max_push_cost: String, + pub osd_max_push_objects: String, + pub osd_recovery_forget_lost_objects: String, + pub osd_max_scrubs: String, + pub osd_scrub_load_threshold: String, + pub osd_scrub_min_interval: String, + pub osd_scrub_max_interval: String, + pub osd_scrub_chunk_min: String, + pub osd_scrub_chunk_max: String, + pub osd_scrub_sleep: String, + pub osd_deep_scrub_interval: String, + pub osd_deep_scrub_stride: String, + pub osd_scan_list_ping_tp_interval: String, + pub osd_auto_weight: String, + pub osd_class_dir: String, + pub osd_open_classes_on_start: String, + pub osd_check_for_log_corruption: String, + pub osd_use_stale_snap: String, + pub osd_rollback_to_cluster_snap: String, + pub osd_default_notify_timeout: String, + pub osd_kill_backfill_at: String, + pub osd_pg_epoch_persisted_max_stale: String, + pub osd_min_pg_log_entries: String, + pub osd_max_pg_log_entries: String, + pub osd_op_complaint_time: String, + pub osd_command_max_records: String, + pub osd_op_log_threshold: String, + pub osd_verify_sparse_read_holes: String, + pub osd_debug_drop_ping_probability: String, + pub osd_debug_drop_ping_duration: String, + pub osd_debug_drop_pg_create_probability: String, + pub osd_debug_drop_pg_create_duration: String, + pub osd_debug_drop_op_probability: String, + pub osd_debug_op_order: String, + pub osd_debug_verify_snaps_on_info: String, + pub osd_debug_verify_stray_on_activate: String, + pub osd_debug_skip_full_check_in_backfill_reservation: String, + pub osd_debug_reject_backfill_probability: String, + pub osd_enable_op_tracker: String, +} + +fn main() {} From 3b2a8e125998f3cb7b32ec9268b3b2c6404943fe Mon Sep 17 00:00:00 2001 From: Ivan Kozik Date: Thu, 5 Nov 2015 10:39:02 +0000 Subject: [PATCH 2/7] librustdoc: don't override ctrl-s and other browser shortcuts --- src/librustdoc/html/static/main.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 5a6d761683224..8844ed82bb5e2 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -101,6 +101,10 @@ if (document.activeElement.tagName == "INPUT") return; + // Don't interfere with browser shortcuts + if (ev.ctrlKey || ev.altKey || ev.metaKey) + return; + switch (getVirtualKey(ev)) { case "Escape": if (!$("#help").hasClass("hidden")) { From f70f8b43013121a4e911444d6f15aec3319bd469 Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Thu, 5 Nov 2015 14:04:39 +0100 Subject: [PATCH 3/7] Remove short intro from README Originally, this was my 30 minute introduction, and we eventually made it the opener to the book. But as #25918 has shown, the example I use here has some issues. The good news is that Rust makes heap allocation syntatically expensive, but the bad news is that that means showing equivalent programs from Rust and other languages is difficult. After thinking about it, I'm not sure this section is pulling its weight, and since it has problems, I'd rather just pull it than try to re-write it right now. I think the book is fine without it. FIxes #25918 --- src/doc/trpl/README.md | 156 +---------------------------------------- 1 file changed, 3 insertions(+), 153 deletions(-) diff --git a/src/doc/trpl/README.md b/src/doc/trpl/README.md index 6962f828e194d..7acb7f835b8dd 100644 --- a/src/doc/trpl/README.md +++ b/src/doc/trpl/README.md @@ -41,158 +41,8 @@ Copious cross-linking connects these parts together. ### Contributing -The source files from which this book is generated can be found on GitHub: -[github.com/rust-lang/rust/tree/master/src/doc/trpl](https://github.com/rust-lang/rust/tree/master/src/doc/trpl) +The source files from which this book is generated can be found on +[GitHub][trpl]. -## A brief introduction to Rust +[trpl]: https://github.com/rust-lang/rust/tree/master/src/doc/trpl -Is Rust a language you might be interested in? Let’s examine a few small code -samples to show off a few of its strengths. - -The main concept that makes Rust unique is called ‘ownership’. Consider this -small example: - -```rust -fn main() { - let mut x = vec!["Hello", "world"]; -} -``` - -This program makes a [variable binding][var] named `x`. The value of this -binding is a `Vec`, a ‘vector’, that we create through a [macro][macro] -defined in the standard library. This macro is called `vec`, and we invoke -macros with a `!`. This follows a general principle of Rust: make things -explicit. Macros can do significantly more complicated things than function -calls, and so they’re visually distinct. The `!` also helps with parsing, -making tooling easier to write, which is also important. - -We used `mut` to make `x` mutable: bindings are immutable by default in Rust. -We’ll be mutating this vector later in the example. - -It’s also worth noting that we didn’t need a type annotation here: while Rust -is statically typed, we didn’t need to explicitly annotate the type. Rust has -type inference to balance out the power of static typing with the verbosity of -annotating types. - -Rust prefers stack allocation to heap allocation: `x` is placed directly on the -stack. However, the `Vec` type allocates space for the elements of the vector -on the heap. If you’re not familiar with this distinction, you can ignore it for -now, or check out [‘The Stack and the Heap’][heap]. As a systems programming -language, Rust gives us the ability to control how our memory is allocated, but -when we’re getting started, it’s less of a big deal. - -[var]: variable-bindings.html -[macro]: macros.html -[heap]: the-stack-and-the-heap.html - -Earlier, we mentioned that ‘ownership’ is the key new concept in Rust. In Rust -parlance, `x` is said to ‘own’ the vector. This means that when `x` goes out of -scope, the vector’s memory will be de-allocated. This is done deterministically -by the Rust compiler, rather than through a mechanism such as a garbage -collector. In other words, in Rust, we don’t call functions like `malloc` and -`free` ourselves: the compiler statically determines when we need to allocate or -deallocate memory, and inserts those calls itself. To err is to be human, but -compilers never forget. - -Let’s add another line to our example: - -```rust -fn main() { - let mut x = vec!["Hello", "world"]; - - let y = &x[0]; -} -``` - -We’ve introduced another binding, `y`. In this case, `y` is a ‘reference’ to the -first element of the vector. Rust’s references are similar to pointers in other -languages, but with additional compile-time safety checks. References interact -with the ownership system by [‘borrowing’][borrowing] what they point to, rather -than owning it. The difference is, when the reference goes out of scope, it -won't deallocate the underlying memory. If it did, we’d de-allocate twice, which -is bad! - -[borrowing]: references-and-borrowing.html - -Let’s add a third line. It looks innocent enough, but causes a compiler error: - -```rust,ignore -fn main() { - let mut x = vec!["Hello", "world"]; - - let y = &x[0]; - - x.push("foo"); -} -``` - -`push` is a method on vectors that appends another element to the end of the -vector. When we try to compile this program, we get an error: - -```text -error: cannot borrow `x` as mutable because it is also borrowed as immutable - x.push("foo"); - ^ -note: previous borrow of `x` occurs here; the immutable borrow prevents -subsequent moves or mutable borrows of `x` until the borrow ends - let y = &x[0]; - ^ -note: previous borrow ends here -fn main() { - -} -^ -``` - -Whew! The Rust compiler gives quite detailed errors at times, and this is one -of those times. As the error explains, while we made our binding mutable, we -still can't call `push`. This is because we already have a reference to an -element of the vector, `y`. Mutating something while another reference exists -is dangerous, because we may invalidate the reference. In this specific case, -when we create the vector, we may have only allocated space for two elements. -Adding a third would mean allocating a new chunk of memory for all those elements, -copying the old values over, and updating the internal pointer to that memory. -That all works just fine. The problem is that `y` wouldn’t get updated, and so -we’d have a ‘dangling pointer’. That’s bad. Any use of `y` would be an error in -this case, and so the compiler has caught this for us. - -So how do we solve this problem? There are two approaches we can take. The first -is making a copy rather than using a reference: - -```rust -fn main() { - let mut x = vec!["Hello", "world"]; - - let y = x[0].clone(); - - x.push("foo"); -} -``` - -Rust has [move semantics][move] by default, so if we want to make a copy of some -data, we call the `clone()` method. In this example, `y` is no longer a reference -to the vector stored in `x`, but a copy of its first element, `"Hello"`. Now -that we don’t have a reference, our `push()` works just fine. - -[move]: ownership.html#move-semantics - -If we truly want a reference, we need the other option: ensure that our reference -goes out of scope before we try to do the mutation. That looks like this: - -```rust -fn main() { - let mut x = vec!["Hello", "world"]; - - { - let y = &x[0]; - } - - x.push("foo"); -} -``` - -We created an inner scope with an additional set of curly braces. `y` will go out of -scope before we call `push()`, and so we’re all good. - -This concept of ownership isn’t just good for preventing dangling pointers, but an -entire set of related problems, like iterator invalidation, concurrency, and more. From 6d9502d35b4b0bc41bee1bd3acc0d75bf2cfd835 Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Thu, 5 Nov 2015 14:40:50 +0100 Subject: [PATCH 4/7] Remove .ok().expect() in favor of just expect() Fixes #29506 --- src/doc/trpl/guessing-game.md | 76 +++++++++++++---------------------- 1 file changed, 27 insertions(+), 49 deletions(-) diff --git a/src/doc/trpl/guessing-game.md b/src/doc/trpl/guessing-game.md index db484a28cb02c..6a513fb2c5963 100644 --- a/src/doc/trpl/guessing-game.md +++ b/src/doc/trpl/guessing-game.md @@ -83,7 +83,6 @@ fn main() { let mut guess = String::new(); io::stdin().read_line(&mut guess) - .ok() .expect("Failed to read line"); println!("You guessed: {}", guess); @@ -189,7 +188,6 @@ Let’s move forward: ```rust,ignore io::stdin().read_line(&mut guess) - .ok() .expect("Failed to read line"); ``` @@ -245,7 +243,6 @@ a single line of text, it’s only the first part of the single logical line of code: ```rust,ignore - .ok() .expect("Failed to read line"); ``` @@ -254,33 +251,27 @@ and other whitespace. This helps you split up long lines. We _could_ have done: ```rust,ignore - io::stdin().read_line(&mut guess).ok().expect("failed to read line"); + io::stdin().read_line(&mut guess).expect("failed to read line"); ``` -But that gets hard to read. So we’ve split it up, three lines for three -method calls. We already talked about `read_line()`, but what about `ok()` -and `expect()`? Well, we already mentioned that `read_line()` puts what -the user types into the `&mut String` we pass it. But it also returns -a value: in this case, an [`io::Result`][ioresult]. Rust has a number of -types named `Result` in its standard library: a generic [`Result`][result], -and then specific versions for sub-libraries, like `io::Result`. +But that gets hard to read. So we’ve split it up, three lines for three method +calls. We already talked about `read_line()`, but what about `expect()`? Well, +we already mentioned that `read_line()` puts what the user types into the `&mut +String` we pass it. But it also returns a value: in this case, an +[`io::Result`][ioresult]. Rust has a number of types named `Result` in its +standard library: a generic [`Result`][result], and then specific versions for +sub-libraries, like `io::Result`. [ioresult]: ../std/io/type.Result.html [result]: ../std/result/enum.Result.html The purpose of these `Result` types is to encode error handling information. Values of the `Result` type, like any type, have methods defined on them. In -this case, `io::Result` has an `ok()` method, which says ‘we want to assume -this value is a successful one. If not, just throw away the error -information’. Why throw it away? Well, for a basic program, we just want to -print a generic error, as basically any issue means we can’t continue. The -[`ok()` method][ok] returns a value which has another method defined on it: -`expect()`. The [`expect()` method][expect] takes a value it’s called on, and -if it isn’t a successful one, [`panic!`][panic]s with a message you -passed it. A `panic!` like this will cause our program to crash, displaying -the message. - -[ok]: ../std/result/enum.Result.html#method.ok +this case, `io::Result` has an [`expect()` method][expect] that takes a value +it’s called on, and if it isn’t a successful one, [`panic!`][panic]s with a +message you passed it. A `panic!` like this will cause our program to crash, +displaying the message. + [expect]: ../std/option/enum.Option.html#method.expect [panic]: error-handling.html @@ -468,7 +459,6 @@ fn main() { let mut guess = String::new(); io::stdin().read_line(&mut guess) - .ok() .expect("failed to read line"); println!("You guessed: {}", guess); @@ -557,7 +547,6 @@ fn main() { let mut guess = String::new(); io::stdin().read_line(&mut guess) - .ok() .expect("failed to read line"); println!("You guessed: {}", guess); @@ -668,11 +657,9 @@ fn main() { let mut guess = String::new(); io::stdin().read_line(&mut guess) - .ok() .expect("failed to read line"); let guess: u32 = guess.trim().parse() - .ok() .expect("Please type a number!"); println!("You guessed: {}", guess); @@ -689,7 +676,6 @@ The new three lines: ```rust,ignore let guess: u32 = guess.trim().parse() - .ok() .expect("Please type a number!"); ``` @@ -706,27 +692,26 @@ We bind `guess` to an expression that looks like something we wrote earlier: guess.trim().parse() ``` -Followed by an `ok().expect()` invocation. Here, `guess` refers to the old -`guess`, the one that was a `String` with our input in it. The `trim()` -method on `String`s will eliminate any white space at the beginning and end of -our string. This is important, as we had to press the ‘return’ key to satisfy -`read_line()`. This means that if we type `5` and hit return, `guess` looks -like this: `5\n`. The `\n` represents ‘newline’, the enter key. `trim()` gets -rid of this, leaving our string with just the `5`. The [`parse()` method on -strings][parse] parses a string into some kind of number. Since it can parse a -variety of numbers, we need to give Rust a hint as to the exact type of number -we want. Hence, `let guess: u32`. The colon (`:`) after `guess` tells Rust -we’re going to annotate its type. `u32` is an unsigned, thirty-two bit -integer. Rust has [a number of built-in number types][number], but we’ve -chosen `u32`. It’s a good default choice for a small positive number. +Here, `guess` refers to the old `guess`, the one that was a `String` with our +input in it. The `trim()` method on `String`s will eliminate any white space at +the beginning and end of our string. This is important, as we had to press the +‘return’ key to satisfy `read_line()`. This means that if we type `5` and hit +return, `guess` looks like this: `5\n`. The `\n` represents ‘newline’, the +enter key. `trim()` gets rid of this, leaving our string with just the `5`. The +[`parse()` method on strings][parse] parses a string into some kind of number. +Since it can parse a variety of numbers, we need to give Rust a hint as to the +exact type of number we want. Hence, `let guess: u32`. The colon (`:`) after +`guess` tells Rust we’re going to annotate its type. `u32` is an unsigned, +thirty-two bit integer. Rust has [a number of built-in number types][number], +but we’ve chosen `u32`. It’s a good default choice for a small positive number. [parse]: ../std/primitive.str.html#method.parse [number]: primitive-types.html#numeric-types Just like `read_line()`, our call to `parse()` could cause an error. What if our string contained `A👍%`? There’d be no way to convert that to a number. As -such, we’ll do the same thing we did with `read_line()`: use the `ok()` and -`expect()` methods to crash if there’s an error. +such, we’ll do the same thing we did with `read_line()`: use the `expect()` +method to crash if there’s an error. Let’s try our program out! @@ -773,11 +758,9 @@ fn main() { let mut guess = String::new(); io::stdin().read_line(&mut guess) - .ok() .expect("failed to read line"); let guess: u32 = guess.trim().parse() - .ok() .expect("Please type a number!"); println!("You guessed: {}", guess); @@ -841,11 +824,9 @@ fn main() { let mut guess = String::new(); io::stdin().read_line(&mut guess) - .ok() .expect("failed to read line"); let guess: u32 = guess.trim().parse() - .ok() .expect("Please type a number!"); println!("You guessed: {}", guess); @@ -888,7 +869,6 @@ fn main() { let mut guess = String::new(); io::stdin().read_line(&mut guess) - .ok() .expect("failed to read line"); let guess: u32 = match guess.trim().parse() { @@ -920,7 +900,6 @@ let guess: u32 = match guess.trim().parse() { ``` This is how you generally move from ‘crash on error’ to ‘actually handle the -error’, by switching from `ok().expect()` to a `match` statement. The `Result` returned by `parse()` is an `enum` just like `Ordering`, but in this case, each variant has some data associated with it: `Ok` is a success, and `Err` is a failure. Each contains more information: the successfully parsed integer, or an @@ -977,7 +956,6 @@ fn main() { let mut guess = String::new(); io::stdin().read_line(&mut guess) - .ok() .expect("failed to read line"); let guess: u32 = match guess.trim().parse() { From 7300ed8e401f7a0910a17b981c315e1e3e9f8128 Mon Sep 17 00:00:00 2001 From: Ulrik Sverdrup Date: Thu, 5 Nov 2015 14:37:45 +0100 Subject: [PATCH 5/7] vec: Remove old comment in Vec::drop This comment was leftover from an earlier revision of a PR, something that never was merged. There is no ZST special casing in Vec::drop. --- src/libcollections/vec.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index a22e66583c4a9..95158054d656e 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -1384,10 +1384,6 @@ impl Ord for Vec { impl Drop for Vec { #[unsafe_destructor_blind_to_params] fn drop(&mut self) { - // NOTE: this is currently abusing the fact that ZSTs can't impl Drop. - // Or rather, that impl'ing Drop makes them not zero-sized. This is - // OK because exactly when this stops being a valid assumption, we - // don't need unsafe_no_drop_flag shenanigans anymore. if self.buf.unsafe_no_drop_flag_needs_drop() { unsafe { // The branch on needs_drop() is an -O1 performance optimization. From 58628b3f792ede73dc72848a3c71dcd8f8c0c33a Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Thu, 5 Nov 2015 16:46:56 +0100 Subject: [PATCH 6/7] Beef up macro designator docs Fixes #28824 --- src/doc/reference.md | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/doc/reference.md b/src/doc/reference.md index 037fb6a8d98d8..e0c2f4e5c3078 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -547,9 +547,20 @@ a `$` literally, including delimiters. For parsing reasons, delimiters must be balanced, but they are otherwise not special. In the matcher, `$` _name_ `:` _designator_ matches the nonterminal in the Rust -syntax named by _designator_. Valid designators are `item`, `block`, `stmt`, -`pat`, `expr`, `ty` (type), `ident`, `path`, `tt` (either side of the `=>` -in macro rules), and `meta` (contents of an attribute). In the transcriber, the +syntax named by _designator_. Valid designators are: + +* `item`: an [item](#items) +* `block`: a [block](#block-expressions) +* `stmt`: a [statement](#statements) +* `pat`: a [pattern](#match-expressions) +* `expr`: an [expression](#expressions) +* `ty`: a [type](#types) +* `ident`: an [identifier](#identifiers) +* `path`: a [path](#paths) +* `tt`: either side of the `=>` in macro rules +* `meta`: the contents of an [attribute](#attributes) + +In the transcriber, the designator is already known, and so only the name of a matched nonterminal comes after the dollar sign. From edee0232974dde935fb7ba53dab9ba90df197a3d Mon Sep 17 00:00:00 2001 From: Rizky Luthfianto Date: Fri, 6 Nov 2015 00:15:32 +0700 Subject: [PATCH 7/7] doc(lib.rs): fix #L79 with inline link syntax --- src/libstd/lib.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 9acf5795fa2c0..01effcadb3aca 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -76,7 +76,7 @@ //! `i32`](primitive.i32.html) that lists all the methods that can be called on //! 32-bit integers (very useful), and there is a [page for the module //! `std::i32`](i32/index.html) that documents the constant values [`MIN`] and -//! [`MAX`] (rarely useful). +//! [`MAX`](i32/constant.MAX.html) (rarely useful). //! //! Note the documentation for the primitives [`str`] and [`[T]`][slice] (also //! called 'slice'). Many method calls on [`String`] and [`Vec`] are actually @@ -153,7 +153,6 @@ //! //! [I/O]: io/index.html //! [MIN]: i32/constant.MIN.html -//! [MAX]: i32/constant.MAX.html //! [TCP]: net/struct.TcpStream.html //! [The Rust Prelude]: prelude/index.html //! [UDP]: net/struct.UdpSocket.html