<commit_before>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::AccountData;
use admission_control_proto::{
    proto::{
        admission_control::{
            SubmitTransactionRequest, SubmitTransactionResponse as ProtoSubmitTransactionResponse,
        },
        admission_control_grpc::AdmissionControlClient,
    },
    AdmissionControlStatus, SubmitTransactionResponse,
};
use failure::prelude::*;
use futures::Future;
use grpcio::{CallOption, ChannelBuilder, EnvBuilder};
use logger::prelude::*;
use proto_conv::{FromProto, IntoProto};
use std::sync::Arc;
use types::{
    access_path::AccessPath,
    account_address::AccountAddress,
    account_config::get_account_resource_or_default,
    account_state_blob::{AccountStateBlob, AccountStateWithProof},
    contract_event::{ContractEvent, EventWithProof},
    get_with_proof::{
        RequestItem, ResponseItem, UpdateToLatestLedgerRequest, UpdateToLatestLedgerResponse,
    },
    transaction::{SignedTransaction, Version},
    validator_verifier::ValidatorVerifier,
    vm_error::{VMStatus, VMValidationStatus},
};

const MAX_GRPC_RETRY_COUNT: u64 = 1;

/// Struct holding dependencies of client.
pub struct GRPCClient {
    client: AdmissionControlClient,
    validator_verifier: Arc<ValidatorVerifier>,
}

impl GRPCClient {
    /// Construct a new Client instance.
    pub fn new(host: &str, port: &str, validator_verifier: Arc<ValidatorVerifier>) -> Result<Self> {
        let conn_addr = format!("{}:{}", host, port);

        // Create a GRPC client
        let env = Arc::new(EnvBuilder::new().name_prefix("grpc-client-").build());
        let ch = ChannelBuilder::new(env).connect(&conn_addr);
        let client = AdmissionControlClient::new(ch);

        Ok(GRPCClient {
            client,
            validator_verifier,
        })
    }

    /// Submits a transaction and bumps the sequence number for the sender, pass in `None` for
    /// sender_account if sender's address is not managed by the client.
    pub fn submit_transaction(
        &self,
        sender_account_opt: Option<&mut AccountData>,
        req: &SubmitTransactionRequest,
    ) -> Result<()> {
        let mut resp = self.submit_transaction_opt(req);

        let mut try_cnt = 0_u64;
        while Self::need_to_retry(&mut try_cnt, &resp) {
            resp = self.submit_transaction_opt(&req);
        }

        let completed_resp = SubmitTransactionResponse::from_proto(resp?)?;

        if let Some(ac_status) = completed_resp.ac_status {
            if ac_status == AdmissionControlStatus::Accepted {
                if let Some(sender_account) = sender_account_opt {
                    // Bump up sequence_number if transaction is accepted.
                    sender_account.sequence_number += 1;
                }
            } else {
                bail!("Transaction failed with AC status: {:?}", ac_status,);
            }
        } else if let Some(vm_error) = completed_resp.vm_error {
            if vm_error == VMStatus::Validation(VMValidationStatus::SequenceNumberTooOld) {
                if let Some(sender_account) = sender_account_opt {
                    sender_account.sequence_number =
                        self.get_sequence_number(sender_account.address)?;
                    bail!(
                        "Transaction failed with vm status: {:?}, please retry your transaction.",
                        vm_error
                    );
                }
            }
            bail!("Transaction failed with vm status: {:?}", vm_error);
        } else if let Some(mempool_error) = completed_resp.mempool_error {
            bail!(
                "Transaction failed with mempool status: {:?}",
                mempool_error,
            );
        } else {
            bail!(
                "Malformed SubmitTransactionResponse which has no status set, {:?}",
                completed_resp,
            );
        }
        Ok(())
    }

    /// Async version of submit_transaction
    pub fn submit_transaction_async(
        &self,
        req: &SubmitTransactionRequest,
    ) -> Result<(impl Future<Item = SubmitTransactionResponse, Error = failure::Error>)> {
        let resp = self
            .client
            .submit_transaction_async_opt(&req, Self::get_default_grpc_call_option())?
            .then(|proto_resp| {
                let ret = SubmitTransactionResponse::from_proto(proto_resp?)?;
                Ok(ret)
            });
        Ok(resp)
    }

    fn submit_transaction_opt(
        &self,
        resp: &SubmitTransactionRequest,
    ) -> Result<ProtoSubmitTransactionResponse> {
        Ok(self
            .client
            .submit_transaction_opt(resp, Self::get_default_grpc_call_option())?)
    }

    fn get_with_proof_async(
        &self,
        requested_items: Vec<RequestItem>,
    ) -> Result<impl Future<Item = UpdateToLatestLedgerResponse, Error = failure::Error>> {
        let req = UpdateToLatestLedgerRequest::new(0, requested_items.clone());
        debug!("get_with_proof with request: {:?}", req);
        let proto_req = req.clone().into_proto();
        let arc_validator_verifier: Arc<ValidatorVerifier> = Arc::clone(&self.validator_verifier);
        let ret = self
            .client
            .update_to_latest_ledger_async_opt(&proto_req, Self::get_default_grpc_call_option())?
            .then(move |get_with_proof_resp| {
                // TODO: Cache/persist client_known_version to work with validator set change when
                // the feature is available.

                let resp = UpdateToLatestLedgerResponse::from_proto(get_with_proof_resp?)?;
                resp.verify(arc_validator_verifier, &req)?;
                Ok(resp)
            });
        Ok(ret)
    }

    fn need_to_retry<T>(try_cnt: &mut u64, ret: &Result<T>) -> bool {
        if *try_cnt <= MAX_GRPC_RETRY_COUNT {
            *try_cnt += 1;
            if let Err(error) = ret {
                if let Some(grpc_error) = error.downcast_ref::<grpcio::Error>() {
                    if let grpcio::Error::RpcFailure(grpc_rpc_failure) = grpc_error {
                        // Only retry when the connection is down to make sure we won't
                        // send one txn twice.
                        return grpc_rpc_failure.status == grpcio::RpcStatusCode::Unavailable;
                    }
                }
            }
        }
        false
    }
    /// Sync version of get_with_proof
    pub(crate) fn get_with_proof_sync(
        &self,
        requested_items: Vec<RequestItem>,
    ) -> Result<UpdateToLatestLedgerResponse> {
        let mut resp: Result<UpdateToLatestLedgerResponse> =
            self.get_with_proof_async(requested_items.clone())?.wait();
        let mut try_cnt = 0_u64;

        while Self::need_to_retry(&mut try_cnt, &resp) {
            resp = self.get_with_proof_async(requested_items.clone())?.wait();
        }

        Ok(resp?)
    }

    /// Get the latest account sequence number for the account specified.
    pub fn get_sequence_number(&self, address: AccountAddress) -> Result<u64> {
        Ok(get_account_resource_or_default(&self.get_account_blob(address)?.0)?.sequence_number())
    }

    /// Get the latest account state blob from validator.
    pub(crate) fn get_account_blob(
        &self,
        address: AccountAddress,
    ) -> Result<(Option<AccountStateBlob>, Version)> {
        let req_item = RequestItem::GetAccountState { address };

        let mut response = self.get_with_proof_sync(vec![req_item])?;
        let account_state_with_proof = response
            .response_items
            .remove(0)
            .into_get_account_state_response()?;

        Ok((
            account_state_with_proof.blob,
            response.ledger_info_with_sigs.ledger_info().version(),
        ))
    }

    /// Get transaction from validator by account and sequence number.
    pub fn get_txn_by_acc_seq(
        &self,
        account: AccountAddress,
        sequence_number: u64,
        fetch_events: bool,
    ) -> Result<Option<(SignedTransaction, Option<Vec<ContractEvent>>)>> {
        let req_item = RequestItem::GetAccountTransactionBySequenceNumber {
            account,
            sequence_number,
            fetch_events,
        };

        let mut response = self.get_with_proof_sync(vec![req_item])?;
        let (signed_txn_with_proof, _) = response
            .response_items
            .remove(0)
            .into_get_account_txn_by_seq_num_response()?;

        Ok(signed_txn_with_proof.map(|t| (t.signed_transaction, t.events)))
    }

    /// Get transactions in range (start_version..start_version + limit - 1) from validator.
    pub fn get_txn_by_range(
        &self,
        start_version: u64,
        limit: u64,
        fetch_events: bool,
    ) -> Result<Vec<(SignedTransaction, Option<Vec<ContractEvent>>)>> {
        // Make the request.
        let req_item = RequestItem::GetTransactions {
            start_version,
            limit,
            fetch_events,
        };
        let mut response = self.get_with_proof_sync(vec![req_item])?;
        let txn_list_with_proof = response
            .response_items
            .remove(0)
            .into_get_transactions_response()?;

        // Transform the response.
        let num_txns = txn_list_with_proof.transaction_and_infos.len();
        let event_lists = txn_list_with_proof
            .events
            .map(|event_lists| event_lists.into_iter().map(Some).collect())
            .unwrap_or_else(|| vec![None; num_txns]);

        let res = itertools::zip_eq(txn_list_with_proof.transaction_and_infos, event_lists)
            .map(|((signed_txn, _), events)| (signed_txn, events))
            .collect();
        Ok(res)
    }

    /// Get event by access path from validator. AccountStateWithProof will be returned if
    /// 1. No event is available. 2. Ascending and available event number < limit.
    /// 3. Descending and start_seq_num > latest account event sequence number.
    pub fn get_events_by_access_path(
        &self,
        access_path: AccessPath,
        start_event_seq_num: u64,
        ascending: bool,
        limit: u64,
    ) -> Result<(Vec<EventWithProof>, Option<AccountStateWithProof>)> {
        let req_item = RequestItem::GetEventsByEventAccessPath {
            access_path,
            start_event_seq_num,
            ascending,
            limit,
        };

        let mut response = self.get_with_proof_sync(vec![req_item])?;
        let value_with_proof = response.response_items.remove(0);
        match value_with_proof {
            ResponseItem::GetEventsByEventAccessPath {
                events_with_proof,
                proof_of_latest_event,
            } => Ok((events_with_proof, proof_of_latest_event)),
            _ => bail!(
                "Incorrect type of response returned: {:?}",
                value_with_proof
            ),
        }
    }

    fn get_default_grpc_call_option() -> CallOption {
        CallOption::default()
            .wait_for_ready(true)
            .timeout(std::time::Duration::from_millis(5000))
    }
}
<commit_msg>[Client] Rename arc_validator_verifier<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::AccountData;
use admission_control_proto::{
    proto::{
        admission_control::{
            SubmitTransactionRequest, SubmitTransactionResponse as ProtoSubmitTransactionResponse,
        },
        admission_control_grpc::AdmissionControlClient,
    },
    AdmissionControlStatus, SubmitTransactionResponse,
};
use failure::prelude::*;
use futures::Future;
use grpcio::{CallOption, ChannelBuilder, EnvBuilder};
use logger::prelude::*;
use proto_conv::{FromProto, IntoProto};
use std::sync::Arc;
use types::{
    access_path::AccessPath,
    account_address::AccountAddress,
    account_config::get_account_resource_or_default,
    account_state_blob::{AccountStateBlob, AccountStateWithProof},
    contract_event::{ContractEvent, EventWithProof},
    get_with_proof::{
        RequestItem, ResponseItem, UpdateToLatestLedgerRequest, UpdateToLatestLedgerResponse,
    },
    transaction::{SignedTransaction, Version},
    validator_verifier::ValidatorVerifier,
    vm_error::{VMStatus, VMValidationStatus},
};

const MAX_GRPC_RETRY_COUNT: u64 = 1;

/// Struct holding dependencies of client.
pub struct GRPCClient {
    client: AdmissionControlClient,
    validator_verifier: Arc<ValidatorVerifier>,
}

impl GRPCClient {
    /// Construct a new Client instance.
    pub fn new(host: &str, port: &str, validator_verifier: Arc<ValidatorVerifier>) -> Result<Self> {
        let conn_addr = format!("{}:{}", host, port);

        // Create a GRPC client
        let env = Arc::new(EnvBuilder::new().name_prefix("grpc-client-").build());
        let ch = ChannelBuilder::new(env).connect(&conn_addr);
        let client = AdmissionControlClient::new(ch);

        Ok(GRPCClient {
            client,
            validator_verifier,
        })
    }

