@@ -1320,6 +1320,8 @@ impl<T: ?Sized> *const T {
1320
1320
/// }
1321
1321
/// # }
1322
1322
/// ```
1323
+ #[ must_use]
1324
+ #[ inline]
1323
1325
#[ stable( feature = "align_offset" , since = "1.36.0" ) ]
1324
1326
#[ rustc_const_unstable( feature = "const_align_offset" , issue = "90962" ) ]
1325
1327
pub const fn align_offset ( self , align : usize ) -> usize
@@ -1330,32 +1332,149 @@ impl<T: ?Sized> *const T {
1330
1332
panic ! ( "align_offset: align is not a power-of-two" ) ;
1331
1333
}
1332
1334
1333
- fn rt_impl < T > ( p : * const T , align : usize ) -> usize {
1334
- // SAFETY: `align` has been checked to be a power of 2 above
1335
- unsafe { align_offset ( p, align) }
1336
- }
1335
+ #[ cfg( bootstrap) ]
1336
+ {
1337
+ fn rt_impl < T > ( p : * const T , align : usize ) -> usize {
1338
+ // SAFETY: `align` has been checked to be a power of 2 above
1339
+ unsafe { align_offset ( p, align) }
1340
+ }
1341
+
1342
+ const fn ctfe_impl < T > ( _: * const T , _: usize ) -> usize {
1343
+ usize:: MAX
1344
+ }
1337
1345
1338
- const fn ctfe_impl < T > ( _: * const T , _: usize ) -> usize {
1339
- usize:: MAX
1346
+ // SAFETY:
1347
+ // It is permissible for `align_offset` to always return `usize::MAX`,
1348
+ // algorithm correctness can not depend on `align_offset` returning non-max values.
1349
+ //
1350
+ // As such the behaviour can't change after replacing `align_offset` with `usize::MAX`, only performance can.
1351
+ unsafe { intrinsics:: const_eval_select ( ( self , align) , ctfe_impl, rt_impl) }
1340
1352
}
1341
1353
1342
- // SAFETY:
1343
- // It is permissible for `align_offset` to always return `usize::MAX`,
1344
- // algorithm correctness can not depend on `align_offset` returning non-max values.
1345
- //
1346
- // As such the behaviour can't change after replacing `align_offset` with `usize::MAX`, only performance can.
1347
- unsafe { intrinsics:: const_eval_select ( ( self , align) , ctfe_impl, rt_impl) }
1354
+ #[ cfg( not( bootstrap) ) ]
1355
+ {
1356
+ // SAFETY: `align` has been checked to be a power of 2 above
1357
+ unsafe { align_offset ( self , align) }
1358
+ }
1348
1359
}
1349
1360
1350
1361
/// Returns whether the pointer is properly aligned for `T`.
1362
+ ///
1363
+ /// # Examples
1364
+ ///
1365
+ /// Basic usage:
1366
+ /// ```
1367
+ /// #![feature(pointer_is_aligned)]
1368
+ /// #![feature(pointer_byte_offsets)]
1369
+ ///
1370
+ /// // On some platforms, the alignment of i32 is less than 4.
1371
+ /// #[repr(align(4))]
1372
+ /// struct AlignedI32(i32);
1373
+ ///
1374
+ /// let data = AlignedI32(42);
1375
+ /// let ptr = &data as *const AlignedI32;
1376
+ ///
1377
+ /// assert!(ptr.is_aligned());
1378
+ /// assert!(!ptr.wrapping_byte_add(1).is_aligned());
1379
+ /// ```
1380
+ ///
1381
+ /// # At compiletime
1382
+ /// **Note: Alignment at compiletime is experimental and subject to change. See the
1383
+ /// [tracking issue] for details.**
1384
+ ///
1385
+ /// At compiletime, the compiler may not know where a value will end up in memory.
1386
+ /// Calling this function on a pointer created from a reference at compiletime will only
1387
+ /// return `true` if the pointer is guaranteed to be aligned. This means that the pointer
1388
+ /// is never aligned if cast to a type with a stricter alignment than the reference's
1389
+ /// underlying allocation.
1390
+ ///
1391
+ #[ cfg_attr( bootstrap, doc = "```ignore" ) ]
1392
+ #[ cfg_attr( not( bootstrap) , doc = "```" ) ]
1393
+ /// #![feature(pointer_is_aligned)]
1394
+ /// #![feature(const_pointer_is_aligned)]
1395
+ ///
1396
+ /// // On some platforms, the alignment of primitives is less than their size.
1397
+ /// #[repr(align(4))]
1398
+ /// struct AlignedI32(i32);
1399
+ /// #[repr(align(8))]
1400
+ /// struct AlignedI64(i64);
1401
+ ///
1402
+ /// const _: () = {
1403
+ /// let data = AlignedI32(42);
1404
+ /// let ptr = &data as *const AlignedI32;
1405
+ /// assert!(ptr.is_aligned());
1406
+ ///
1407
+ /// // At runtime either `ptr1` or `ptr2` would be aligned, but at compiletime neither is aligned.
1408
+ /// let ptr1 = ptr.cast::<AlignedI64>();
1409
+ /// let ptr2 = ptr.wrapping_add(1).cast::<AlignedI64>();
1410
+ /// assert!(!ptr1.is_aligned());
1411
+ /// assert!(!ptr2.is_aligned());
1412
+ /// };
1413
+ /// ```
1414
+ ///
1415
+ /// Due to this behavior, it is possible that a runtime pointer derived from a compiletime
1416
+ /// pointer is aligned, even if the compiletime pointer wasn't aligned.
1417
+ ///
1418
+ #[ cfg_attr( bootstrap, doc = "```ignore" ) ]
1419
+ #[ cfg_attr( not( bootstrap) , doc = "```" ) ]
1420
+ /// #![feature(pointer_is_aligned)]
1421
+ /// #![feature(const_pointer_is_aligned)]
1422
+ ///
1423
+ /// // On some platforms, the alignment of primitives is less than their size.
1424
+ /// #[repr(align(4))]
1425
+ /// struct AlignedI32(i32);
1426
+ /// #[repr(align(8))]
1427
+ /// struct AlignedI64(i64);
1428
+ ///
1429
+ /// // At compiletime, neither `COMPTIME_PTR` nor `COMPTIME_PTR + 1` is aligned.
1430
+ /// const COMPTIME_PTR: *const AlignedI32 = &AlignedI32(42);
1431
+ /// const _: () = assert!(!COMPTIME_PTR.cast::<AlignedI64>().is_aligned());
1432
+ /// const _: () = assert!(!COMPTIME_PTR.wrapping_add(1).cast::<AlignedI64>().is_aligned());
1433
+ ///
1434
+ /// // At runtime, either `runtime_ptr` or `runtime_ptr + 1` is aligned.
1435
+ /// let runtime_ptr = COMPTIME_PTR;
1436
+ /// assert_ne!(
1437
+ /// runtime_ptr.cast::<AlignedI64>().is_aligned(),
1438
+ /// runtime_ptr.wrapping_add(1).cast::<AlignedI64>().is_aligned(),
1439
+ /// );
1440
+ /// ```
1441
+ ///
1442
+ /// If a pointer is created from a fixed address, this function behaves the same during
1443
+ /// runtime and compiletime.
1444
+ ///
1445
+ #[ cfg_attr( bootstrap, doc = "```ignore" ) ]
1446
+ #[ cfg_attr( not( bootstrap) , doc = "```" ) ]
1447
+ /// #![feature(pointer_is_aligned)]
1448
+ /// #![feature(const_pointer_is_aligned)]
1449
+ ///
1450
+ /// // On some platforms, the alignment of primitives is less than their size.
1451
+ /// #[repr(align(4))]
1452
+ /// struct AlignedI32(i32);
1453
+ /// #[repr(align(8))]
1454
+ /// struct AlignedI64(i64);
1455
+ ///
1456
+ /// const _: () = {
1457
+ /// let ptr = 40 as *const AlignedI32;
1458
+ /// assert!(ptr.is_aligned());
1459
+ ///
1460
+ /// // For pointers with a known address, runtime and compiletime behavior are identical.
1461
+ /// let ptr1 = ptr.cast::<AlignedI64>();
1462
+ /// let ptr2 = ptr.wrapping_add(1).cast::<AlignedI64>();
1463
+ /// assert!(ptr1.is_aligned());
1464
+ /// assert!(!ptr2.is_aligned());
1465
+ /// };
1466
+ /// ```
1467
+ ///
1468
+ /// [tracking issue]: https://github.com/rust-lang/rust/issues/104203
1351
1469
#[ must_use]
1352
1470
#[ inline]
1353
1471
#[ unstable( feature = "pointer_is_aligned" , issue = "96284" ) ]
1354
- pub fn is_aligned ( self ) -> bool
1472
+ #[ rustc_const_unstable( feature = "const_pointer_is_aligned" , issue = "104203" ) ]
1473
+ pub const fn is_aligned ( self ) -> bool
1355
1474
where
1356
1475
T : Sized ,
1357
1476
{
1358
- self . is_aligned_to ( core :: mem:: align_of :: < T > ( ) )
1477
+ self . is_aligned_to ( mem:: align_of :: < T > ( ) )
1359
1478
}
1360
1479
1361
1480
/// Returns whether the pointer is aligned to `align`.
@@ -1366,16 +1485,121 @@ impl<T: ?Sized> *const T {
1366
1485
/// # Panics
1367
1486
///
1368
1487
/// The function panics if `align` is not a power-of-two (this includes 0).
1488
+ ///
1489
+ /// # Examples
1490
+ ///
1491
+ /// Basic usage:
1492
+ /// ```
1493
+ /// #![feature(pointer_is_aligned)]
1494
+ /// #![feature(pointer_byte_offsets)]
1495
+ ///
1496
+ /// // On some platforms, the alignment of i32 is less than 4.
1497
+ /// #[repr(align(4))]
1498
+ /// struct AlignedI32(i32);
1499
+ ///
1500
+ /// let data = AlignedI32(42);
1501
+ /// let ptr = &data as *const AlignedI32;
1502
+ ///
1503
+ /// assert!(ptr.is_aligned_to(1));
1504
+ /// assert!(ptr.is_aligned_to(2));
1505
+ /// assert!(ptr.is_aligned_to(4));
1506
+ ///
1507
+ /// assert!(ptr.wrapping_byte_add(2).is_aligned_to(2));
1508
+ /// assert!(!ptr.wrapping_byte_add(2).is_aligned_to(4));
1509
+ ///
1510
+ /// assert_ne!(ptr.is_aligned_to(8), ptr.wrapping_add(1).is_aligned_to(8));
1511
+ /// ```
1512
+ ///
1513
+ /// # At compiletime
1514
+ /// **Note: Alignment at compiletime is experimental and subject to change. See the
1515
+ /// [tracking issue] for details.**
1516
+ ///
1517
+ /// At compiletime, the compiler may not know where a value will end up in memory.
1518
+ /// Calling this function on a pointer created from a reference at compiletime will only
1519
+ /// return `true` if the pointer is guaranteed to be aligned. This means that the pointer
1520
+ /// cannot be stricter aligned than the reference's underlying allocation.
1521
+ ///
1522
+ #[ cfg_attr( bootstrap, doc = "```ignore" ) ]
1523
+ #[ cfg_attr( not( bootstrap) , doc = "```" ) ]
1524
+ /// #![feature(pointer_is_aligned)]
1525
+ /// #![feature(const_pointer_is_aligned)]
1526
+ ///
1527
+ /// // On some platforms, the alignment of i32 is less than 4.
1528
+ /// #[repr(align(4))]
1529
+ /// struct AlignedI32(i32);
1530
+ ///
1531
+ /// const _: () = {
1532
+ /// let data = AlignedI32(42);
1533
+ /// let ptr = &data as *const AlignedI32;
1534
+ ///
1535
+ /// assert!(ptr.is_aligned_to(1));
1536
+ /// assert!(ptr.is_aligned_to(2));
1537
+ /// assert!(ptr.is_aligned_to(4));
1538
+ ///
1539
+ /// // At compiletime, we know for sure that the pointer isn't aligned to 8.
1540
+ /// assert!(!ptr.is_aligned_to(8));
1541
+ /// assert!(!ptr.wrapping_add(1).is_aligned_to(8));
1542
+ /// };
1543
+ /// ```
1544
+ ///
1545
+ /// Due to this behavior, it is possible that a runtime pointer derived from a compiletime
1546
+ /// pointer is aligned, even if the compiletime pointer wasn't aligned.
1547
+ ///
1548
+ #[ cfg_attr( bootstrap, doc = "```ignore" ) ]
1549
+ #[ cfg_attr( not( bootstrap) , doc = "```" ) ]
1550
+ /// #![feature(pointer_is_aligned)]
1551
+ /// #![feature(const_pointer_is_aligned)]
1552
+ ///
1553
+ /// // On some platforms, the alignment of i32 is less than 4.
1554
+ /// #[repr(align(4))]
1555
+ /// struct AlignedI32(i32);
1556
+ ///
1557
+ /// // At compiletime, neither `COMPTIME_PTR` nor `COMPTIME_PTR + 1` is aligned.
1558
+ /// const COMPTIME_PTR: *const AlignedI32 = &AlignedI32(42);
1559
+ /// const _: () = assert!(!COMPTIME_PTR.is_aligned_to(8));
1560
+ /// const _: () = assert!(!COMPTIME_PTR.wrapping_add(1).is_aligned_to(8));
1561
+ ///
1562
+ /// // At runtime, either `runtime_ptr` or `runtime_ptr + 1` is aligned.
1563
+ /// let runtime_ptr = COMPTIME_PTR;
1564
+ /// assert_ne!(
1565
+ /// runtime_ptr.is_aligned_to(8),
1566
+ /// runtime_ptr.wrapping_add(1).is_aligned_to(8),
1567
+ /// );
1568
+ /// ```
1569
+ ///
1570
+ /// If a pointer is created from a fixed address, this function behaves the same during
1571
+ /// runtime and compiletime.
1572
+ ///
1573
+ #[ cfg_attr( bootstrap, doc = "```ignore" ) ]
1574
+ #[ cfg_attr( not( bootstrap) , doc = "```" ) ]
1575
+ /// #![feature(pointer_is_aligned)]
1576
+ /// #![feature(const_pointer_is_aligned)]
1577
+ ///
1578
+ /// const _: () = {
1579
+ /// let ptr = 40 as *const u8;
1580
+ /// assert!(ptr.is_aligned_to(1));
1581
+ /// assert!(ptr.is_aligned_to(2));
1582
+ /// assert!(ptr.is_aligned_to(4));
1583
+ /// assert!(ptr.is_aligned_to(8));
1584
+ /// assert!(!ptr.is_aligned_to(16));
1585
+ /// };
1586
+ /// ```
1587
+ ///
1588
+ /// [tracking issue]: https://github.com/rust-lang/rust/issues/104203
1369
1589
#[ must_use]
1370
1590
#[ inline]
1371
1591
#[ unstable( feature = "pointer_is_aligned" , issue = "96284" ) ]
1372
- pub fn is_aligned_to ( self , align : usize ) -> bool {
1592
+ #[ rustc_const_unstable( feature = "const_pointer_is_aligned" , issue = "104203" ) ]
1593
+ pub const fn is_aligned_to ( self , align : usize ) -> bool {
1373
1594
if !align. is_power_of_two ( ) {
1374
1595
panic ! ( "is_aligned_to: align is not a power-of-two" ) ;
1375
1596
}
1376
1597
1377
- // Cast is needed for `T: !Sized`
1378
- self . cast :: < u8 > ( ) . addr ( ) & align - 1 == 0
1598
+ // We can't use the address of `self` in a `const fn`, so we use `align_offset` instead.
1599
+ // The cast to `()` is used to
1600
+ // 1. deal with fat pointers; and
1601
+ // 2. ensure that `align_offset` doesn't actually try to compute an offset.
1602
+ self . cast :: < ( ) > ( ) . align_offset ( align) == 0
1379
1603
}
1380
1604
}
1381
1605
0 commit comments