@@ -4671,7 +4671,7 @@ impl<'a> LoweringContext<'a> {
4671
4671
// The construct was introduced in #21984.
4672
4672
// FIXME(60253): Is this still necessary?
4673
4673
// Also, add the attributes to the outer returned expr node.
4674
- return self . expr_use ( head_sp, match_expr, e. attrs . clone ( ) )
4674
+ return self . expr_drop_temps ( head_sp, match_expr, e. attrs . clone ( ) )
4675
4675
}
4676
4676
4677
4677
// Desugar `ExprKind::Try`
@@ -5030,15 +5030,19 @@ impl<'a> LoweringContext<'a> {
5030
5030
)
5031
5031
}
5032
5032
5033
- /// Wrap the given `expr` in `hir::ExprKind::Use `.
5033
+ /// Wrap the given `expr` in a terminating scope using `hir::ExprKind::DropTemps `.
5034
5034
///
5035
- /// In terms of drop order, it has the same effect as
5036
- /// wrapping `expr` in `{ let _t = $expr; _t }` but
5037
- /// should provide better compile-time performance.
5035
+ /// In terms of drop order, it has the same effect as wrapping `expr` in
5036
+ /// `{ let _t = $expr; _t }` but should provide better compile-time performance.
5038
5037
///
5039
5038
/// The drop order can be important in e.g. `if expr { .. }`.
5040
- fn expr_use ( & mut self , span : Span , expr : P < hir:: Expr > , attrs : ThinVec < Attribute > ) -> hir:: Expr {
5041
- self . expr ( span, hir:: ExprKind :: Use ( expr) , attrs)
5039
+ fn expr_drop_temps (
5040
+ & mut self ,
5041
+ span : Span ,
5042
+ expr : P < hir:: Expr > ,
5043
+ attrs : ThinVec < Attribute >
5044
+ ) -> hir:: Expr {
5045
+ self . expr ( span, hir:: ExprKind :: DropTemps ( expr) , attrs)
5042
5046
}
5043
5047
5044
5048
fn expr_match (
@@ -5400,3 +5404,65 @@ fn body_ids(bodies: &BTreeMap<hir::BodyId, hir::Body>) -> Vec<hir::BodyId> {
5400
5404
body_ids. sort_by_key ( |b| bodies[ b] . value . span ) ;
5401
5405
body_ids
5402
5406
}
5407
+
5408
+ /// Checks if the specified expression is a built-in range literal.
5409
+ /// (See: `LoweringContext::lower_expr()`).
5410
+ pub fn is_range_literal ( sess : & Session , expr : & hir:: Expr ) -> bool {
5411
+ use hir:: { Path , QPath , ExprKind , TyKind } ;
5412
+
5413
+ // Returns whether the given path represents a (desugared) range,
5414
+ // either in std or core, i.e. has either a `::std::ops::Range` or
5415
+ // `::core::ops::Range` prefix.
5416
+ fn is_range_path ( path : & Path ) -> bool {
5417
+ let segs: Vec < _ > = path. segments . iter ( ) . map ( |seg| seg. ident . as_str ( ) . to_string ( ) ) . collect ( ) ;
5418
+ let segs: Vec < _ > = segs. iter ( ) . map ( |seg| & * * seg) . collect ( ) ;
5419
+
5420
+ // "{{root}}" is the equivalent of `::` prefix in `Path`.
5421
+ if let [ "{{root}}" , std_core, "ops" , range] = segs. as_slice ( ) {
5422
+ ( * std_core == "std" || * std_core == "core" ) && range. starts_with ( "Range" )
5423
+ } else {
5424
+ false
5425
+ }
5426
+ } ;
5427
+
5428
+ // Check whether a span corresponding to a range expression is a
5429
+ // range literal, rather than an explicit struct or `new()` call.
5430
+ fn is_lit ( sess : & Session , span : & Span ) -> bool {
5431
+ let source_map = sess. source_map ( ) ;
5432
+ let end_point = source_map. end_point ( * span) ;
5433
+
5434
+ if let Ok ( end_string) = source_map. span_to_snippet ( end_point) {
5435
+ !( end_string. ends_with ( "}" ) || end_string. ends_with ( ")" ) )
5436
+ } else {
5437
+ false
5438
+ }
5439
+ } ;
5440
+
5441
+ match expr. node {
5442
+ // All built-in range literals but `..=` and `..` desugar to `Struct`s.
5443
+ ExprKind :: Struct ( ref qpath, _, _) => {
5444
+ if let QPath :: Resolved ( None , ref path) = * * qpath {
5445
+ return is_range_path ( & path) && is_lit ( sess, & expr. span ) ;
5446
+ }
5447
+ }
5448
+
5449
+ // `..` desugars to its struct path.
5450
+ ExprKind :: Path ( QPath :: Resolved ( None , ref path) ) => {
5451
+ return is_range_path ( & path) && is_lit ( sess, & expr. span ) ;
5452
+ }
5453
+
5454
+ // `..=` desugars into `::std::ops::RangeInclusive::new(...)`.
5455
+ ExprKind :: Call ( ref func, _) => {
5456
+ if let ExprKind :: Path ( QPath :: TypeRelative ( ref ty, ref segment) ) = func. node {
5457
+ if let TyKind :: Path ( QPath :: Resolved ( None , ref path) ) = ty. node {
5458
+ let new_call = segment. ident . as_str ( ) == "new" ;
5459
+ return is_range_path ( & path) && is_lit ( sess, & expr. span ) && new_call;
5460
+ }
5461
+ }
5462
+ }
5463
+
5464
+ _ => { }
5465
+ }
5466
+
5467
+ false
5468
+ }
0 commit comments