    /// Submits a transaction and bumps the sequence number for the sender, pass in `None` for
    /// sender_account if sender's address is not managed by the client.
    pub fn submit_transaction(
        &self,
        sender_account_opt: Option<&mut AccountData>,
        req: &SubmitTransactionRequest,
    ) -> Result<()> {
        let mut resp = self.submit_transaction_opt(req);

        let mut try_cnt = 0_u64;
        while Self::need_to_retry(&mut try_cnt, &resp) {
            resp = self.submit_transaction_opt(&req);
        }

        let completed_resp = SubmitTransactionResponse::from_proto(resp?)?;

        if let Some(ac_status) = completed_resp.ac_status {
            if ac_status == AdmissionControlStatus::Accepted {
                if let Some(sender_account) = sender_account_opt {
                    // Bump up sequence_number if transaction is accepted.
                    sender_account.sequence_number += 1;
                }
            } else {
                bail!("Transaction failed with AC status: {:?}", ac_status,);
            }
        } else if let Some(vm_error) = completed_resp.vm_error {
            if vm_error == VMStatus::Validation(VMValidationStatus::SequenceNumberTooOld) {
                if let Some(sender_account) = sender_account_opt {
                    sender_account.sequence_number =
                        self.get_sequence_number(sender_account.address)?;
                    bail!(
                        "Transaction failed with vm status: {:?}, please retry your transaction.",
                        vm_error
                    );
                }
            }
            bail!("Transaction failed with vm status: {:?}", vm_error);
        } else if let Some(mempool_error) = completed_resp.mempool_error {
            bail!(
                "Transaction failed with mempool status: {:?}",
                mempool_error,
            );
        } else {
            bail!(
                "Malformed SubmitTransactionResponse which has no status set, {:?}",
                completed_resp,
            );
        }
        Ok(())
    }

    /// Async version of submit_transaction
    pub fn submit_transaction_async(
        &self,
        req: &SubmitTransactionRequest,
    ) -> Result<(impl Future<Item = SubmitTransactionResponse, Error = failure::Error>)> {
        let resp = self
            .client
            .submit_transaction_async_opt(&req, Self::get_default_grpc_call_option())?
            .then(|proto_resp| {
                let ret = SubmitTransactionResponse::from_proto(proto_resp?)?;
                Ok(ret)
            });
        Ok(resp)
    }

    fn submit_transaction_opt(
        &self,
        resp: &SubmitTransactionRequest,
    ) -> Result<ProtoSubmitTransactionResponse> {
        Ok(self
            .client
            .submit_transaction_opt(resp, Self::get_default_grpc_call_option())?)
    }

    fn get_with_proof_async(
        &self,
        requested_items: Vec<RequestItem>,
    ) -> Result<impl Future<Item = UpdateToLatestLedgerResponse, Error = failure::Error>> {
        let req = UpdateToLatestLedgerRequest::new(0, requested_items.clone());
        debug!("get_with_proof with request: {:?}", req);
        let proto_req = req.clone().into_proto();
        let validator_verifier = Arc::clone(&self.validator_verifier);
        let ret = self
            .client
            .update_to_latest_ledger_async_opt(&proto_req, Self::get_default_grpc_call_option())?
            .then(move |get_with_proof_resp| {
                // TODO: Cache/persist client_known_version to work with validator set change when
                // the feature is available.

                let resp = UpdateToLatestLedgerResponse::from_proto(get_with_proof_resp?)?;
                resp.verify(validator_verifier, &req)?;
                Ok(resp)
            });
        Ok(ret)
    }

    fn need_to_retry<T>(try_cnt: &mut u64, ret: &Result<T>) -> bool {
        if *try_cnt <= MAX_GRPC_RETRY_COUNT {
            *try_cnt += 1;
            if let Err(error) = ret {
                if let Some(grpc_error) = error.downcast_ref::<grpcio::Error>() {
                    if let grpcio::Error::RpcFailure(grpc_rpc_failure) = grpc_error {
                        // Only retry when the connection is down to make sure we won't
                        // send one txn twice.
                        return grpc_rpc_failure.status == grpcio::RpcStatusCode::Unavailable;
                    }
                }
            }
        }
        false
    }
    /// Sync version of get_with_proof
    pub(crate) fn get_with_proof_sync(
        &self,
        requested_items: Vec<RequestItem>,
    ) -> Result<UpdateToLatestLedgerResponse> {
        let mut resp: Result<UpdateToLatestLedgerResponse> =
            self.get_with_proof_async(requested_items.clone())?.wait();
        let mut try_cnt = 0_u64;

        while Self::need_to_retry(&mut try_cnt, &resp) {
            resp = self.get_with_proof_async(requested_items.clone())?.wait();
        }

        Ok(resp?)
    }

    /// Get the latest account sequence number for the account specified.
    pub fn get_sequence_number(&self, address: AccountAddress) -> Result<u64> {
        Ok(get_account_resource_or_default(&self.get_account_blob(address)?.0)?.sequence_number())
    }

    /// Get the latest account state blob from validator.
    pub(crate) fn get_account_blob(
        &self,
        address: AccountAddress,
    ) -> Result<(Option<AccountStateBlob>, Version)> {
        let req_item = RequestItem::GetAccountState { address };

        let mut response = self.get_with_proof_sync(vec![req_item])?;
        let account_state_with_proof = response
            .response_items
            .remove(0)
            .into_get_account_state_response()?;

        Ok((
            account_state_with_proof.blob,
            response.ledger_info_with_sigs.ledger_info().version(),
        ))
    }

    /// Get transaction from validator by account and sequence number.
    pub fn get_txn_by_acc_seq(
        &self,
        account: AccountAddress,
        sequence_number: u64,
        fetch_events: bool,
    ) -> Result<Option<(SignedTransaction, Option<Vec<ContractEvent>>)>> {
        let req_item = RequestItem::GetAccountTransactionBySequenceNumber {
            account,
            sequence_number,
            fetch_events,
        };

        let mut response = self.get_with_proof_sync(vec![req_item])?;
        let (signed_txn_with_proof, _) = response
            .response_items
            .remove(0)
            .into_get_account_txn_by_seq_num_response()?;

        Ok(signed_txn_with_proof.map(|t| (t.signed_transaction, t.events)))
    }

    /// Get transactions in range (start_version..start_version + limit - 1) from validator.
    pub fn get_txn_by_range(
        &self,
        start_version: u64,
        limit: u64,
        fetch_events: bool,
    ) -> Result<Vec<(SignedTransaction, Option<Vec<ContractEvent>>)>> {
        // Make the request.
        let req_item = RequestItem::GetTransactions {
            start_version,
            limit,
            fetch_events,
        };
        let mut response = self.get_with_proof_sync(vec![req_item])?;
        let txn_list_with_proof = response
            .response_items
            .remove(0)
            .into_get_transactions_response()?;

        // Transform the response.
        let num_txns = txn_list_with_proof.transaction_and_infos.len();
        let event_lists = txn_list_with_proof
            .events
            .map(|event_lists| event_lists.into_iter().map(Some).collect())
            .unwrap_or_else(|| vec![None; num_txns]);

        let res = itertools::zip_eq(txn_list_with_proof.transaction_and_infos, event_lists)
            .map(|((signed_txn, _), events)| (signed_txn, events))
            .collect();
        Ok(res)
    }

    /// Get event by access path from validator. AccountStateWithProof will be returned if
    /// 1. No event is available. 2. Ascending and available event number < limit.
    /// 3. Descending and start_seq_num > latest account event sequence number.
    pub fn get_events_by_access_path(
        &self,
        access_path: AccessPath,
        start_event_seq_num: u64,
        ascending: bool,
        limit: u64,
    ) -> Result<(Vec<EventWithProof>, Option<AccountStateWithProof>)> {
        let req_item = RequestItem::GetEventsByEventAccessPath {
            access_path,
            start_event_seq_num,
            ascending,
            limit,
        };

        let mut response = self.get_with_proof_sync(vec![req_item])?;
        let value_with_proof = response.response_items.remove(0);
        match value_with_proof {
            ResponseItem::GetEventsByEventAccessPath {
                events_with_proof,
                proof_of_latest_event,
            } => Ok((events_with_proof, proof_of_latest_event)),
            _ => bail!(
                "Incorrect type of response returned: {:?}",
                value_with_proof
            ),
        }
    }

    fn get_default_grpc_call_option() -> CallOption {
        CallOption::default()
            .wait_for_ready(true)
            .timeout(std::time::Duration::from_millis(5000))
    }
}
<|endoftext|>


<commit_before>use crate::utils::{
    in_macro_or_desugar, match_def_path,
    paths::{BEGIN_PANIC, BEGIN_PANIC_FMT},
    resolve_node, snippet_opt, span_lint_and_then,
};
use if_chain::if_chain;
use rustc::{
    declare_lint_pass, declare_tool_lint,
    hir::{intravisit::FnKind, Body, Expr, ExprKind, FnDecl, HirId, MatchSource, StmtKind},
    lint::{LateContext, LateLintPass, LintArray, LintPass},
};
use rustc_errors::Applicability;
use syntax_pos::Span;

declare_clippy_lint! {
    /// **What it does:** Checks for missing return statements at the end of a block.
    ///
    /// **Why is this bad?** Actually omitting the return keyword is idiomatic Rust code. Programmers
    /// coming from other languages might prefer the expressiveness of `return`. It's possible to miss
    /// the last returning statement because the only difference is a missing `;`. Especially in bigger
    /// code with multiple return paths having a `return` keyword makes it easier to find the
    /// corresponding statements.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```rust
    /// fn foo(x: usize) -> usize {
    ///     x
    /// }
    /// ```
    /// add return
    /// ```rust
    /// fn foo(x: usize) -> usize {
    ///     return x;
    /// }
    /// ```
    pub IMPLICIT_RETURN,
    restriction,
    "use a return statement like `return expr` instead of an expression"
}

declare_lint_pass!(ImplicitReturn => [IMPLICIT_RETURN]);

static LINT_BREAK: &str = "change `break` to `return` as shown";
static LINT_RETURN: &str = "add `return` as shown";

fn lint(cx: &LateContext<'_, '_>, outer_span: Span, inner_span: Span, msg: &str) {
    let outer_span = span_to_outer_expn(outer_span);
    let inner_span = span_to_outer_expn(inner_span);

    span_lint_and_then(cx, IMPLICIT_RETURN, outer_span, "missing return statement", |db| {
        if let Some(snippet) = snippet_opt(cx, inner_span) {
            db.span_suggestion(
                outer_span,
                msg,
                format!("return {}", snippet),
                Applicability::MachineApplicable,
            );
        }
    });
}

fn span_to_outer_expn(span: Span) -> Span {
    if let Some(expr) = span.ctxt().outer_expn_info() {
        span_to_outer_expn(expr.call_site)
    } else {
        span
    }
}

fn expr_match(cx: &LateContext<'_, '_>, expr: &Expr) {
    match &expr.node {
        // loops could be using `break` instead of `return`
        ExprKind::Block(block, ..) | ExprKind::Loop(block, ..) => {
            if let Some(expr) = &block.expr {
                expr_match(cx, expr);
            }
            // only needed in the case of `break` with `;` at the end
            else if let Some(stmt) = block.stmts.last() {
                if_chain! {
                    if let StmtKind::Semi(expr, ..) = &stmt.node;
                    // make sure it's a break, otherwise we want to skip
                    if let ExprKind::Break(.., break_expr) = &expr.node;
                    if let Some(break_expr) = break_expr;
                    then {
                            lint(cx, expr.span, break_expr.span, LINT_BREAK);
                    }
                }
            }
        },
        // use `return` instead of `break`
        ExprKind::Break(.., break_expr) => {
            if let Some(break_expr) = break_expr {
                lint(cx, expr.span, break_expr.span, LINT_BREAK);
            }
        },
        ExprKind::Match(.., arms, source) => {
            let check_all_arms = match source {
                MatchSource::IfLetDesugar {
                    contains_else_clause: has_else,
                } => *has_else,
                _ => true,
            };

            if check_all_arms {
                for arm in arms {
                    expr_match(cx, &arm.body);
                }
            } else {
                expr_match(cx, &arms.first().expect("if let doesn't have a single arm").body);
            }
        },
        // skip if it already has a return statement
        ExprKind::Ret(..) => (),
        // make sure it's not a call that panics
        ExprKind::Call(expr, ..) => {
            if_chain! {
                if let ExprKind::Path(qpath) = &expr.node;
                if let Some(path_def_id) = resolve_node(cx, qpath, expr.hir_id).opt_def_id();
                if match_def_path(cx, path_def_id, &BEGIN_PANIC) ||
                    match_def_path(cx, path_def_id, &BEGIN_PANIC_FMT);
                then { }
                else {
                    lint(cx, expr.span, expr.span, LINT_RETURN)
                }
            }
        },
        // everything else is missing `return`
        _ => lint(cx, expr.span, expr.span, LINT_RETURN),
    }
}

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ImplicitReturn {
    fn check_fn(
        &mut self,
        cx: &LateContext<'a, 'tcx>,
        _: FnKind<'tcx>,
        _: &'tcx FnDecl,
        body: &'tcx Body,
        span: syntax::source_map::Span,
        _: HirId,
    ) {
        let def_id = cx.tcx.hir().body_owner_def_id(body.id());
        let mir = cx.tcx.optimized_mir(def_id);

        // checking return type through MIR, HIR is not able to determine inferred closure return types
        // make sure it's not a macro
        if !mir.return_ty().is_unit() && !in_macro_or_desugar(span) {
            expr_match(cx, &body.value);
        }
    }
}
<commit_msg>Improved imports<commit_after>use crate::utils::{
    in_macro_or_desugar, match_def_path,
    paths::{BEGIN_PANIC, BEGIN_PANIC_FMT},
    resolve_node, snippet_opt, span_lint_and_then,
};
use if_chain::if_chain;
use rustc::{
    declare_lint_pass, declare_tool_lint,
    hir::{intravisit::FnKind, Body, Expr, ExprKind, FnDecl, HirId, MatchSource, StmtKind},
    lint::{LateContext, LateLintPass, LintArray, LintPass},
};
use rustc_errors::Applicability;
use syntax::source_map::Span;

declare_clippy_lint! {
    /// **What it does:** Checks for missing return statements at the end of a block.
    ///
    /// **Why is this bad?** Actually omitting the return keyword is idiomatic Rust code. Programmers
    /// coming from other languages might prefer the expressiveness of `return`. It's possible to miss
    /// the last returning statement because the only difference is a missing `;`. Especially in bigger
    /// code with multiple return paths having a `return` keyword makes it easier to find the
    /// corresponding statements.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```rust
    /// fn foo(x: usize) -> usize {
    ///     x
    /// }
    /// ```
    /// add return
    /// ```rust
    /// fn foo(x: usize) -> usize {
    ///     return x;
    /// }
    /// ```
    pub IMPLICIT_RETURN,
    restriction,
    "use a return statement like `return expr` instead of an expression"
}

declare_lint_pass!(ImplicitReturn => [IMPLICIT_RETURN]);

static LINT_BREAK: &str = "change `break` to `return` as shown";
static LINT_RETURN: &str = "add `return` as shown";

fn lint(cx: &LateContext<'_, '_>, outer_span: Span, inner_span: Span, msg: &str) {
    let outer_span = span_to_outer_expn(outer_span);
    let inner_span = span_to_outer_expn(inner_span);

    span_lint_and_then(cx, IMPLICIT_RETURN, outer_span, "missing return statement", |db| {
        if let Some(snippet) = snippet_opt(cx, inner_span) {
            db.span_suggestion(
                outer_span,
                msg,
                format!("return {}", snippet),
                Applicability::MachineApplicable,
            );
        }
    });
}

fn span_to_outer_expn(span: Span) -> Span {
    if let Some(expr) = span.ctxt().outer_expn_info() {
        span_to_outer_expn(expr.call_site)
    } else {
        span
    }
}

fn expr_match(cx: &LateContext<'_, '_>, expr: &Expr) {
    match &expr.node {
        // loops could be using `break` instead of `return`
        ExprKind::Block(block, ..) | ExprKind::Loop(block, ..) => {
            if let Some(expr) = &block.expr {
                expr_match(cx, expr);
            }
            // only needed in the case of `break` with `;` at the end
            else if let Some(stmt) = block.stmts.last() {
                if_chain! {
                    if let StmtKind::Semi(expr, ..) = &stmt.node;
                    // make sure it's a break, otherwise we want to skip
                    if let ExprKind::Break(.., break_expr) = &expr.node;
                    if let Some(break_expr) = break_expr;
                    then {
                            lint(cx, expr.span, break_expr.span, LINT_BREAK);
                    }
                }
            }
        },
        // use `return` instead of `break`
        ExprKind::Break(.., break_expr) => {
            if let Some(break_expr) = break_expr {
                lint(cx, expr.span, break_expr.span, LINT_BREAK);
            }
        },
        ExprKind::Match(.., arms, source) => {
            let check_all_arms = match source {
                MatchSource::IfLetDesugar {
                    contains_else_clause: has_else,
                } => *has_else,
                _ => true,
            };

            if check_all_arms {
                for arm in arms {
                    expr_match(cx, &arm.body);
                }
            } else {
                expr_match(cx, &arms.first().expect("if let doesn't have a single arm").body);
            }
        },
        // skip if it already has a return statement
        ExprKind::Ret(..) => (),
        // make sure it's not a call that panics
        ExprKind::Call(expr, ..) => {
            if_chain! {
                if let ExprKind::Path(qpath) = &expr.node;
                if let Some(path_def_id) = resolve_node(cx, qpath, expr.hir_id).opt_def_id();
                if match_def_path(cx, path_def_id, &BEGIN_PANIC) ||
                    match_def_path(cx, path_def_id, &BEGIN_PANIC_FMT);
                then { }
                else {
                    lint(cx, expr.span, expr.span, LINT_RETURN)
                }
            }
        },
        // everything else is missing `return`
        _ => lint(cx, expr.span, expr.span, LINT_RETURN),
    }
}

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ImplicitReturn {
    fn check_fn(
        &mut self,
        cx: &LateContext<'a, 'tcx>,
        _: FnKind<'tcx>,
        _: &'tcx FnDecl,
        body: &'tcx Body,
        span: Span,
        _: HirId,
    ) {
        let def_id = cx.tcx.hir().body_owner_def_id(body.id());
        let mir = cx.tcx.optimized_mir(def_id);

        // checking return type through MIR, HIR is not able to determine inferred closure return types
        // make sure it's not a macro
        if !mir.return_ty().is_unit() && !in_macro_or_desugar(span) {
            expr_match(cx, &body.value);
        }
    }
}
<|endoftext|>


<commit_before>use crate::utils::{
    has_drop, in_macro, is_copy, match_def_path, match_type, paths, snippet_opt, span_lint_hir, span_lint_hir_and_then,
    walk_ptrs_ty_depth,
};
use if_chain::if_chain;
use matches::matches;
use rustc::hir::intravisit::FnKind;
use rustc::hir::{def_id, Body, FnDecl, HirId};
use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use rustc::mir::{
    self, traversal,
    visit::{MutatingUseContext, PlaceContext, Visitor},
    TerminatorKind,
};
use rustc::ty::{self, Ty};
use rustc::{declare_tool_lint, lint_array};
use rustc_errors::Applicability;
use std::convert::TryFrom;
use syntax::source_map::{BytePos, Span};

macro_rules! unwrap_or_continue {
    ($x:expr) => {
        match $x {
            Some(x) => x,
            None => continue,
        }
    };
}

declare_clippy_lint! {
    /// **What it does:** Checks for a redudant `clone()` (and its relatives) which clones an owned
    /// value that is going to be dropped without further use.
    ///
    /// **Why is this bad?** It is not always possible for the compiler to eliminate useless
    /// allocations and deallocations generated by redundant `clone()`s.
    ///
    /// **Known problems:**
    ///
    /// * Suggestions made by this lint could require NLL to be enabled.
    /// * False-positive if there is a borrow preventing the value from moving out.
    ///
    /// ```rust
    /// let x = String::new();
    ///
    /// let y = &x;
    ///
    /// foo(x.clone()); // This lint suggests to remove this `clone()`
    /// ```
    ///
    /// **Example:**
    /// ```rust
    /// {
    ///     let x = Foo::new();
    ///     call(x.clone());
    ///     call(x.clone()); // this can just pass `x`
    /// }
    ///
    /// ["lorem", "ipsum"].join(" ").to_string()
    ///
    /// Path::new("/a/b").join("c").to_path_buf()
    /// ```
    pub REDUNDANT_CLONE,
    nursery,
    "`clone()` of an owned value that is going to be dropped immediately"
}

pub struct RedundantClone;

impl LintPass for RedundantClone {
    fn get_lints(&self) -> LintArray {
        lint_array!(REDUNDANT_CLONE)
    }

    fn name(&self) -> &'static str {
        "RedundantClone"
    }
}

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for RedundantClone {
    #[allow(clippy::too_many_lines)]
    fn check_fn(
        &mut self,
        cx: &LateContext<'a, 'tcx>,
        _: FnKind<'tcx>,
        _: &'tcx FnDecl,
        body: &'tcx Body,
        _: Span,
        _: HirId,
    ) {
        let def_id = cx.tcx.hir().body_owner_def_id(body.id());
        let mir = cx.tcx.optimized_mir(def_id);

        for (bb, bbdata) in mir.basic_blocks().iter_enumerated() {
            let terminator = bbdata.terminator();

            if in_macro(terminator.source_info.span) {
                continue;
            }

            // Give up on loops
            if terminator.successors().any(|s| *s == bb) {
                continue;
            }

            let (fn_def_id, arg, arg_ty, _) = unwrap_or_continue!(is_call_with_ref_arg(cx, mir, &terminator.kind));

            let from_borrow = match_def_path(cx.tcx, fn_def_id, &paths::CLONE_TRAIT_METHOD)
                || match_def_path(cx.tcx, fn_def_id, &paths::TO_OWNED_METHOD)
                || (match_def_path(cx.tcx, fn_def_id, &paths::TO_STRING_METHOD)
                    && match_type(cx, arg_ty, &paths::STRING));

            let from_deref = !from_borrow
                && (match_def_path(cx.tcx, fn_def_id, &paths::PATH_TO_PATH_BUF)
                    || match_def_path(cx.tcx, fn_def_id, &paths::OS_STR_TO_OS_STRING));

            if !from_borrow && !from_deref {
                continue;
            }

            // _1 in MIR `{ _2 = &_1; clone(move _2); }` or `{ _2 = _1; to_path_buf(_2); } (from_deref)
            // In case of `from_deref`, `arg` is already a reference since it is `deref`ed in the previous
            // block.
            let (cloned, cannot_move_out) = unwrap_or_continue!(find_stmt_assigns_to(
                cx,
                mir,
                arg,
                from_borrow,
                bbdata.statements.iter()
            ));

            if from_borrow && cannot_move_out {
                continue;
            }

            // _1 in MIR `{ _2 = &_1; _3 = deref(move _2); } -> { _4 = _3; to_path_buf(move _4); }`
            let referent = if from_deref {
                let ps = mir.predecessors_for(bb);
                if ps.len() != 1 {
                    continue;
                }
                let pred_terminator = mir[ps[0]].terminator();

                let pred_arg = if_chain! {
                    if let Some((pred_fn_def_id, pred_arg, pred_arg_ty, Some(res))) =
                        is_call_with_ref_arg(cx, mir, &pred_terminator.kind);
                    if *res == mir::Place::Base(mir::PlaceBase::Local(cloned));
                    if match_def_path(cx.tcx, pred_fn_def_id, &paths::DEREF_TRAIT_METHOD);
                    if match_type(cx, pred_arg_ty, &paths::PATH_BUF)
                        || match_type(cx, pred_arg_ty, &paths::OS_STRING);
                    then {
                        pred_arg
                    } else {
                        continue;
                    }
                };

                let (local, cannot_move_out) = unwrap_or_continue!(find_stmt_assigns_to(
                    cx,
                    mir,
                    pred_arg,
                    true,
                    mir[ps[0]].statements.iter()
                ));
                if cannot_move_out {
                    continue;
                }
                local
            } else {
                cloned
            };

            let used_later = traversal::ReversePostorder::new(&mir, bb).skip(1).any(|(tbb, tdata)| {
                // Give up on loops
                if tdata.terminator().successors().any(|s| *s == bb) {
                    return true;
                }

                let mut vis = LocalUseVisitor {
                    local: referent,
                    used_other_than_drop: false,
                };
                vis.visit_basic_block_data(tbb, tdata);
                vis.used_other_than_drop
            });

            if !used_later {
                let span = terminator.source_info.span;
                let node = if let mir::ClearCrossCrate::Set(scope_local_data) = &mir.source_scope_local_data {
                    scope_local_data[terminator.source_info.scope].lint_root
                } else {
                    unreachable!()
                };

                if_chain! {
                    if let Some(snip) = snippet_opt(cx, span);
                    if let Some(dot) = snip.rfind('.');
                    then {
                        let sugg_span = span.with_lo(
                            span.lo() + BytePos(u32::try_from(dot).unwrap())
                        );

                        span_lint_hir_and_then(cx, REDUNDANT_CLONE, node, sugg_span, "redundant clone", |db| {
                            db.span_suggestion(
                                sugg_span,
                                "remove this",
                                String::new(),
                                Applicability::MaybeIncorrect,
                            );
                            db.span_note(
                                span.with_hi(span.lo() + BytePos(u32::try_from(dot).unwrap())),
                                "this value is dropped without further use",
                            );
                        });
                    } else {
                        span_lint_hir(cx, REDUNDANT_CLONE, node, span, "redundant clone");
                    }
                }
            }
        }
    }
}

/// If `kind` is `y = func(x: &T)` where `T: !Copy`, returns `(DefId of func, x, T, y)`.
fn is_call_with_ref_arg<'tcx>(
    cx: &LateContext<'_, 'tcx>,
    mir: &'tcx mir::Mir<'tcx>,
    kind: &'tcx mir::TerminatorKind<'tcx>,
) -> Option<(def_id::DefId, mir::Local, Ty<'tcx>, Option<&'tcx mir::Place<'tcx>>)> {
    if_chain! {
        if let TerminatorKind::Call { func, args, destination, .. } = kind;
        if args.len() == 1;
        if let mir::Operand::Move(mir::Place::Base(mir::PlaceBase::Local(local))) = &args[0];
        if let ty::FnDef(def_id, _) = func.ty(&*mir, cx.tcx).sty;
        if let (inner_ty, 1) = walk_ptrs_ty_depth(args[0].ty(&*mir, cx.tcx));
        if !is_copy(cx, inner_ty);
        then {
            Some((def_id, *local, inner_ty, destination.as_ref().map(|(dest, _)| dest)))
        } else {
            None
        }
    }
}

type CannotMoveOut = bool;

/// Finds the first `to = (&)from`, and returns
/// ``Some((from, [`true` if `from` cannot be moved out]))``.
fn find_stmt_assigns_to<'a, 'tcx: 'a>(
    cx: &LateContext<'_, 'tcx>,
    mir: &mir::Mir<'tcx>,
    to: mir::Local,
    by_ref: bool,
    stmts: impl DoubleEndedIterator<Item = &'a mir::Statement<'tcx>>,
) -> Option<(mir::Local, CannotMoveOut)> {
    stmts
        .rev()
        .find_map(|stmt| {
            if let mir::StatementKind::Assign(mir::Place::Base(mir::PlaceBase::Local(local)), v) = &stmt.kind {
                if *local == to {
                    return Some(v);
                }
            }

            None
        })
        .and_then(|v| {
            if by_ref {
                if let mir::Rvalue::Ref(_, _, ref place) = **v {
                    return base_local_and_movability(cx, mir, place);
                }
            } else if let mir::Rvalue::Use(mir::Operand::Copy(ref place)) = **v {
                return base_local_and_movability(cx, mir, place);
            }
            None
        })
}

/// Extracts and returns the undermost base `Local` of given `place`. Returns `place` itself
/// if it is already a `Local`.
///
/// Also reports whether given `place` cannot be moved out.
fn base_local_and_movability<'tcx>(
    cx: &LateContext<'_, 'tcx>,
    mir: &mir::Mir<'tcx>,
    mut place: &mir::Place<'tcx>,
) -> Option<(mir::Local, CannotMoveOut)> {
    use rustc::mir::Place::*;
    use rustc::mir::PlaceBase;

    // Dereference. You cannot move things out from a borrowed value.
    let mut deref = false;
    // Accessing a field of an ADT that has `Drop`. Moving the field out will cause E0509.
    let mut field = false;

    loop {
        match place {
            Base(PlaceBase::Local(local)) => return Some((*local, deref || field)),
            Projection(proj) => {
                place = &proj.base;
                deref = deref || matches!(proj.elem, mir::ProjectionElem::Deref);
                if !field && matches!(proj.elem, mir::ProjectionElem::Field(..)) {
                    field = has_drop(cx, place.ty(&mir.local_decls, cx.tcx).to_ty(cx.tcx));
                }
            },
            _ => return None,
        }
    }
}

struct LocalUseVisitor {
    local: mir::Local,
    used_other_than_drop: bool,
}

impl<'tcx> mir::visit::Visitor<'tcx> for LocalUseVisitor {
    fn visit_basic_block_data(&mut self, block: mir::BasicBlock, data: &mir::BasicBlockData<'tcx>) {
        let statements = &data.statements;
        for (statement_index, statement) in statements.iter().enumerate() {
            self.visit_statement(block, statement, mir::Location { block, statement_index });

            // Once flagged, skip remaining statements
            if self.used_other_than_drop {
                return;
            }
        }

        self.visit_terminator(
            block,
            data.terminator(),
            mir::Location {
                block,
                statement_index: statements.len(),
            },
        );
    }

    fn visit_local(&mut self, local: &mir::Local, ctx: PlaceContext<'tcx>, _: mir::Location) {
        match ctx {
            PlaceContext::MutatingUse(MutatingUseContext::Drop) | PlaceContext::NonUse(_) => return,
            _ => {},
        }

        if *local == self.local {
            self.used_other_than_drop = true;
        }
    }
}
<commit_msg>rustup https://github.com/rust-lang/rust/pull/59657<commit_after>use crate::utils::{
    has_drop, in_macro, is_copy, match_def_path, match_type, paths, snippet_opt, span_lint_hir, span_lint_hir_and_then,
    walk_ptrs_ty_depth,
};
use if_chain::if_chain;
use matches::matches;
use rustc::hir::intravisit::FnKind;
use rustc::hir::{def_id, Body, FnDecl, HirId};
use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use rustc::mir::{
    self, traversal,
    visit::{MutatingUseContext, PlaceContext, Visitor},
    TerminatorKind,
};
use rustc::ty::{self, Ty};
use rustc::{declare_tool_lint, lint_array};
use rustc_errors::Applicability;
use std::convert::TryFrom;
use syntax::source_map::{BytePos, Span};

macro_rules! unwrap_or_continue {
    ($x:expr) => {
        match $x {
            Some(x) => x,
            None => continue,
        }
    };
}

declare_clippy_lint! {
    /// **What it does:** Checks for a redudant `clone()` (and its relatives) which clones an owned
    /// value that is going to be dropped without further use.
    ///
    /// **Why is this bad?** It is not always possible for the compiler to eliminate useless
    /// allocations and deallocations generated by redundant `clone()`s.
    ///
    /// **Known problems:**
    ///
    /// * Suggestions made by this lint could require NLL to be enabled.
    /// * False-positive if there is a borrow preventing the value from moving out.
    ///
    /// ```rust
    /// let x = String::new();
    ///
    /// let y = &x;
    ///
    /// foo(x.clone()); // This lint suggests to remove this `clone()`
    /// ```
    ///
    /// **Example:**
    /// ```rust
    /// {
    ///     let x = Foo::new();
    ///     call(x.clone());
    ///     call(x.clone()); // this can just pass `x`
    /// }
    ///
    /// ["lorem", "ipsum"].join(" ").to_string()
    ///
    /// Path::new("/a/b").join("c").to_path_buf()
    /// ```
    pub REDUNDANT_CLONE,
    nursery,
    "`clone()` of an owned value that is going to be dropped immediately"
}

pub struct RedundantClone;

impl LintPass for RedundantClone {
    fn get_lints(&self) -> LintArray {
        lint_array!(REDUNDANT_CLONE)
    }

    fn name(&self) -> &'static str {
        "RedundantClone"
    }
}

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for RedundantClone {
    #[allow(clippy::too_many_lines)]
    fn check_fn(
        &mut self,
        cx: &LateContext<'a, 'tcx>,
        _: FnKind<'tcx>,
        _: &'tcx FnDecl,
        body: &'tcx Body,
        _: Span,
        _: HirId,
    ) {
        let def_id = cx.tcx.hir().body_owner_def_id(body.id());
        let mir = cx.tcx.optimized_mir(def_id);

        for (bb, bbdata) in mir.basic_blocks().iter_enumerated() {
            let terminator = bbdata.terminator();

            if in_macro(terminator.source_info.span) {
                continue;
            }

            // Give up on loops
            if terminator.successors().any(|s| *s == bb) {
                continue;
            }

            let (fn_def_id, arg, arg_ty, _) = unwrap_or_continue!(is_call_with_ref_arg(cx, mir, &terminator.kind));

            let from_borrow = match_def_path(cx.tcx, fn_def_id, &paths::CLONE_TRAIT_METHOD)
                || match_def_path(cx.tcx, fn_def_id, &paths::TO_OWNED_METHOD)
                || (match_def_path(cx.tcx, fn_def_id, &paths::TO_STRING_METHOD)
                    && match_type(cx, arg_ty, &paths::STRING));

            let from_deref = !from_borrow
                && (match_def_path(cx.tcx, fn_def_id, &paths::PATH_TO_PATH_BUF)
                    || match_def_path(cx.tcx, fn_def_id, &paths::OS_STR_TO_OS_STRING));

            if !from_borrow && !from_deref {
                continue;
            }

            // _1 in MIR `{ _2 = &_1; clone(move _2); }` or `{ _2 = _1; to_path_buf(_2); } (from_deref)
            // In case of `from_deref`, `arg` is already a reference since it is `deref`ed in the previous
            // block.
            let (cloned, cannot_move_out) = unwrap_or_continue!(find_stmt_assigns_to(
                cx,
                mir,
                arg,
                from_borrow,
                bbdata.statements.iter()
            ));

            if from_borrow && cannot_move_out {
                continue;
            }

            // _1 in MIR `{ _2 = &_1; _3 = deref(move _2); } -> { _4 = _3; to_path_buf(move _4); }`
            let referent = if from_deref {
                let ps = mir.predecessors_for(bb);
                if ps.len() != 1 {
                    continue;
                }
                let pred_terminator = mir[ps[0]].terminator();

                let pred_arg = if_chain! {
                    if let Some((pred_fn_def_id, pred_arg, pred_arg_ty, Some(res))) =
                        is_call_with_ref_arg(cx, mir, &pred_terminator.kind);
                    if *res == mir::Place::Base(mir::PlaceBase::Local(cloned));
                    if match_def_path(cx.tcx, pred_fn_def_id, &paths::DEREF_TRAIT_METHOD);
                    if match_type(cx, pred_arg_ty, &paths::PATH_BUF)
                        || match_type(cx, pred_arg_ty, &paths::OS_STRING);
                    then {
                        pred_arg
                    } else {
                        continue;
                    }
                };

                let (local, cannot_move_out) = unwrap_or_continue!(find_stmt_assigns_to(
                    cx,
                    mir,
                    pred_arg,
                    true,
                    mir[ps[0]].statements.iter()
                ));
                if cannot_move_out {
                    continue;
                }
                local
            } else {
                cloned
            };

            let used_later = traversal::ReversePostorder::new(&mir, bb).skip(1).any(|(tbb, tdata)| {
                // Give up on loops
                if tdata.terminator().successors().any(|s| *s == bb) {
                    return true;
                }

                let mut vis = LocalUseVisitor {
                    local: referent,
                    used_other_than_drop: false,
                };
                vis.visit_basic_block_data(tbb, tdata);
                vis.used_other_than_drop
            });

            if !used_later {
                let span = terminator.source_info.span;
                let node = if let mir::ClearCrossCrate::Set(scope_local_data) = &mir.source_scope_local_data {
                    scope_local_data[terminator.source_info.scope].lint_root
                } else {
                    unreachable!()
                };

                if_chain! {
                    if let Some(snip) = snippet_opt(cx, span);
                    if let Some(dot) = snip.rfind('.');
                    then {
                        let sugg_span = span.with_lo(
                            span.lo() + BytePos(u32::try_from(dot).unwrap())
                        );

                        span_lint_hir_and_then(cx, REDUNDANT_CLONE, node, sugg_span, "redundant clone", |db| {
                            db.span_suggestion(
                                sugg_span,
                                "remove this",
                                String::new(),
                                Applicability::MaybeIncorrect,
                            );
                            db.span_note(
                                span.with_hi(span.lo() + BytePos(u32::try_from(dot).unwrap())),
                                "this value is dropped without further use",
                            );
                        });
                    } else {
                        span_lint_hir(cx, REDUNDANT_CLONE, node, span, "redundant clone");
                    }
                }
            }
        }
    }
}

/// If `kind` is `y = func(x: &T)` where `T: !Copy`, returns `(DefId of func, x, T, y)`.
fn is_call_with_ref_arg<'tcx>(
    cx: &LateContext<'_, 'tcx>,
    mir: &'tcx mir::Mir<'tcx>,
    kind: &'tcx mir::TerminatorKind<'tcx>,
) -> Option<(def_id::DefId, mir::Local, Ty<'tcx>, Option<&'tcx mir::Place<'tcx>>)> {
    if_chain! {
        if let TerminatorKind::Call { func, args, destination, .. } = kind;
        if args.len() == 1;
        if let mir::Operand::Move(mir::Place::Base(mir::PlaceBase::Local(local))) = &args[0];
        if let ty::FnDef(def_id, _) = func.ty(&*mir, cx.tcx).sty;
        if let (inner_ty, 1) = walk_ptrs_ty_depth(args[0].ty(&*mir, cx.tcx));
        if !is_copy(cx, inner_ty);
        then {
            Some((def_id, *local, inner_ty, destination.as_ref().map(|(dest, _)| dest)))
        } else {
            None
        }
    }
}

type CannotMoveOut = bool;

/// Finds the first `to = (&)from`, and returns
/// ``Some((from, [`true` if `from` cannot be moved out]))``.
fn find_stmt_assigns_to<'a, 'tcx: 'a>(
    cx: &LateContext<'_, 'tcx>,
    mir: &mir::Mir<'tcx>,
    to: mir::Local,
    by_ref: bool,
    stmts: impl DoubleEndedIterator<Item = &'a mir::Statement<'tcx>>,
) -> Option<(mir::Local, CannotMoveOut)> {
    stmts
        .rev()
        .find_map(|stmt| {
            if let mir::StatementKind::Assign(mir::Place::Base(mir::PlaceBase::Local(local)), v) = &stmt.kind {
                if *local == to {
                    return Some(v);
                }
            }

            None
        })
        .and_then(|v| {
            if by_ref {
                if let mir::Rvalue::Ref(_, _, ref place) = **v {
                    return base_local_and_movability(cx, mir, place);
                }
            } else if let mir::Rvalue::Use(mir::Operand::Copy(ref place)) = **v {
                return base_local_and_movability(cx, mir, place);
            }
            None
        })
}

/// Extracts and returns the undermost base `Local` of given `place`. Returns `place` itself
/// if it is already a `Local`.
///
/// Also reports whether given `place` cannot be moved out.
fn base_local_and_movability<'tcx>(
    cx: &LateContext<'_, 'tcx>,
    mir: &mir::Mir<'tcx>,
    mut place: &mir::Place<'tcx>,
) -> Option<(mir::Local, CannotMoveOut)> {
    use rustc::mir::Place::*;
    use rustc::mir::PlaceBase;

    // Dereference. You cannot move things out from a borrowed value.
    let mut deref = false;
    // Accessing a field of an ADT that has `Drop`. Moving the field out will cause E0509.
    let mut field = false;

    loop {
        match place {
            Base(PlaceBase::Local(local)) => return Some((*local, deref || field)),
            Projection(proj) => {
                place = &proj.base;
                deref = deref || matches!(proj.elem, mir::ProjectionElem::Deref);
                if !field && matches!(proj.elem, mir::ProjectionElem::Field(..)) {
                    field = has_drop(cx, place.ty(&mir.local_decls, cx.tcx).ty);
                }
            },
            _ => return None,
        }
    }
}

struct LocalUseVisitor {
    local: mir::Local,
    used_other_than_drop: bool,
}

impl<'tcx> mir::visit::Visitor<'tcx> for LocalUseVisitor {
    fn visit_basic_block_data(&mut self, block: mir::BasicBlock, data: &mir::BasicBlockData<'tcx>) {
        let statements = &data.statements;
        for (statement_index, statement) in statements.iter().enumerate() {
            self.visit_statement(block, statement, mir::Location { block, statement_index });

            // Once flagged, skip remaining statements
            if self.used_other_than_drop {
                return;
            }
        }

        self.visit_terminator(
            block,
            data.terminator(),
            mir::Location {
                block,
                statement_index: statements.len(),
            },
        );
    }

    fn visit_local(&mut self, local: &mir::Local, ctx: PlaceContext<'tcx>, _: mir::Location) {
        match ctx {
            PlaceContext::MutatingUse(MutatingUseContext::Drop) | PlaceContext::NonUse(_) => return,
            _ => {},
        }

        if *local == self.local {
            self.used_other_than_drop = true;
        }
    }
}
<|endoftext|>


<commit_before>use rustc::hir::*;
use rustc::lint::*;
use utils::{in_macro, implements_trait, is_copy, multispan_sugg, snippet, span_lint, span_lint_and_then, SpanlessEq};

/// **What it does:** Checks for equal operands to comparison, logical and
/// bitwise, difference and division binary operators (`==`, `>`, etc., `&&`,
/// `||`, `&`, `|`, `^`, `-` and `/`).
///
/// **Why is this bad?** This is usually just a typo or a copy and paste error.
///
/// **Known problems:** False negatives: We had some false positives regarding
/// calls (notably [racer](https://github.com/phildawes/racer) had one instance
/// of `x.pop() && x.pop()`), so we removed matching any function or method
/// calls. We may introduce a whitelist of known pure functions in the future.
///
/// **Example:**
/// ```rust
/// x + 1 == x + 1
/// ```
declare_lint! {
    pub EQ_OP,
    Warn,
    "equal operands on both sides of a comparison or bitwise combination (e.g. `x == x`)"
}

/// **What it does:** Checks for arguments to `==` which have their address
/// taken to satisfy a bound
/// and suggests to dereference the other argument instead
///
/// **Why is this bad?** It is more idiomatic to dereference the other argument.
///
/// **Known problems:** None
///
/// **Example:**
/// ```rust
/// &x == y
/// ```
declare_lint! {
    pub OP_REF,
    Warn,
    "taking a reference to satisfy the type constraints on `==`"
}

#[derive(Copy, Clone)]
pub struct EqOp;

impl LintPass for EqOp {
    fn get_lints(&self) -> LintArray {
        lint_array!(EQ_OP, OP_REF)
    }
}

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for EqOp {
    fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) {
        if let ExprBinary(ref op, ref left, ref right) = e.node {
            if !in_macro(e.span) && is_valid_operator(op) && SpanlessEq::new(cx).ignore_fn().eq_expr(left, right) {
                span_lint(
                    cx,
                    EQ_OP,
                    e.span,
                    &format!("equal expressions as operands to `{}`", op.node.as_str()),
                );
                return;
            }
            let (trait_id, requires_ref) = match op.node {
                BiAdd => (cx.tcx.lang_items().add_trait(), false),
                BiSub => (cx.tcx.lang_items().sub_trait(), false),
                BiMul => (cx.tcx.lang_items().mul_trait(), false),
                BiDiv => (cx.tcx.lang_items().div_trait(), false),
                BiRem => (cx.tcx.lang_items().rem_trait(), false),
                // don't lint short circuiting ops
                BiAnd | BiOr => return,
                BiBitXor => (cx.tcx.lang_items().bitxor_trait(), false),
                BiBitAnd => (cx.tcx.lang_items().bitand_trait(), false),
                BiBitOr => (cx.tcx.lang_items().bitor_trait(), false),
                BiShl => (cx.tcx.lang_items().shl_trait(), false),
                BiShr => (cx.tcx.lang_items().shr_trait(), false),
                BiNe | BiEq => (cx.tcx.lang_items().eq_trait(), true),
                BiLt | BiLe | BiGe | BiGt => (cx.tcx.lang_items().ord_trait(), true),
            };
            if let Some(trait_id) = trait_id {
                #[allow(match_same_arms)]
                match (&left.node, &right.node) {
                    // do not suggest to dereference literals
                    (&ExprLit(..), _) | (_, &ExprLit(..)) => {},
                    // &foo == &bar
                    (&ExprAddrOf(_, ref l), &ExprAddrOf(_, ref r)) => {
                        let lty = cx.tables.expr_ty(l);
                        let rty = cx.tables.expr_ty(r);
                        let lcpy = is_copy(cx, lty);
                        let rcpy = is_copy(cx, rty);
                        // either operator autorefs or both args are copyable
                        if (requires_ref || (lcpy && rcpy)) && implements_trait(cx, lty, trait_id, &[rty]) {
                            span_lint_and_then(
                                cx,
                                OP_REF,
                                e.span,
                                "needlessly taken reference of both operands",
                                |db| {
                                    let lsnip = snippet(cx, l.span, "...").to_string();
                                    let rsnip = snippet(cx, r.span, "...").to_string();
                                    multispan_sugg(
                                        db,
                                        "use the values directly".to_string(),
                                        vec![(left.span, lsnip), (right.span, rsnip)],
                                    );
                                },
                            )
                        } else if lcpy && !rcpy && implements_trait(cx, lty, trait_id, &[cx.tables.expr_ty(right)]) {
                            span_lint_and_then(cx, OP_REF, e.span, "needlessly taken reference of left operand", |db| {
                                let lsnip = snippet(cx, l.span, "...").to_string();
                                db.span_suggestion(left.span, "use the left value directly", lsnip);
                            })
                        } else if !lcpy && rcpy && implements_trait(cx, cx.tables.expr_ty(left), trait_id, &[rty]) {
                            span_lint_and_then(
                                cx,
                                OP_REF,
                                e.span,
                                "needlessly taken reference of right operand",
                                |db| {
                                    let rsnip = snippet(cx, r.span, "...").to_string();
                                    db.span_suggestion(right.span, "use the right value directly", rsnip);
                                },
                            )
                        }
                    },
                    // &foo == bar
                    (&ExprAddrOf(_, ref l), _) => {
                        let lty = cx.tables.expr_ty(l);
                        let lcpy = is_copy(cx, lty);
                        if (requires_ref || lcpy) && implements_trait(cx, lty, trait_id, &[cx.tables.expr_ty(right)]) {
                            span_lint_and_then(cx, OP_REF, e.span, "needlessly taken reference of left operand", |db| {
                                let lsnip = snippet(cx, l.span, "...").to_string();
                                db.span_suggestion(left.span, "use the left value directly", lsnip);
                            })
                        }
                    },
                    // foo == &bar
                    (_, &ExprAddrOf(_, ref r)) => {
                        let rty = cx.tables.expr_ty(r);
                        let rcpy = is_copy(cx, rty);
                        if (requires_ref || rcpy) && implements_trait(cx, cx.tables.expr_ty(left), trait_id, &[rty]) {
                            span_lint_and_then(cx, OP_REF, e.span, "taken reference of right operand", |db| {
                                let rsnip = snippet(cx, r.span, "...").to_string();
                                db.span_suggestion(right.span, "use the right value directly", rsnip);
                            })
                        }
                    },
                    _ => {},
                }
            }
        }
    }
}

fn is_valid_operator(op: &BinOp) -> bool {
    match op.node {
        BiSub | BiDiv | BiEq | BiLt | BiLe | BiGt | BiGe | BiNe | BiAnd | BiOr | BiBitXor | BiBitAnd | BiBitOr => true,
        _ => false,
    }
}
<commit_msg>Move in_macro check to end of expression since usual case is not inside macro<commit_after>use rustc::hir::*;
use rustc::lint::*;
use utils::{in_macro, implements_trait, is_copy, multispan_sugg, snippet, span_lint, span_lint_and_then, SpanlessEq};

/// **What it does:** Checks for equal operands to comparison, logical and
/// bitwise, difference and division binary operators (`==`, `>`, etc., `&&`,
/// `||`, `&`, `|`, `^`, `-` and `/`).
///
/// **Why is this bad?** This is usually just a typo or a copy and paste error.
///
/// **Known problems:** False negatives: We had some false positives regarding
/// calls (notably [racer](https://github.com/phildawes/racer) had one instance
/// of `x.pop() && x.pop()`), so we removed matching any function or method
/// calls. We may introduce a whitelist of known pure functions in the future.
///
/// **Example:**
/// ```rust
/// x + 1 == x + 1
/// ```
declare_lint! {
    pub EQ_OP,
    Warn,
    "equal operands on both sides of a comparison or bitwise combination (e.g. `x == x`)"
}

/// **What it does:** Checks for arguments to `==` which have their address
/// taken to satisfy a bound
/// and suggests to dereference the other argument instead
///
/// **Why is this bad?** It is more idiomatic to dereference the other argument.
///
/// **Known problems:** None
///
/// **Example:**
/// ```rust
/// &x == y
/// ```
declare_lint! {
    pub OP_REF,
    Warn,
    "taking a reference to satisfy the type constraints on `==`"
}

#[derive(Copy, Clone)]
pub struct EqOp;

impl LintPass for EqOp {
    fn get_lints(&self) -> LintArray {
        lint_array!(EQ_OP, OP_REF)
    }
}

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for EqOp {
    fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) {
        if let ExprBinary(ref op, ref left, ref right) = e.node {
            if is_valid_operator(op) && SpanlessEq::new(cx).ignore_fn().eq_expr(left, right) && !in_macro(e.span) {
                span_lint(
                    cx,
                    EQ_OP,
                    e.span,
                    &format!("equal expressions as operands to `{}`", op.node.as_str()),
                );
                return;
            }
            let (trait_id, requires_ref) = match op.node {
                BiAdd => (cx.tcx.lang_items().add_trait(), false),
                BiSub => (cx.tcx.lang_items().sub_trait(), false),
                BiMul => (cx.tcx.lang_items().mul_trait(), false),
                BiDiv => (cx.tcx.lang_items().div_trait(), false),
                BiRem => (cx.tcx.lang_items().rem_trait(), false),
                // don't lint short circuiting ops
                BiAnd | BiOr => return,
                BiBitXor => (cx.tcx.lang_items().bitxor_trait(), false),
                BiBitAnd => (cx.tcx.lang_items().bitand_trait(), false),
                BiBitOr => (cx.tcx.lang_items().bitor_trait(), false),
                BiShl => (cx.tcx.lang_items().shl_trait(), false),
                BiShr => (cx.tcx.lang_items().shr_trait(), false),
                BiNe | BiEq => (cx.tcx.lang_items().eq_trait(), true),
                BiLt | BiLe | BiGe | BiGt => (cx.tcx.lang_items().ord_trait(), true),
            };
            if let Some(trait_id) = trait_id {
                #[allow(match_same_arms)]
                match (&left.node, &right.node) {
                    // do not suggest to dereference literals
                    (&ExprLit(..), _) | (_, &ExprLit(..)) => {},
                    // &foo == &bar
                    (&ExprAddrOf(_, ref l), &ExprAddrOf(_, ref r)) => {
                        let lty = cx.tables.expr_ty(l);
                        let rty = cx.tables.expr_ty(r);
                        let lcpy = is_copy(cx, lty);
                        let rcpy = is_copy(cx, rty);
                        // either operator autorefs or both args are copyable
                        if (requires_ref || (lcpy && rcpy)) && implements_trait(cx, lty, trait_id, &[rty]) {
                            span_lint_and_then(
                                cx,
                                OP_REF,
                                e.span,
                                "needlessly taken reference of both operands",
                                |db| {
                                    let lsnip = snippet(cx, l.span, "...").to_string();
                                    let rsnip = snippet(cx, r.span, "...").to_string();
                                    multispan_sugg(
                                        db,
                                        "use the values directly".to_string(),
                                        vec![(left.span, lsnip), (right.span, rsnip)],
                                    );
                                },
                            )
                        } else if lcpy && !rcpy && implements_trait(cx, lty, trait_id, &[cx.tables.expr_ty(right)]) {
                            span_lint_and_then(cx, OP_REF, e.span, "needlessly taken reference of left operand", |db| {
                                let lsnip = snippet(cx, l.span, "...").to_string();
                                db.span_suggestion(left.span, "use the left value directly", lsnip);
                            })
                        } else if !lcpy && rcpy && implements_trait(cx, cx.tables.expr_ty(left), trait_id, &[rty]) {
                            span_lint_and_then(
                                cx,
                                OP_REF,
                                e.span,
                                "needlessly taken reference of right operand",
                                |db| {
                                    let rsnip = snippet(cx, r.span, "...").to_string();
                                    db.span_suggestion(right.span, "use the right value directly", rsnip);
                                },
                            )
                        }
                    },
                    // &foo == bar
                    (&ExprAddrOf(_, ref l), _) => {
                        let lty = cx.tables.expr_ty(l);
                        let lcpy = is_copy(cx, lty);
                        if (requires_ref || lcpy) && implements_trait(cx, lty, trait_id, &[cx.tables.expr_ty(right)]) {
                            span_lint_and_then(cx, OP_REF, e.span, "needlessly taken reference of left operand", |db| {
                                let lsnip = snippet(cx, l.span, "...").to_string();
                                db.span_suggestion(left.span, "use the left value directly", lsnip);
                            })
                        }
                    },
                    // foo == &bar
                    (_, &ExprAddrOf(_, ref r)) => {
                        let rty = cx.tables.expr_ty(r);
                        let rcpy = is_copy(cx, rty);
                        if (requires_ref || rcpy) && implements_trait(cx, cx.tables.expr_ty(left), trait_id, &[rty]) {
                            span_lint_and_then(cx, OP_REF, e.span, "taken reference of right operand", |db| {
                                let rsnip = snippet(cx, r.span, "...").to_string();
                                db.span_suggestion(right.span, "use the right value directly", rsnip);
                            })
                        }
                    },
                    _ => {},
                }
            }
        }
    }
}

fn is_valid_operator(op: &BinOp) -> bool {
    match op.node {
        BiSub | BiDiv | BiEq | BiLt | BiLe | BiGt | BiGe | BiNe | BiAnd | BiOr | BiBitXor | BiBitAnd | BiBitOr => true,
        _ => false,
    }
}
<|endoftext|>


<commit_before><commit_msg>Rust: eushully nocd accepts config file with patches<commit_after><|endoftext|>


<commit_before>// run-pass
#![allow(unused_assignments)]
#![allow(unused_variables)]

// ignore-wasm32-bare compiled with panic=abort by default

#![feature(generators, generator_trait, untagged_unions)]
#![feature(slice_patterns)]

use std::cell::{Cell, RefCell};
use std::ops::Generator;
use std::panic;
use std::pin::Pin;
use std::usize;

struct InjectedFailure;

struct Allocator {
    data: RefCell<Vec<bool>>,
    failing_op: usize,
    cur_ops: Cell<usize>,
}

impl panic::UnwindSafe for Allocator {}
impl panic::RefUnwindSafe for Allocator {}

impl Drop for Allocator {
    fn drop(&mut self) {
        let data = self.data.borrow();
        if data.iter().any(|d| *d) {
            panic!("missing free: {:?}", data);
        }
    }
}

impl Allocator {
    fn new(failing_op: usize) -> Self {
        Allocator {
            failing_op: failing_op,
            cur_ops: Cell::new(0),
            data: RefCell::new(vec![])
        }
    }
    fn alloc(&self) -> Ptr {
        self.cur_ops.set(self.cur_ops.get() + 1);

        if self.cur_ops.get() == self.failing_op {
            panic!(InjectedFailure);
        }

        let mut data = self.data.borrow_mut();
        let addr = data.len();
        data.push(true);
        Ptr(addr, self)
    }
}

struct Ptr<'a>(usize, &'a Allocator);
impl<'a> Drop for Ptr<'a> {
    fn drop(&mut self) {
        match self.1.data.borrow_mut()[self.0] {
            false => {
                panic!("double free at index {:?}", self.0)
            }
            ref mut d => *d = false
        }

        self.1.cur_ops.set(self.1.cur_ops.get()+1);

        if self.1.cur_ops.get() == self.1.failing_op {
            panic!(InjectedFailure);
        }
    }
}

fn dynamic_init(a: &Allocator, c: bool) {
    let _x;
    if c {
        _x = Some(a.alloc());
    }
}

fn dynamic_drop(a: &Allocator, c: bool) {
    let x = a.alloc();
    if c {
        Some(x)
    } else {
        None
    };
}

struct TwoPtrs<'a>(Ptr<'a>, Ptr<'a>);
fn struct_dynamic_drop(a: &Allocator, c0: bool, c1: bool, c: bool) {
    for i in 0..2 {
        let x;
        let y;
        if (c0 && i == 0) || (c1 && i == 1) {
            x = (a.alloc(), a.alloc(), a.alloc());
            y = TwoPtrs(a.alloc(), a.alloc());
            if c {
                drop(x.1);
                drop(y.0);
            }
        }
    }
}

fn field_assignment(a: &Allocator, c0: bool) {
    let mut x = (TwoPtrs(a.alloc(), a.alloc()), a.alloc());

    x.1 = a.alloc();
    x.1 = a.alloc();

    let f = (x.0).0;
    if c0 {
        (x.0).0 = f;
    }
}

fn assignment2(a: &Allocator, c0: bool, c1: bool) {
    let mut _v = a.alloc();
    let mut _w = a.alloc();
    if c0 {
        drop(_v);
    }
    _v = _w;
    if c1 {
        _w = a.alloc();
    }
}

fn assignment1(a: &Allocator, c0: bool) {
    let mut _v = a.alloc();
    let mut _w = a.alloc();
    if c0 {
        drop(_v);
    }
    _v = _w;
}

#[allow(unions_with_drop_fields)]
union Boxy<T> {
    a: T,
    b: T,
}

fn union1(a: &Allocator) {
    unsafe {
        let mut u = Boxy { a: a.alloc() };
        u.b = a.alloc();
        drop(u.a);
    }
}

fn array_simple(a: &Allocator) {
    let _x = [a.alloc(), a.alloc(), a.alloc(), a.alloc()];
}

fn vec_simple(a: &Allocator) {
    let _x = vec![a.alloc(), a.alloc(), a.alloc(), a.alloc()];
}

fn generator(a: &Allocator, run_count: usize) {
    assert!(run_count < 4);

    let mut gen = || {
        (a.alloc(),
         yield a.alloc(),
         a.alloc(),
         yield a.alloc()
         );
    };
    for _ in 0..run_count {
        Pin::new(&mut gen).resume();
    }
}

fn mixed_drop_and_nondrop(a: &Allocator) {
    // check that destructor panics handle drop
    // and non-drop blocks in the same scope correctly.
    //
    // Surprisingly enough, this used to not work.
    let (x, y, z);
    x = a.alloc();
    y = 5;
    z = a.alloc();
}

#[allow(unreachable_code)]
fn vec_unreachable(a: &Allocator) {
    let _x = vec![a.alloc(), a.alloc(), a.alloc(), return];
}

fn slice_pattern_first(a: &Allocator) {
    let[_x, ..] = [a.alloc(), a.alloc(), a.alloc()];
}

fn slice_pattern_middle(a: &Allocator) {
    let[_, _x, _] = [a.alloc(), a.alloc(), a.alloc()];
}

fn slice_pattern_two(a: &Allocator) {
    let[_x, _, _y, _] = [a.alloc(), a.alloc(), a.alloc(), a.alloc()];
}

fn slice_pattern_last(a: &Allocator) {
    let[.., _y] = [a.alloc(), a.alloc(), a.alloc(), a.alloc()];
}

fn slice_pattern_one_of(a: &Allocator, i: usize) {
    let array = [a.alloc(), a.alloc(), a.alloc(), a.alloc()];
    let _x = match i {
        0 => { let [a, ..] = array; a }
        1 => { let [_, a, ..] = array; a }
        2 => { let [_, _, a, _] = array; a }
        3 => { let [_, _, _, a] = array; a }
        _ => panic!("unmatched"),
    };
}

fn subslice_pattern_from_end(a: &Allocator, arg: bool) {
    let a = [a.alloc(), a.alloc(), a.alloc()];
    if arg {
        let[.., _x, _] = a;
    } else {
        let[_, _y..] = a;
    }
}

fn subslice_pattern_from_end_with_drop(a: &Allocator, arg: bool, arg2: bool) {
    let a = [a.alloc(), a.alloc(), a.alloc(), a.alloc(), a.alloc()];
    if arg2 {
        drop(a);
        return;
    }

    if arg {
        let[.., _x, _] = a;
    } else {
        let[_, _y..] = a;
    }
}

fn slice_pattern_reassign(a: &Allocator) {
    let mut ar = [a.alloc(), a.alloc()];
    let[_, _x] = ar;
    ar = [a.alloc(), a.alloc()];
    let[.., _y] = ar;
}

fn subslice_pattern_reassign(a: &Allocator) {
    let mut ar = [a.alloc(), a.alloc(), a.alloc()];
    let[_, _, _x] = ar;
    ar = [a.alloc(), a.alloc(), a.alloc()];
    let[_, _y..] = ar;
}

fn run_test<F>(mut f: F)
    where F: FnMut(&Allocator)
{
    let first_alloc = Allocator::new(usize::MAX);
    f(&first_alloc);

    for failing_op in 1..first_alloc.cur_ops.get()+1 {
        let alloc = Allocator::new(failing_op);
        let alloc = &alloc;
        let f = panic::AssertUnwindSafe(&mut f);
        let result = panic::catch_unwind(move || {
            f.0(alloc);
        });
        match result {
            Ok(..) => panic!("test executed {} ops but now {}",
                             first_alloc.cur_ops.get(), alloc.cur_ops.get()),
            Err(e) => {
                if e.downcast_ref::<InjectedFailure>().is_none() {
                    panic::resume_unwind(e);
                }
            }
        }
    }
}

fn run_test_nopanic<F>(mut f: F)
    where F: FnMut(&Allocator)
{
    let first_alloc = Allocator::new(usize::MAX);
    f(&first_alloc);
}

fn main() {
    run_test(|a| dynamic_init(a, false));
    run_test(|a| dynamic_init(a, true));
    run_test(|a| dynamic_drop(a, false));
    run_test(|a| dynamic_drop(a, true));

    run_test(|a| assignment2(a, false, false));
    run_test(|a| assignment2(a, false, true));
    run_test(|a| assignment2(a, true, false));
    run_test(|a| assignment2(a, true, true));

    run_test(|a| assignment1(a, false));
    run_test(|a| assignment1(a, true));

    run_test(|a| array_simple(a));
    run_test(|a| vec_simple(a));
    run_test(|a| vec_unreachable(a));

    run_test(|a| struct_dynamic_drop(a, false, false, false));
    run_test(|a| struct_dynamic_drop(a, false, false, true));
    run_test(|a| struct_dynamic_drop(a, false, true, false));
    run_test(|a| struct_dynamic_drop(a, false, true, true));
    run_test(|a| struct_dynamic_drop(a, true, false, false));
    run_test(|a| struct_dynamic_drop(a, true, false, true));
    run_test(|a| struct_dynamic_drop(a, true, true, false));
    run_test(|a| struct_dynamic_drop(a, true, true, true));

    run_test(|a| field_assignment(a, false));
    run_test(|a| field_assignment(a, true));

    run_test(|a| generator(a, 0));
    run_test(|a| generator(a, 1));
    run_test(|a| generator(a, 2));
    run_test(|a| generator(a, 3));

    run_test(|a| mixed_drop_and_nondrop(a));

    run_test(|a| slice_pattern_first(a));
    run_test(|a| slice_pattern_middle(a));
    run_test(|a| slice_pattern_two(a));
    run_test(|a| slice_pattern_last(a));
    run_test(|a| slice_pattern_one_of(a, 0));
    run_test(|a| slice_pattern_one_of(a, 1));
    run_test(|a| slice_pattern_one_of(a, 2));
    run_test(|a| slice_pattern_one_of(a, 3));

    run_test(|a| subslice_pattern_from_end(a, true));
    run_test(|a| subslice_pattern_from_end(a, false));
    run_test(|a| subslice_pattern_from_end_with_drop(a, true, true));
    run_test(|a| subslice_pattern_from_end_with_drop(a, true, false));
    run_test(|a| subslice_pattern_from_end_with_drop(a, false, true));
    run_test(|a| subslice_pattern_from_end_with_drop(a, false, false));
    run_test(|a| slice_pattern_reassign(a));
    run_test(|a| subslice_pattern_reassign(a));

    run_test_nopanic(|a| union1(a));
}
<commit_msg>Expand dynamic drop tests for cases in #47949<commit_after>// run-pass
#![allow(unused_assignments)]
#![allow(unused_variables)]

// ignore-wasm32-bare compiled with panic=abort by default

#![feature(generators, generator_trait, untagged_unions)]
#![feature(slice_patterns)]

use std::cell::{Cell, RefCell};
use std::ops::Generator;
use std::panic;
use std::pin::Pin;
use std::usize;

struct InjectedFailure;

struct Allocator {
    data: RefCell<Vec<bool>>,
    failing_op: usize,
    cur_ops: Cell<usize>,
}

impl panic::UnwindSafe for Allocator {}
impl panic::RefUnwindSafe for Allocator {}

impl Drop for Allocator {
    fn drop(&mut self) {
        let data = self.data.borrow();
        if data.iter().any(|d| *d) {
            panic!("missing free: {:?}", data);
        }
    }
}

impl Allocator {
    fn new(failing_op: usize) -> Self {
        Allocator {
            failing_op: failing_op,
            cur_ops: Cell::new(0),
            data: RefCell::new(vec![])
        }
    }
    fn alloc(&self) -> Ptr<'_> {
        self.cur_ops.set(self.cur_ops.get() + 1);

        if self.cur_ops.get() == self.failing_op {
            panic!(InjectedFailure);
        }

        let mut data = self.data.borrow_mut();
        let addr = data.len();
        data.push(true);
        Ptr(addr, self)
    }
    // FIXME(#47949) Any use of this indicates a bug in rustc: we should never
    // be leaking values in the cases here.
    //
    // Creates a `Ptr<'_>` and checks that the allocated value is leaked if the
    // `failing_op` is in the list of exception.
    fn alloc_leaked(&self, exceptions: Vec<usize>) -> Ptr<'_> {
        let ptr = self.alloc();

        if exceptions.iter().any(|operation| *operation == self.failing_op) {
            let mut data = self.data.borrow_mut();
            data[ptr.0] = false;
        }
        ptr
    }
}

struct Ptr<'a>(usize, &'a Allocator);
impl<'a> Drop for Ptr<'a> {
    fn drop(&mut self) {
        match self.1.data.borrow_mut()[self.0] {
            false => {
                panic!("double free at index {:?}", self.0)
            }
            ref mut d => *d = false
        }

        self.1.cur_ops.set(self.1.cur_ops.get()+1);

        if self.1.cur_ops.get() == self.1.failing_op {
            panic!(InjectedFailure);
        }
    }
}

fn dynamic_init(a: &Allocator, c: bool) {
    let _x;
    if c {
        _x = Some(a.alloc());
    }
}

fn dynamic_drop(a: &Allocator, c: bool) {
    let x = a.alloc();
    if c {
        Some(x)
    } else {
        None
    };
}

struct TwoPtrs<'a>(Ptr<'a>, Ptr<'a>);
fn struct_dynamic_drop(a: &Allocator, c0: bool, c1: bool, c: bool) {
    for i in 0..2 {
        let x;
        let y;
        if (c0 && i == 0) || (c1 && i == 1) {
            x = (a.alloc(), a.alloc(), a.alloc());
            y = TwoPtrs(a.alloc(), a.alloc());
            if c {
                drop(x.1);
                drop(y.0);
            }
        }
    }
}

fn field_assignment(a: &Allocator, c0: bool) {
    let mut x = (TwoPtrs(a.alloc(), a.alloc()), a.alloc());

    x.1 = a.alloc();
    x.1 = a.alloc();

    let f = (x.0).0;
    if c0 {
        (x.0).0 = f;
    }
}

fn assignment2(a: &Allocator, c0: bool, c1: bool) {
    let mut _v = a.alloc();
    let mut _w = a.alloc();
    if c0 {
        drop(_v);
    }
    _v = _w;
    if c1 {
        _w = a.alloc();
    }
}

fn assignment1(a: &Allocator, c0: bool) {
    let mut _v = a.alloc();
    let mut _w = a.alloc();
    if c0 {
        drop(_v);
    }
    _v = _w;
}

#[allow(unions_with_drop_fields)]
union Boxy<T> {
    a: T,
    b: T,
}

fn union1(a: &Allocator) {
    unsafe {
        let mut u = Boxy { a: a.alloc() };
        u.b = a.alloc();
        drop(u.a);
    }
}

fn array_simple(a: &Allocator) {
    let _x = [a.alloc(), a.alloc(), a.alloc(), a.alloc()];
}

fn vec_simple(a: &Allocator) {
    let _x = vec![a.alloc(), a.alloc(), a.alloc(), a.alloc()];
}

fn generator(a: &Allocator, run_count: usize) {
    assert!(run_count < 4);

    let mut gen = || {
        (a.alloc(),
         yield a.alloc(),
         a.alloc(),
         yield a.alloc()
         );
    };
    for _ in 0..run_count {
        Pin::new(&mut gen).resume();
    }
}

fn mixed_drop_and_nondrop(a: &Allocator) {
    // check that destructor panics handle drop
    // and non-drop blocks in the same scope correctly.
    //
    // Surprisingly enough, this used to not work.
    let (x, y, z);
    x = a.alloc();
    y = 5;
    z = a.alloc();
}

#[allow(unreachable_code)]
fn vec_unreachable(a: &Allocator) {
    let _x = vec![a.alloc(), a.alloc(), a.alloc(), return];
}

fn slice_pattern_first(a: &Allocator) {
    let[_x, ..] = [a.alloc(), a.alloc(), a.alloc()];
}

fn slice_pattern_middle(a: &Allocator) {
    let[_, _x, _] = [a.alloc(), a.alloc(), a.alloc()];
}

fn slice_pattern_two(a: &Allocator) {
    let[_x, _, _y, _] = [a.alloc(), a.alloc(), a.alloc(), a.alloc()];
}

fn slice_pattern_last(a: &Allocator) {
    let[.., _y] = [a.alloc(), a.alloc(), a.alloc(), a.alloc()];
}

fn slice_pattern_one_of(a: &Allocator, i: usize) {
    let array = [a.alloc(), a.alloc(), a.alloc(), a.alloc()];
    let _x = match i {
        0 => { let [a, ..] = array; a }
        1 => { let [_, a, ..] = array; a }
        2 => { let [_, _, a, _] = array; a }
        3 => { let [_, _, _, a] = array; a }
        _ => panic!("unmatched"),
    };
}

fn subslice_pattern_from_end(a: &Allocator, arg: bool) {
    let a = [a.alloc(), a.alloc(), a.alloc()];
    if arg {
        let[.., _x, _] = a;
    } else {
        let[_, _y..] = a;
    }
}

fn subslice_pattern_from_end_with_drop(a: &Allocator, arg: bool, arg2: bool) {
    let a = [a.alloc(), a.alloc(), a.alloc(), a.alloc(), a.alloc()];
    if arg2 {
        drop(a);
        return;
    }

    if arg {
        let[.., _x, _] = a;
    } else {
        let[_, _y..] = a;
    }
}

fn slice_pattern_reassign(a: &Allocator) {
    let mut ar = [a.alloc(), a.alloc()];
    let[_, _x] = ar;
    ar = [a.alloc(), a.alloc()];
    let[.., _y] = ar;
}

fn subslice_pattern_reassign(a: &Allocator) {
    let mut ar = [a.alloc(), a.alloc(), a.alloc()];
    let[_, _, _x] = ar;
    ar = [a.alloc(), a.alloc(), a.alloc()];
    let[_, _y..] = ar;
}

fn panic_after_return(a: &Allocator) -> Ptr<'_> {
    // Panic in the drop of `p` or `q` can leak
    let exceptions = vec![8, 9];
    a.alloc();
    let p = a.alloc();
    {
        a.alloc();
        let p = a.alloc();
        // FIXME (#47949) We leak values when we panic in a destructor after
        // evaluating an expression with `rustc_mir::build::Builder::into`.
        a.alloc_leaked(exceptions)
    }
}

fn panic_after_return_expr(a: &Allocator) -> Ptr<'_> {
    // Panic in the drop of `p` or `q` can leak
    let exceptions = vec![8, 9];
    a.alloc();
    let p = a.alloc();
    {
        a.alloc();
        let q = a.alloc();
        // FIXME (#47949)
        return a.alloc_leaked(exceptions);
    }
}

fn panic_after_init(a: &Allocator) {
    // Panic in the drop of `r` can leak
    let exceptions = vec![8];
    a.alloc();
    let p = a.alloc();
    let q = {
        a.alloc();
        let r = a.alloc();
        // FIXME (#47949)
        a.alloc_leaked(exceptions)
    };
}

fn panic_after_init_temp(a: &Allocator) {
    // Panic in the drop of `r` can leak
    let exceptions = vec![8];
    a.alloc();
    let p = a.alloc();
    {
        a.alloc();
        let r = a.alloc();
        // FIXME (#47949)
        a.alloc_leaked(exceptions)
    };
}

fn panic_after_init_by_loop(a: &Allocator) {
    // Panic in the drop of `r` can leak
    let exceptions = vec![8];
    a.alloc();
    let p = a.alloc();
    let q = loop {
        a.alloc();
        let r = a.alloc();
        // FIXME (#47949)
        break a.alloc_leaked(exceptions);
    };
}

fn run_test<F>(mut f: F)
    where F: FnMut(&Allocator)
{
    let first_alloc = Allocator::new(usize::MAX);
    f(&first_alloc);

    for failing_op in 1..first_alloc.cur_ops.get()+1 {
        let alloc = Allocator::new(failing_op);
        let alloc = &alloc;
        let f = panic::AssertUnwindSafe(&mut f);
        let result = panic::catch_unwind(move || {
            f.0(alloc);
        });
        match result {
            Ok(..) => panic!("test executed {} ops but now {}",
                             first_alloc.cur_ops.get(), alloc.cur_ops.get()),
            Err(e) => {
                if e.downcast_ref::<InjectedFailure>().is_none() {
                    panic::resume_unwind(e);
                }
            }
        }
    }
}

fn run_test_nopanic<F>(mut f: F)
    where F: FnMut(&Allocator)
{
    let first_alloc = Allocator::new(usize::MAX);
    f(&first_alloc);
}

fn main() {
    run_test(|a| dynamic_init(a, false));
    run_test(|a| dynamic_init(a, true));
    run_test(|a| dynamic_drop(a, false));
    run_test(|a| dynamic_drop(a, true));

    run_test(|a| assignment2(a, false, false));
    run_test(|a| assignment2(a, false, true));
    run_test(|a| assignment2(a, true, false));
    run_test(|a| assignment2(a, true, true));

    run_test(|a| assignment1(a, false));
    run_test(|a| assignment1(a, true));

    run_test(|a| array_simple(a));
    run_test(|a| vec_simple(a));
    run_test(|a| vec_unreachable(a));

    run_test(|a| struct_dynamic_drop(a, false, false, false));
    run_test(|a| struct_dynamic_drop(a, false, false, true));
    run_test(|a| struct_dynamic_drop(a, false, true, false));
    run_test(|a| struct_dynamic_drop(a, false, true, true));
    run_test(|a| struct_dynamic_drop(a, true, false, false));
    run_test(|a| struct_dynamic_drop(a, true, false, true));
    run_test(|a| struct_dynamic_drop(a, true, true, false));
    run_test(|a| struct_dynamic_drop(a, true, true, true));

    run_test(|a| field_assignment(a, false));
    run_test(|a| field_assignment(a, true));

    run_test(|a| generator(a, 0));
    run_test(|a| generator(a, 1));
    run_test(|a| generator(a, 2));
    run_test(|a| generator(a, 3));

    run_test(|a| mixed_drop_and_nondrop(a));

    run_test(|a| slice_pattern_first(a));
    run_test(|a| slice_pattern_middle(a));
    run_test(|a| slice_pattern_two(a));
    run_test(|a| slice_pattern_last(a));
    run_test(|a| slice_pattern_one_of(a, 0));
    run_test(|a| slice_pattern_one_of(a, 1));
    run_test(|a| slice_pattern_one_of(a, 2));
    run_test(|a| slice_pattern_one_of(a, 3));

    run_test(|a| subslice_pattern_from_end(a, true));
    run_test(|a| subslice_pattern_from_end(a, false));
    run_test(|a| subslice_pattern_from_end_with_drop(a, true, true));
    run_test(|a| subslice_pattern_from_end_with_drop(a, true, false));
    run_test(|a| subslice_pattern_from_end_with_drop(a, false, true));
    run_test(|a| subslice_pattern_from_end_with_drop(a, false, false));
    run_test(|a| slice_pattern_reassign(a));
    run_test(|a| subslice_pattern_reassign(a));

    run_test(|a| {
        panic_after_return(a);
    });
    run_test(|a| {
        panic_after_return_expr(a);
    });
    run_test(|a| panic_after_init(a));
    run_test(|a| panic_after_init_temp(a));
    run_test(|a| panic_after_init_by_loop(a));

    run_test_nopanic(|a| union1(a));
}
<|endoftext|>


<commit_before>// Copyright 2017 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![allow(warnings)]
#![feature(in_band_lifetimes, universal_impl_trait)]

fn foo(x: &'x u8) -> &'x u8 { x }
fn foo2(x: &'a u8, y: &u8) -> &'a u8 { x }

fn check_in_band_can_be_late_bound() {
    let _: for<'x> fn(&'x u8, &u8) -> &'x u8 = foo2;
}

struct ForInherentNoParams;

impl ForInherentNoParams {
    fn foo(x: &'a u32, y: &u32) -> &'a u32 { x }
}

struct X<'a>(&'a u8);

impl<'a> X<'a> {
    fn inner(&self) -> &'a u8 {
        self.0
    }

    fn same_lifetime_as_parameter(&mut self, x: &'a u8) {
        self.0 = x;
    }
}

impl X<'b> {
    fn inner_2(&self) -> &'b u8 {
        self.0
    }

    fn reference_already_introduced_in_band_from_method_with_explicit_binders<'a>(
        &'b self, x: &'a u32
    ) {}
}

struct Y<T>(T);

impl Y<&'a u8> {
    fn inner(&self) -> &'a u8 {
        self.0
    }
}

trait MyTrait<'a> {
    fn my_lifetime(&self) -> &'a u8;
    fn any_lifetime() -> &'b u8;
    fn borrowed_lifetime(&'b self) -> &'b u8;
    fn default_impl(&self, x: &'b u32, y: &u32) -> &'b u32 { x }
    fn in_band_def_explicit_impl(&self, x: &'b u8);
}

impl MyTrait<'a> for Y<&'a u8> {
    fn my_lifetime(&self) -> &'a u8 { self.0 }
    fn any_lifetime() -> &'b u8 { &0 }
    fn borrowed_lifetime(&'b self) -> &'b u8 { &*self.0 }
    fn in_band_def_explicit_impl<'b>(&self, x: &'b u8) {}
}

fn test_hrtb_defined_lifetime_where<F>(_: F) where for<'a> F: Fn(&'a u8) {}
fn test_hrtb_defined_lifetime_polytraitref<F>(_: F) where F: for<'a> Fn(&'a u8) {}

fn reference_in_band_from_locals(x: &'test u32) -> &'test u32 {
    let y: &'test u32 = x;
    y
}

fn in_generics_in_band<T: MyTrait<'a>>(x: &T) {}
fn where_clause_in_band<T>(x: &T) where T: MyTrait<'a> {}
fn impl_trait_in_band(x: &impl MyTrait<'a>) {}

fn main() {}
<commit_msg>add some tests for the interaction with existential impl trait<commit_after>// Copyright 2017 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![allow(warnings)]
#![feature(in_band_lifetimes, universal_impl_trait, conservative_impl_trait)]

fn foo(x: &'x u8) -> &'x u8 { x }
fn foo2(x: &'a u8, y: &u8) -> &'a u8 { x }

fn check_in_band_can_be_late_bound() {
    let _: for<'x> fn(&'x u8, &u8) -> &'x u8 = foo2;
}

struct ForInherentNoParams;

impl ForInherentNoParams {
    fn foo(x: &'a u32, y: &u32) -> &'a u32 { x }
}

struct X<'a>(&'a u8);

impl<'a> X<'a> {
    fn inner(&self) -> &'a u8 {
        self.0
    }

    fn same_lifetime_as_parameter(&mut self, x: &'a u8) {
        self.0 = x;
    }
}

impl X<'b> {
    fn inner_2(&self) -> &'b u8 {
        self.0
    }

    fn reference_already_introduced_in_band_from_method_with_explicit_binders<'a>(
        &'b self, x: &'a u32
    ) {}
}

struct Y<T>(T);

impl Y<&'a u8> {
    fn inner(&self) -> &'a u8 {
        self.0
    }
}

trait MyTrait<'a> {
    fn my_lifetime(&self) -> &'a u8;
    fn any_lifetime() -> &'b u8;
    fn borrowed_lifetime(&'b self) -> &'b u8;
    fn default_impl(&self, x: &'b u32, y: &u32) -> &'b u32 { x }
    fn in_band_def_explicit_impl(&self, x: &'b u8);
}

impl MyTrait<'a> for Y<&'a u8> {
    fn my_lifetime(&self) -> &'a u8 { self.0 }
    fn any_lifetime() -> &'b u8 { &0 }
    fn borrowed_lifetime(&'b self) -> &'b u8 { &*self.0 }
    fn in_band_def_explicit_impl<'b>(&self, x: &'b u8) {}
}

fn test_hrtb_defined_lifetime_where<F>(_: F) where for<'a> F: Fn(&'a u8) {}
fn test_hrtb_defined_lifetime_polytraitref<F>(_: F) where F: for<'a> Fn(&'a u8) {}

fn reference_in_band_from_locals(x: &'test u32) -> &'test u32 {
    let y: &'test u32 = x;
    y
}

fn in_generics_in_band<T: MyTrait<'a>>(x: &T) {}
fn where_clause_in_band<T>(x: &T) where T: MyTrait<'a> {}
fn impl_trait_in_band(x: &impl MyTrait<'a>) {}

// Tests around using in-band lifetimes within existential traits.

trait FunkyTrait<'a> { }
impl<'a, T> FunkyTrait<'a> for T { }
fn existential_impl_trait_in_band_outlives(x: &'a u32) -> impl ::std::fmt::Debug + 'a {
    x
}
fn existential_impl_trait_in_band_param(x: &'a u32) -> impl FunkyTrait<'a> {
    x
}
fn existential_impl_trait_in_band_param_static(x: &'a u32) -> impl FunkyTrait<'static> + 'a {
    x
}
fn existential_impl_trait_in_band_param_outlives(x: &'a u32) -> impl FunkyTrait<'a> + 'a {
    x
}
fn existential_impl_trait_in_band_higher_ranked(x: &'a u32) -> impl for<'b> FunkyTrait<'b> + 'a {
    x
}

fn main() {}
<|endoftext|>