From 321cd2aa25318eb2f565b06d26ced5111e1fd15f Mon Sep 17 00:00:00 2001 From: cyrgani Date: Mon, 22 Sep 2025 22:55:22 +0200 Subject: [PATCH 01/64] remove duplicated columns from `rustc_error_code::error_codes!` --- .../src/error_codes/E0773.md | 2 +- compiler/rustc_error_codes/src/lib.rs | 1040 ++++++++--------- compiler/rustc_errors/src/codes.rs | 8 +- compiler/rustc_errors/src/lib.rs | 1 + src/tools/tidy/src/error_codes.rs | 46 +- 5 files changed, 535 insertions(+), 562 deletions(-) diff --git a/compiler/rustc_error_codes/src/error_codes/E0773.md b/compiler/rustc_error_codes/src/error_codes/E0773.md index 5ebb43c6683e..91cf005d5471 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0773.md +++ b/compiler/rustc_error_codes/src/error_codes/E0773.md @@ -1,4 +1,4 @@ -#### this error code is no longer emitted by the compiler. +#### Note: this error code is no longer emitted by the compiler. This was triggered when multiple macro definitions used the same `#[rustc_builtin_macro(..)]`. This is no longer an error. diff --git a/compiler/rustc_error_codes/src/lib.rs b/compiler/rustc_error_codes/src/lib.rs index 0aff1c06e0a8..a7bcab444788 100644 --- a/compiler/rustc_error_codes/src/lib.rs +++ b/compiler/rustc_error_codes/src/lib.rs @@ -21,533 +21,531 @@ // Also, the contents of this macro is checked by tidy (in `check_error_codes_docs`). If you change // the macro syntax you will need to change tidy as well. // -// Both columns are necessary because it's not possible in Rust to create a new identifier such as -// `E0123` from an integer literal such as `0123`, unfortunately. -// -// Do *not* remove entries from this list. Instead, just add a note th the corresponding markdown +// Do *not* remove entries from this list. Instead, just add a note to the corresponding markdown // file saying that this error is not emitted by the compiler any more (see E0001.md for an // example), and remove all code examples that do not build any more. #[macro_export] +#[rustfmt::skip] macro_rules! error_codes { ($macro:path) => ( $macro!( -E0001: 0001, -E0002: 0002, -E0004: 0004, -E0005: 0005, -E0007: 0007, -E0009: 0009, -E0010: 0010, -E0013: 0013, -E0014: 0014, -E0015: 0015, -E0023: 0023, -E0025: 0025, -E0026: 0026, -E0027: 0027, -E0029: 0029, -E0030: 0030, -E0033: 0033, -E0034: 0034, -E0038: 0038, -E0040: 0040, -E0044: 0044, -E0045: 0045, -E0046: 0046, -E0049: 0049, -E0050: 0050, -E0053: 0053, -E0054: 0054, -E0055: 0055, -E0057: 0057, -E0059: 0059, -E0060: 0060, -E0061: 0061, -E0062: 0062, -E0063: 0063, -E0067: 0067, -E0069: 0069, -E0070: 0070, -E0071: 0071, -E0072: 0072, -E0073: 0073, -E0074: 0074, -E0075: 0075, -E0076: 0076, -E0077: 0077, -E0080: 0080, -E0081: 0081, -E0084: 0084, -E0087: 0087, -E0088: 0088, -E0089: 0089, -E0090: 0090, -E0091: 0091, -E0092: 0092, -E0093: 0093, -E0094: 0094, -E0106: 0106, -E0107: 0107, -E0109: 0109, -E0110: 0110, -E0116: 0116, -E0117: 0117, -E0118: 0118, -E0119: 0119, -E0120: 0120, -E0121: 0121, -E0124: 0124, -E0128: 0128, -E0130: 0130, -E0131: 0131, -E0132: 0132, -E0133: 0133, -E0136: 0136, -E0137: 0137, -E0138: 0138, -E0139: 0139, -E0152: 0152, -E0154: 0154, -E0158: 0158, -E0161: 0161, -E0162: 0162, -E0164: 0164, -E0165: 0165, -E0170: 0170, -E0178: 0178, -E0183: 0183, -E0184: 0184, -E0185: 0185, -E0186: 0186, -E0191: 0191, -E0192: 0192, -E0193: 0193, -E0195: 0195, -E0197: 0197, -E0198: 0198, -E0199: 0199, -E0200: 0200, -E0201: 0201, -E0203: 0203, -E0204: 0204, -E0205: 0205, -E0206: 0206, -E0207: 0207, -E0208: 0208, -E0210: 0210, -E0211: 0211, -E0212: 0212, -E0214: 0214, -E0220: 0220, -E0221: 0221, -E0222: 0222, -E0223: 0223, -E0224: 0224, -E0225: 0225, -E0226: 0226, -E0227: 0227, -E0228: 0228, -E0229: 0229, -E0230: 0230, -E0231: 0231, -E0232: 0232, -E0243: 0243, -E0244: 0244, -E0251: 0251, -E0252: 0252, -E0253: 0253, -E0254: 0254, -E0255: 0255, -E0256: 0256, -E0259: 0259, -E0260: 0260, -E0261: 0261, -E0262: 0262, -E0263: 0263, -E0264: 0264, -E0267: 0267, -E0268: 0268, -E0271: 0271, -E0275: 0275, -E0276: 0276, -E0277: 0277, -E0281: 0281, -E0282: 0282, -E0283: 0283, -E0284: 0284, -E0297: 0297, -E0301: 0301, -E0302: 0302, -E0303: 0303, -E0307: 0307, -E0308: 0308, -E0309: 0309, -E0310: 0310, -E0311: 0311, -E0312: 0312, -E0316: 0316, -E0317: 0317, -E0320: 0320, -E0321: 0321, -E0322: 0322, -E0323: 0323, -E0324: 0324, -E0325: 0325, -E0326: 0326, -E0328: 0328, -E0329: 0329, -E0364: 0364, -E0365: 0365, -E0366: 0366, -E0367: 0367, -E0368: 0368, -E0369: 0369, -E0370: 0370, -E0371: 0371, -E0373: 0373, -E0374: 0374, -E0375: 0375, -E0376: 0376, -E0377: 0377, -E0378: 0378, -E0379: 0379, -E0380: 0380, -E0381: 0381, -E0382: 0382, -E0383: 0383, -E0384: 0384, -E0386: 0386, -E0387: 0387, -E0388: 0388, -E0389: 0389, -E0390: 0390, -E0391: 0391, -E0392: 0392, -E0393: 0393, -E0398: 0398, -E0399: 0399, -E0401: 0401, -E0403: 0403, -E0404: 0404, -E0405: 0405, -E0407: 0407, -E0408: 0408, -E0409: 0409, -E0411: 0411, -E0412: 0412, -E0415: 0415, -E0416: 0416, -E0422: 0422, -E0423: 0423, -E0424: 0424, -E0425: 0425, -E0426: 0426, -E0428: 0428, -E0429: 0429, -E0430: 0430, -E0431: 0431, -E0432: 0432, -E0433: 0433, -E0434: 0434, -E0435: 0435, -E0436: 0436, -E0437: 0437, -E0438: 0438, -E0439: 0439, -E0445: 0445, -E0446: 0446, -E0447: 0447, -E0448: 0448, -E0449: 0449, -E0451: 0451, -E0452: 0452, -E0453: 0453, -E0454: 0454, -E0455: 0455, -E0457: 0457, -E0458: 0458, -E0459: 0459, -E0460: 0460, -E0461: 0461, -E0462: 0462, -E0463: 0463, -E0464: 0464, -E0466: 0466, -E0468: 0468, -E0469: 0469, -E0472: 0472, -E0476: 0476, -E0477: 0477, -E0478: 0478, -E0482: 0482, -E0491: 0491, -E0492: 0492, -E0493: 0493, -E0495: 0495, -E0496: 0496, -E0497: 0497, -E0498: 0498, -E0499: 0499, -E0500: 0500, -E0501: 0501, -E0502: 0502, -E0503: 0503, -E0504: 0504, -E0505: 0505, -E0506: 0506, -E0507: 0507, -E0508: 0508, -E0509: 0509, -E0510: 0510, -E0511: 0511, -E0512: 0512, -E0514: 0514, -E0515: 0515, -E0516: 0516, -E0517: 0517, -E0518: 0518, -E0519: 0519, -E0520: 0520, -E0521: 0521, -E0522: 0522, -E0523: 0523, -E0524: 0524, -E0525: 0525, -E0527: 0527, -E0528: 0528, -E0529: 0529, -E0530: 0530, -E0531: 0531, -E0532: 0532, -E0533: 0533, -E0534: 0534, -E0535: 0535, -E0536: 0536, -E0537: 0537, -E0538: 0538, -E0539: 0539, -E0541: 0541, -E0542: 0542, -E0543: 0543, -E0544: 0544, -E0545: 0545, -E0546: 0546, -E0547: 0547, -E0549: 0549, -E0550: 0550, -E0551: 0551, -E0552: 0552, -E0554: 0554, -E0556: 0556, -E0557: 0557, -E0559: 0559, -E0560: 0560, -E0561: 0561, -E0562: 0562, -E0565: 0565, -E0566: 0566, -E0567: 0567, -E0568: 0568, -E0569: 0569, -E0570: 0570, -E0571: 0571, -E0572: 0572, -E0573: 0573, -E0574: 0574, -E0575: 0575, -E0576: 0576, -E0577: 0577, -E0578: 0578, -E0579: 0579, -E0580: 0580, -E0581: 0581, -E0582: 0582, -E0583: 0583, -E0584: 0584, -E0585: 0585, -E0586: 0586, -E0587: 0587, -E0588: 0588, -E0589: 0589, -E0590: 0590, -E0591: 0591, -E0592: 0592, -E0593: 0593, -E0594: 0594, -E0595: 0595, -E0596: 0596, -E0597: 0597, -E0599: 0599, -E0600: 0600, -E0601: 0601, -E0602: 0602, -E0603: 0603, -E0604: 0604, -E0605: 0605, -E0606: 0606, -E0607: 0607, -E0608: 0608, -E0609: 0609, -E0610: 0610, -E0614: 0614, -E0615: 0615, -E0616: 0616, -E0617: 0617, -E0618: 0618, -E0619: 0619, -E0620: 0620, -E0621: 0621, -E0622: 0622, // REMOVED: rustc-intrinsic ABI was removed -E0623: 0623, -E0624: 0624, -E0625: 0625, -E0626: 0626, -E0627: 0627, -E0628: 0628, -E0631: 0631, -E0632: 0632, -E0633: 0633, -E0634: 0634, -E0635: 0635, -E0636: 0636, -E0637: 0637, -E0638: 0638, -E0639: 0639, -E0640: 0640, -E0641: 0641, -E0642: 0642, -E0643: 0643, -E0644: 0644, -E0646: 0646, -E0647: 0647, -E0648: 0648, -E0657: 0657, -E0658: 0658, -E0659: 0659, -E0660: 0660, -E0661: 0661, -E0662: 0662, -E0663: 0663, -E0664: 0664, -E0665: 0665, -E0666: 0666, -E0667: 0667, -E0668: 0668, -E0669: 0669, -E0670: 0670, -E0671: 0671, -E0687: 0687, -E0688: 0688, -E0689: 0689, -E0690: 0690, -E0691: 0691, -E0692: 0692, -E0693: 0693, -E0695: 0695, -E0696: 0696, -E0697: 0697, -E0698: 0698, -E0699: 0699, // REMOVED: merged into generic inference var error -E0700: 0700, -E0701: 0701, -E0703: 0703, -E0704: 0704, -E0705: 0705, -E0706: 0706, -E0708: 0708, -E0710: 0710, -E0712: 0712, -E0713: 0713, -E0714: 0714, -E0715: 0715, -E0716: 0716, -E0711: 0711, -E0717: 0717, -E0718: 0718, -E0719: 0719, -E0720: 0720, -E0722: 0722, -E0724: 0724, -E0725: 0725, -E0726: 0726, -E0727: 0727, -E0728: 0728, -E0729: 0729, -E0730: 0730, -E0731: 0731, -E0732: 0732, -E0733: 0733, -E0734: 0734, -E0735: 0735, -E0736: 0736, -E0737: 0737, -E0739: 0739, -E0740: 0740, -E0741: 0741, -E0742: 0742, -E0743: 0743, -E0744: 0744, -E0745: 0745, -E0746: 0746, -E0747: 0747, -E0748: 0748, -E0749: 0749, -E0750: 0750, -E0751: 0751, -E0752: 0752, -E0753: 0753, -E0754: 0754, -E0755: 0755, -E0756: 0756, -E0757: 0757, -E0758: 0758, -E0759: 0759, -E0760: 0760, -E0761: 0761, -E0762: 0762, -E0763: 0763, -E0764: 0764, -E0765: 0765, -E0766: 0766, -E0767: 0767, -E0768: 0768, -E0769: 0769, -E0770: 0770, -E0771: 0771, -E0772: 0772, -E0773: 0773, -E0774: 0774, -E0775: 0775, -E0776: 0776, -E0777: 0777, -E0778: 0778, -E0779: 0779, -E0780: 0780, -E0781: 0781, -E0782: 0782, -E0783: 0783, -E0784: 0784, -E0785: 0785, -E0786: 0786, -E0787: 0787, -E0788: 0788, -E0789: 0789, -E0790: 0790, -E0791: 0791, -E0792: 0792, -E0793: 0793, -E0794: 0794, -E0795: 0795, -E0796: 0796, -E0797: 0797, -E0798: 0798, -E0799: 0799, -E0800: 0800, -E0801: 0801, -E0802: 0802, -E0803: 0803, -E0804: 0804, -E0805: 0805, +0001, +0002, +0004, +0005, +0007, +0009, +0010, +0013, +0014, +0015, +0023, +0025, +0026, +0027, +0029, +0030, +0033, +0034, +0038, +0040, +0044, +0045, +0046, +0049, +0050, +0053, +0054, +0055, +0057, +0059, +0060, +0061, +0062, +0063, +0067, +0069, +0070, +0071, +0072, +0073, +0074, +0075, +0076, +0077, +0080, +0081, +0084, +0087, +0088, +0089, +0090, +0091, +0092, +0093, +0094, +0106, +0107, +0109, +0110, +0116, +0117, +0118, +0119, +0120, +0121, +0124, +0128, +0130, +0131, +0132, +0133, +0136, +0137, +0138, +0139, +0152, +0154, +0158, +0161, +0162, +0164, +0165, +0170, +0178, +0183, +0184, +0185, +0186, +0191, +0192, +0193, +0195, +0197, +0198, +0199, +0200, +0201, +0203, +0204, +0205, +0206, +0207, +0208, +0210, +0211, +0212, +0214, +0220, +0221, +0222, +0223, +0224, +0225, +0226, +0227, +0228, +0229, +0230, +0231, +0232, +0243, +0244, +0251, +0252, +0253, +0254, +0255, +0256, +0259, +0260, +0261, +0262, +0263, +0264, +0267, +0268, +0271, +0275, +0276, +0277, +0281, +0282, +0283, +0284, +0297, +0301, +0302, +0303, +0307, +0308, +0309, +0310, +0311, +0312, +0316, +0317, +0320, +0321, +0322, +0323, +0324, +0325, +0326, +0328, +0329, +0364, +0365, +0366, +0367, +0368, +0369, +0370, +0371, +0373, +0374, +0375, +0376, +0377, +0378, +0379, +0380, +0381, +0382, +0383, +0384, +0386, +0387, +0388, +0389, +0390, +0391, +0392, +0393, +0398, +0399, +0401, +0403, +0404, +0405, +0407, +0408, +0409, +0411, +0412, +0415, +0416, +0422, +0423, +0424, +0425, +0426, +0428, +0429, +0430, +0431, +0432, +0433, +0434, +0435, +0436, +0437, +0438, +0439, +0445, +0446, +0447, +0448, +0449, +0451, +0452, +0453, +0454, +0455, +0457, +0458, +0459, +0460, +0461, +0462, +0463, +0464, +0466, +0468, +0469, +0472, +0476, +0477, +0478, +0482, +0491, +0492, +0493, +0495, +0496, +0497, +0498, +0499, +0500, +0501, +0502, +0503, +0504, +0505, +0506, +0507, +0508, +0509, +0510, +0511, +0512, +0514, +0515, +0516, +0517, +0518, +0519, +0520, +0521, +0522, +0523, +0524, +0525, +0527, +0528, +0529, +0530, +0531, +0532, +0533, +0534, +0535, +0536, +0537, +0538, +0539, +0541, +0542, +0543, +0544, +0545, +0546, +0547, +0549, +0550, +0551, +0552, +0554, +0556, +0557, +0559, +0560, +0561, +0562, +0565, +0566, +0567, +0568, +0569, +0570, +0571, +0572, +0573, +0574, +0575, +0576, +0577, +0578, +0579, +0580, +0581, +0582, +0583, +0584, +0585, +0586, +0587, +0588, +0589, +0590, +0591, +0592, +0593, +0594, +0595, +0596, +0597, +0599, +0600, +0601, +0602, +0603, +0604, +0605, +0606, +0607, +0608, +0609, +0610, +0614, +0615, +0616, +0617, +0618, +0619, +0620, +0621, +0622, // REMOVED: rustc-intrinsic ABI was removed +0623, +0624, +0625, +0626, +0627, +0628, +0631, +0632, +0633, +0634, +0635, +0636, +0637, +0638, +0639, +0640, +0641, +0642, +0643, +0644, +0646, +0647, +0648, +0657, +0658, +0659, +0660, +0661, +0662, +0663, +0664, +0665, +0666, +0667, +0668, +0669, +0670, +0671, +0687, +0688, +0689, +0690, +0691, +0692, +0693, +0695, +0696, +0697, +0698, +0699, // REMOVED: merged into generic inference var error +0700, +0701, +0703, +0704, +0705, +0706, +0708, +0710, +0712, +0713, +0714, +0715, +0716, +0711, +0717, +0718, +0719, +0720, +0722, +0724, +0725, +0726, +0727, +0728, +0729, +0730, +0731, +0732, +0733, +0734, +0735, +0736, +0737, +0739, +0740, +0741, +0742, +0743, +0744, +0745, +0746, +0747, +0748, +0749, +0750, +0751, +0752, +0753, +0754, +0755, +0756, +0757, +0758, +0759, +0760, +0761, +0762, +0763, +0764, +0765, +0766, +0767, +0768, +0769, +0770, +0771, +0772, +0773, // REMOVED: no longer an error +0774, +0775, +0776, +0777, +0778, +0779, +0780, +0781, +0782, +0783, +0784, +0785, +0786, +0787, +0788, +0789, +0790, +0791, +0792, +0793, +0794, +0795, +0796, +0797, +0798, +0799, +0800, +0801, +0802, +0803, +0804, +0805, ); ) } diff --git a/compiler/rustc_errors/src/codes.rs b/compiler/rustc_errors/src/codes.rs index 787a8af99b1f..924924f285eb 100644 --- a/compiler/rustc_errors/src/codes.rs +++ b/compiler/rustc_errors/src/codes.rs @@ -23,15 +23,15 @@ impl fmt::Display for ErrCode { rustc_error_messages::into_diag_arg_using_display!(ErrCode); macro_rules! define_error_code_constants_and_diagnostics_table { - ($($name:ident: $num:literal,)*) => ( + ($($num:literal,)*) => ( $( - pub const $name: $crate::ErrCode = $crate::ErrCode::from_u32($num); + pub const ${concat(E, $num)}: $crate::ErrCode = $crate::ErrCode::from_u32($num); )* pub static DIAGNOSTICS: &[($crate::ErrCode, &str)] = &[ $( ( - $name, + ${concat(E, $num)}, include_str!( - concat!("../../rustc_error_codes/src/error_codes/", stringify!($name), ".md") + concat!("../../rustc_error_codes/src/error_codes/E", stringify!($num), ".md") ) ), )* ]; diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 8869799ce90d..ad2b3c74270a 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -15,6 +15,7 @@ #![feature(box_patterns)] #![feature(default_field_values)] #![feature(error_reporter)] +#![feature(macro_metavar_expr_concat)] #![feature(negative_impls)] #![feature(never_type)] #![feature(rustc_attrs)] diff --git a/src/tools/tidy/src/error_codes.rs b/src/tools/tidy/src/error_codes.rs index 83fbefa43d97..240ac839e3e3 100644 --- a/src/tools/tidy/src/error_codes.rs +++ b/src/tools/tidy/src/error_codes.rs @@ -91,20 +91,16 @@ fn extract_error_codes(root_path: &Path, check: &mut RunningCheck) -> Vec(); + if chars.next() != Some(',') { check.error(format!( - "{path}:{line_index}: Expected a line with the format `Eabcd: abcd, \ - but got \"{line}\" without a `:` delimiter", + "{path}:{line_index}: Expected a line with the format `abcd,` \ + but got \"{line}\" without a `,` delimiter", )); continue; - }; - - let err_code = split_line.0.to_owned(); + } // If this is a duplicate of another error code, emit a fatal error. if error_codes.contains(&err_code) { @@ -114,35 +110,13 @@ fn extract_error_codes(root_path: &Path, check: &mut RunningCheck) -> Vec Date: Tue, 2 Dec 2025 16:53:12 -0500 Subject: [PATCH 02/64] rustdoc: Add unstable `--merge-doctests=yes/no/auto` flag This is useful for changing the *default* for whether doctests are merged or not. Currently, that default is solely controlled by `edition = 2024`, which adds a high switching cost to get doctest merging. This flag allows opt-ing in even on earlier additions. Unlike the `edition = 2024` default, `--merge-doctests=yes` gives a hard error if merging fails instead of falling back to running standalone tests. The user has explicitly said they want merging, so we shouldn't silently do something else. `--merge-doctests=auto` is equivalent to the current 2024 edition behavior, but available on earlier editions. --- src/librustdoc/config.rs | 31 ++++++++++++++++ src/librustdoc/doctest.rs | 34 +++++++++++------ src/librustdoc/doctest/make.rs | 37 ++++++++++++------- src/librustdoc/doctest/markdown.rs | 4 +- src/librustdoc/lib.rs | 10 ++++- .../output-default.stdout | 4 ++ tests/rustdoc-ui/doctest/force-merge-fail.rs | 18 +++++++++ .../doctest/force-merge-fail.stderr | 6 +++ tests/rustdoc-ui/doctest/force-merge.rs | 25 +++++++++++++ tests/rustdoc-ui/doctest/force-merge.stdout | 8 ++++ tests/rustdoc-ui/doctest/force-no-merge.rs | 24 ++++++++++++ .../rustdoc-ui/doctest/force-no-merge.stdout | 7 ++++ .../rustdoc-ui/doctest/merge-doctests-auto.rs | 28 ++++++++++++++ .../doctest/merge-doctests-auto.stdout | 8 ++++ .../doctest/merge-doctests-invalid.rs | 2 + .../doctest/merge-doctests-invalid.stderr | 2 + .../doctest/merge-doctests-unstable.rs | 2 + .../doctest/merge-doctests-unstable.stderr | 2 + 18 files changed, 224 insertions(+), 28 deletions(-) create mode 100644 tests/rustdoc-ui/doctest/force-merge-fail.rs create mode 100644 tests/rustdoc-ui/doctest/force-merge-fail.stderr create mode 100644 tests/rustdoc-ui/doctest/force-merge.rs create mode 100644 tests/rustdoc-ui/doctest/force-merge.stdout create mode 100644 tests/rustdoc-ui/doctest/force-no-merge.rs create mode 100644 tests/rustdoc-ui/doctest/force-no-merge.stdout create mode 100644 tests/rustdoc-ui/doctest/merge-doctests-auto.rs create mode 100644 tests/rustdoc-ui/doctest/merge-doctests-auto.stdout create mode 100644 tests/rustdoc-ui/doctest/merge-doctests-invalid.rs create mode 100644 tests/rustdoc-ui/doctest/merge-doctests-invalid.stderr create mode 100644 tests/rustdoc-ui/doctest/merge-doctests-unstable.rs create mode 100644 tests/rustdoc-ui/doctest/merge-doctests-unstable.stderr diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index 5d16dff24c69..e5a4593260a4 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -63,6 +63,15 @@ pub(crate) enum InputMode { HasFile(Input), } +/// Whether to run multiple doctests in the same binary. +#[derive(Clone, Copy, PartialEq, Eq, Debug, Default)] +pub(crate) enum MergeDoctests { + #[default] + Never, + Always, + Auto, +} + /// Configuration options for rustdoc. #[derive(Clone)] pub(crate) struct Options { @@ -121,6 +130,8 @@ pub(crate) struct Options { /// Optional path to persist the doctest executables to, defaults to a /// temporary directory if not set. pub(crate) persist_doctests: Option, + /// Whether to merge + pub(crate) merge_doctests: MergeDoctests, /// Runtool to run doctests with pub(crate) test_runtool: Option, /// Arguments to pass to the runtool @@ -801,6 +812,8 @@ impl Options { Ok(result) => result, Err(e) => dcx.fatal(format!("--merge option error: {e}")), }; + let merge_doctests = parse_merge_doctests(matches, edition, dcx); + tracing::debug!("merge_doctests: {merge_doctests:?}"); if generate_link_to_definition && (show_coverage || output_format != OutputFormat::Html) { dcx.struct_warn( @@ -852,6 +865,7 @@ impl Options { crate_version, test_run_directory, persist_doctests, + merge_doctests, test_runtool, test_runtool_args, test_builder, @@ -1048,3 +1062,20 @@ fn parse_merge(m: &getopts::Matches) -> Result { Some(_) => Err("argument to --merge must be `none`, `shared`, or `finalize`"), } } + +fn parse_merge_doctests( + m: &getopts::Matches, + edition: Edition, + dcx: DiagCtxtHandle<'_>, +) -> MergeDoctests { + match m.opt_str("merge-doctests").as_deref() { + Some("y") | Some("yes") | Some("on") | Some("true") => MergeDoctests::Always, + Some("n") | Some("no") | Some("off") | Some("false") => MergeDoctests::Never, + Some("auto") => MergeDoctests::Auto, + None if edition < Edition::Edition2024 => MergeDoctests::Never, + None => MergeDoctests::Auto, + Some(_) => { + dcx.fatal("argument to --merge-doctests must be a boolean (true/false) or 'auto'") + } + } +} diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 481aa392007c..cab65181c940 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -33,7 +33,7 @@ use tempfile::{Builder as TempFileBuilder, TempDir}; use tracing::debug; use self::rust::HirCollector; -use crate::config::{Options as RustdocOptions, OutputFormat}; +use crate::config::{MergeDoctests, Options as RustdocOptions, OutputFormat}; use crate::html::markdown::{ErrorCodes, Ignore, LangString, MdRelLine}; use crate::lint::init_lints; @@ -265,6 +265,7 @@ pub(crate) fn run(dcx: DiagCtxtHandle<'_>, input: Input, options: RustdocOptions }; run_tests( + dcx, opts, &rustdoc_options, &unused_extern_reports, @@ -316,6 +317,7 @@ pub(crate) fn run(dcx: DiagCtxtHandle<'_>, input: Input, options: RustdocOptions } pub(crate) fn run_tests( + dcx: DiagCtxtHandle<'_>, opts: GlobalTestOptions, rustdoc_options: &Arc, unused_extern_reports: &Arc>>, @@ -368,6 +370,13 @@ pub(crate) fn run_tests( } continue; } + + if rustdoc_options.merge_doctests == MergeDoctests::Always { + let mut diag = dcx.struct_fatal("failed to merge doctests"); + diag.note("requested explicitly on the command line with `--merge-doctests=yes`"); + diag.emit(); + } + // We failed to compile all compatible tests as one so we push them into the // `standalone_tests` doctests. debug!("Failed to compile compatible doctests for edition {} all at once", edition); @@ -645,9 +654,9 @@ fn run_test( // tested as standalone tests. return (Duration::default(), Err(TestFailure::CompileError)); } - if !rustdoc_options.no_capture { - // If `no_capture` is disabled, then we don't display rustc's output when compiling - // the merged doctests. + if !rustdoc_options.no_capture && rustdoc_options.merge_doctests == MergeDoctests::Auto { + // If `no_capture` is disabled, and we might fallback to standalone tests, then we don't + // display rustc's output when compiling the merged doctests. compiler.stderr(Stdio::null()); } // bundled tests are an rlib, loaded by a separate runner executable @@ -728,10 +737,12 @@ fn run_test( // tested as standalone tests. return (instant.elapsed(), Err(TestFailure::CompileError)); } - if !rustdoc_options.no_capture { - // If `no_capture` is disabled, then we don't display rustc's output when compiling - // the merged doctests. + if !rustdoc_options.no_capture && rustdoc_options.merge_doctests == MergeDoctests::Auto { + // If `no_capture` is disabled and we're autodetecting whether to merge, + // we don't display rustc's output when compiling the merged doctests. runner_compiler.stderr(Stdio::null()); + } else { + runner_compiler.stderr(Stdio::inherit()); } runner_compiler.arg("--error-format=short"); debug!("compiler invocation for doctest runner: {runner_compiler:?}"); @@ -888,7 +899,7 @@ impl IndividualTestOptions { DirState::Perm(path) } else { - DirState::Temp(get_doctest_dir().expect("rustdoc needs a tempdir")) + DirState::Temp(get_doctest_dir(options).expect("rustdoc needs a tempdir")) }; Self { outdir, path: test_path } @@ -977,21 +988,20 @@ struct CreateRunnableDocTests { visited_tests: FxHashMap<(String, usize), usize>, unused_extern_reports: Arc>>, compiling_test_count: AtomicUsize, - can_merge_doctests: bool, + can_merge_doctests: MergeDoctests, } impl CreateRunnableDocTests { fn new(rustdoc_options: RustdocOptions, opts: GlobalTestOptions) -> CreateRunnableDocTests { - let can_merge_doctests = rustdoc_options.edition >= Edition::Edition2024; CreateRunnableDocTests { standalone_tests: Vec::new(), mergeable_tests: FxIndexMap::default(), - rustdoc_options: Arc::new(rustdoc_options), opts, visited_tests: FxHashMap::default(), unused_extern_reports: Default::default(), compiling_test_count: AtomicUsize::new(0), - can_merge_doctests, + can_merge_doctests: rustdoc_options.merge_doctests, + rustdoc_options: Arc::new(rustdoc_options), } } diff --git a/src/librustdoc/doctest/make.rs b/src/librustdoc/doctest/make.rs index e9f5024e494d..1f5956168d7e 100644 --- a/src/librustdoc/doctest/make.rs +++ b/src/librustdoc/doctest/make.rs @@ -20,6 +20,7 @@ use rustc_span::{DUMMY_SP, FileName, Span, kw}; use tracing::debug; use super::GlobalTestOptions; +use crate::config::MergeDoctests; use crate::display::Joined as _; use crate::html::markdown::LangString; @@ -41,7 +42,7 @@ pub(crate) struct BuildDocTestBuilder<'a> { source: &'a str, crate_name: Option<&'a str>, edition: Edition, - can_merge_doctests: bool, + can_merge_doctests: MergeDoctests, // If `test_id` is `None`, it means we're generating code for a code example "run" link. test_id: Option, lang_str: Option<&'a LangString>, @@ -55,7 +56,7 @@ impl<'a> BuildDocTestBuilder<'a> { source, crate_name: None, edition: DEFAULT_EDITION, - can_merge_doctests: false, + can_merge_doctests: MergeDoctests::Never, test_id: None, lang_str: None, span: DUMMY_SP, @@ -70,7 +71,7 @@ impl<'a> BuildDocTestBuilder<'a> { } #[inline] - pub(crate) fn can_merge_doctests(mut self, can_merge_doctests: bool) -> Self { + pub(crate) fn can_merge_doctests(mut self, can_merge_doctests: MergeDoctests) -> Self { self.can_merge_doctests = can_merge_doctests; self } @@ -117,10 +118,6 @@ impl<'a> BuildDocTestBuilder<'a> { span, global_crate_attrs, } = self; - let can_merge_doctests = can_merge_doctests - && lang_str.is_some_and(|lang_str| { - !lang_str.compile_fail && !lang_str.test_harness && !lang_str.standalone_crate - }); let result = rustc_driver::catch_fatal_errors(|| { rustc_span::create_session_if_not_set_then(edition, |_| { @@ -155,14 +152,26 @@ impl<'a> BuildDocTestBuilder<'a> { debug!("crate_attrs:\n{crate_attrs}{maybe_crate_attrs}"); debug!("crates:\n{crates}"); debug!("after:\n{everything_else}"); + debug!("merge-doctests: {can_merge_doctests:?}"); - // If it contains `#[feature]` or `#[no_std]`, we don't want it to be merged either. - let can_be_merged = can_merge_doctests - && !has_global_allocator - && crate_attrs.is_empty() - // If this is a merged doctest and a defined macro uses `$crate`, then the path will - // not work, so better not put it into merged doctests. - && !(has_macro_def && everything_else.contains("$crate")); + // Up until now, we've been dealing with settings for the whole crate. + // Now, infer settings for this particular test. + let can_be_merged = if can_merge_doctests == MergeDoctests::Auto { + let mut can_merge = false; + // Avoid tests with incompatible attributes. + can_merge |= lang_str.is_some_and(|lang_str| { + !lang_str.compile_fail && !lang_str.test_harness && !lang_str.standalone_crate + }); + // If it contains `#[feature]` or `#[no_std]`, we don't want it to be merged either. + can_merge &= !has_global_allocator + && crate_attrs.is_empty() + // If this is a merged doctest and a defined macro uses `$crate`, then the path will + // not work, so better not put it into merged doctests. + && !(has_macro_def && everything_else.contains("$crate")); + can_merge + } else { + can_merge_doctests != MergeDoctests::Never + }; DocTestBuilder { supports_color, has_main_fn, diff --git a/src/librustdoc/doctest/markdown.rs b/src/librustdoc/doctest/markdown.rs index 7f26605f2562..45f1e8a7fb98 100644 --- a/src/librustdoc/doctest/markdown.rs +++ b/src/librustdoc/doctest/markdown.rs @@ -3,6 +3,7 @@ use std::fs::read_to_string; use std::sync::{Arc, Mutex}; +use rustc_errors::DiagCtxtHandle; use rustc_session::config::Input; use rustc_span::{DUMMY_SP, FileName}; use tempfile::tempdir; @@ -78,7 +79,7 @@ impl DocTestVisitor for MdCollector { } /// Runs any tests/code examples in the markdown file `options.input`. -pub(crate) fn test(input: &Input, options: Options) -> Result<(), String> { +pub(crate) fn test(input: &Input, options: Options, dcx: DiagCtxtHandle<'_>) -> Result<(), String> { let input_str = match input { Input::File(path) => { read_to_string(path).map_err(|err| format!("{}: {err}", path.display()))? @@ -118,6 +119,7 @@ pub(crate) fn test(input: &Input, options: Options) -> Result<(), String> { let CreateRunnableDocTests { opts, rustdoc_options, standalone_tests, mergeable_tests, .. } = collector; crate::doctest::run_tests( + dcx, opts, &rustdoc_options, &Arc::new(Mutex::new(Vec::new())), diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index e4601bfb20d7..be46c85311a0 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -544,6 +544,14 @@ fn opts() -> Vec { "[toolchain-shared-resources,invocation-specific,dep-info]", ), opt(Unstable, FlagMulti, "", "no-run", "Compile doctests without running them", ""), + opt( + Unstable, + Opt, + "", + "merge-doctests", + "Force all doctests to be compiled as a single binary, instead of one binary per test. If merging fails, rustdoc will emit a hard error.", + "yes|no|auto", + ), opt( Unstable, Multi, @@ -822,7 +830,7 @@ fn main_args(early_dcx: &mut EarlyDiagCtxt, at_args: &[String]) { options.should_test || output_format == config::OutputFormat::Doctest, config::markdown_input(&input), ) { - (true, Some(_)) => return wrap_return(dcx, doctest::test_markdown(&input, options)), + (true, Some(_)) => return wrap_return(dcx, doctest::test_markdown(&input, options, dcx)), (true, None) => return doctest::run(dcx, input, options), (false, Some(md_input)) => { let md_input = md_input.to_owned(); diff --git a/tests/run-make/rustdoc-default-output/output-default.stdout b/tests/run-make/rustdoc-default-output/output-default.stdout index 49eaf7e2e1e0..4e28be347cbb 100644 --- a/tests/run-make/rustdoc-default-output/output-default.stdout +++ b/tests/run-make/rustdoc-default-output/output-default.stdout @@ -154,6 +154,10 @@ Options: Comma separated list of types of output for rustdoc to emit --no-run Compile doctests without running them + --merge-doctests yes|no|auto + Force all doctests to be compiled as a single binary, + instead of one binary per test. If merging fails, + rustdoc will emit a hard error. --remap-path-prefix FROM=TO Remap source names in compiler messages --show-type-layout diff --git a/tests/rustdoc-ui/doctest/force-merge-fail.rs b/tests/rustdoc-ui/doctest/force-merge-fail.rs new file mode 100644 index 000000000000..88c36268d072 --- /dev/null +++ b/tests/rustdoc-ui/doctest/force-merge-fail.rs @@ -0,0 +1,18 @@ +//@ edition: 2018 +//@ compile-flags: --test --test-args=--test-threads=1 --merge-doctests=yes -Z unstable-options +//@ normalize-stderr: ".*doctest_bundle_2018.rs:\d+:\d+" -> "doctest_bundle_2018.rs:$$LINE:$$COL" + +//~? ERROR failed to merge doctests + +/// These two doctests will fail to force-merge, and should give a hard error as a result. +/// +/// ``` +/// #![deny(clashing_extern_declarations)] +/// unsafe extern "C" { fn unmangled_name() -> u8; } +/// ``` +/// +/// ``` +/// #![deny(clashing_extern_declarations)] +/// unsafe extern "C" { fn unmangled_name(); } +/// ``` +pub struct Foo; diff --git a/tests/rustdoc-ui/doctest/force-merge-fail.stderr b/tests/rustdoc-ui/doctest/force-merge-fail.stderr new file mode 100644 index 000000000000..b87807dc5ed7 --- /dev/null +++ b/tests/rustdoc-ui/doctest/force-merge-fail.stderr @@ -0,0 +1,6 @@ +doctest_bundle_2018.rs:$LINE:$COL: error: `unmangled_name` redeclared with a different signature: this signature doesn't match the previous declaration +error: aborting due to 1 previous error +error: failed to merge doctests + | + = note: requested explicitly on the command line with `--merge-doctests=yes` + diff --git a/tests/rustdoc-ui/doctest/force-merge.rs b/tests/rustdoc-ui/doctest/force-merge.rs new file mode 100644 index 000000000000..bd2f474f8a56 --- /dev/null +++ b/tests/rustdoc-ui/doctest/force-merge.rs @@ -0,0 +1,25 @@ +//@ check-pass +//@ edition: 2018 +//@ compile-flags: --test --test-args=--test-threads=1 --merge-doctests=yes -Z unstable-options +//@ normalize-stdout: "tests/rustdoc-ui/doctest" -> "$$DIR" +//@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME" +//@ normalize-stdout: "ran in \d+\.\d+s" -> "ran in $$TIME" +//@ normalize-stdout: "compilation took \d+\.\d+s" -> "compilation took $$TIME" +//@ normalize-stdout: ".rs:\d+:\d+" -> ".rs:$$LINE:$$COL" + +// FIXME: compiletest doesn't support `// RAW` for doctests because the progress messages aren't +// emitted as JSON. Instead the .stderr file tests that this contains a +// "merged compilation took ..." message. + +/// ``` +/// let x = 12; +/// ``` +/// +/// These two doctests should be force-merged, even though this uses edition 2018. +/// +/// ``` +/// fn main() { +/// println!("owo"); +/// } +/// ``` +pub struct Foo; diff --git a/tests/rustdoc-ui/doctest/force-merge.stdout b/tests/rustdoc-ui/doctest/force-merge.stdout new file mode 100644 index 000000000000..94c7909ae0a6 --- /dev/null +++ b/tests/rustdoc-ui/doctest/force-merge.stdout @@ -0,0 +1,8 @@ + +running 2 tests +test $DIR/force-merge.rs - Foo (line 14) ... ok +test $DIR/force-merge.rs - Foo (line 20) ... ok + +test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + +all doctests ran in $TIME; merged doctests compilation took $TIME diff --git a/tests/rustdoc-ui/doctest/force-no-merge.rs b/tests/rustdoc-ui/doctest/force-no-merge.rs new file mode 100644 index 000000000000..9ddea5fc2e55 --- /dev/null +++ b/tests/rustdoc-ui/doctest/force-no-merge.rs @@ -0,0 +1,24 @@ +//@ edition: 2024 +//@ check-pass +//@ compile-flags: --test --test-args=--test-threads=1 --merge-doctests=no -Z unstable-options +//@ normalize-stderr: ".*doctest_bundle_2018.rs:\d+:\d+" -> "doctest_bundle_2018.rs:$$LINE:$$COL" + +//@ normalize-stdout: "tests/rustdoc-ui/doctest" -> "$$DIR" +//@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME" +//@ normalize-stdout: "ran in \d+\.\d+s" -> "ran in $$TIME" +//@ normalize-stdout: "compilation took \d+\.\d+s" -> "compilation took $$TIME" +//@ normalize-stdout: ".rs:\d+:\d+" -> ".rs:$$LINE:$$COL" + +/// These two doctests should not force-merge, even though this crate has edition 2024 and the +/// individual doctests are not annotated. +/// +/// ``` +/// #![deny(clashing_extern_declarations)] +/// unsafe extern "C" { fn unmangled_name() -> u8; } +/// ``` +/// +/// ``` +/// #![deny(clashing_extern_declarations)] +/// unsafe extern "C" { fn unmangled_name(); } +/// ``` +pub struct Foo; diff --git a/tests/rustdoc-ui/doctest/force-no-merge.stdout b/tests/rustdoc-ui/doctest/force-no-merge.stdout new file mode 100644 index 000000000000..513ff7705497 --- /dev/null +++ b/tests/rustdoc-ui/doctest/force-no-merge.stdout @@ -0,0 +1,7 @@ + +running 2 tests +test $DIR/force-no-merge.rs - Foo (line 15) ... ok +test $DIR/force-no-merge.rs - Foo (line 20) ... ok + +test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/tests/rustdoc-ui/doctest/merge-doctests-auto.rs b/tests/rustdoc-ui/doctest/merge-doctests-auto.rs new file mode 100644 index 000000000000..2e7d0db7a346 --- /dev/null +++ b/tests/rustdoc-ui/doctest/merge-doctests-auto.rs @@ -0,0 +1,28 @@ +//! `--merge-doctests=auto` should override the edition. + +//@ check-pass +//@ edition: 2018 +//@ compile-flags: --test --test-args=--test-threads=1 --merge-doctests=auto -Z unstable-options + +//@ normalize-stdout: "tests/rustdoc-ui/doctest" -> "$$DIR" +//@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME" +//@ normalize-stdout: "ran in \d+\.\d+s" -> "ran in $$TIME" +//@ normalize-stdout: "compilation took \d+\.\d+s" -> "compilation took $$TIME" +//@ normalize-stdout: ".rs:\d+:\d+" -> ".rs:$$LINE:$$COL" + +// FIXME: compiletest doesn't support `// RAW` for doctests because the progress messages aren't +// emitted as JSON. Instead the .stderr file tests that this contains a +// "merged compilation took ..." message. + +/// ``` +/// let x = 12; +/// ``` +/// +/// These two doctests should be auto-merged, even though this uses edition 2018. +/// +/// ``` +/// fn main() { +/// println!("owo"); +/// } +/// ``` +pub struct Foo; diff --git a/tests/rustdoc-ui/doctest/merge-doctests-auto.stdout b/tests/rustdoc-ui/doctest/merge-doctests-auto.stdout new file mode 100644 index 000000000000..a051ffd60636 --- /dev/null +++ b/tests/rustdoc-ui/doctest/merge-doctests-auto.stdout @@ -0,0 +1,8 @@ + +running 2 tests +test $DIR/merge-doctests-auto.rs - Foo (line 17) ... ok +test $DIR/merge-doctests-auto.rs - Foo (line 23) ... ok + +test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + +all doctests ran in $TIME; merged doctests compilation took $TIME diff --git a/tests/rustdoc-ui/doctest/merge-doctests-invalid.rs b/tests/rustdoc-ui/doctest/merge-doctests-invalid.rs new file mode 100644 index 000000000000..cf3a03a901ce --- /dev/null +++ b/tests/rustdoc-ui/doctest/merge-doctests-invalid.rs @@ -0,0 +1,2 @@ +//@ compile-flags: --merge-doctests=bad-opt -Zunstable-options +//~? ERROR must be a boolean diff --git a/tests/rustdoc-ui/doctest/merge-doctests-invalid.stderr b/tests/rustdoc-ui/doctest/merge-doctests-invalid.stderr new file mode 100644 index 000000000000..d232c1b59edb --- /dev/null +++ b/tests/rustdoc-ui/doctest/merge-doctests-invalid.stderr @@ -0,0 +1,2 @@ +error: argument to --merge-doctests must be a boolean (true/false) or 'auto' + diff --git a/tests/rustdoc-ui/doctest/merge-doctests-unstable.rs b/tests/rustdoc-ui/doctest/merge-doctests-unstable.rs new file mode 100644 index 000000000000..496e531659a3 --- /dev/null +++ b/tests/rustdoc-ui/doctest/merge-doctests-unstable.rs @@ -0,0 +1,2 @@ +//@ compile-flags: --merge-doctests=no +//~? RAW `-Z unstable-options` flag must also be passed diff --git a/tests/rustdoc-ui/doctest/merge-doctests-unstable.stderr b/tests/rustdoc-ui/doctest/merge-doctests-unstable.stderr new file mode 100644 index 000000000000..e8d75342bc8e --- /dev/null +++ b/tests/rustdoc-ui/doctest/merge-doctests-unstable.stderr @@ -0,0 +1,2 @@ +error: the `-Z unstable-options` flag must also be passed to enable the flag `merge-doctests` + From 3aa4ece95d6ad46ced3ea895fcc634371ff32039 Mon Sep 17 00:00:00 2001 From: Jynn Nelson Date: Wed, 3 Dec 2025 15:48:16 -0500 Subject: [PATCH 03/64] Support `-C save-temps` in rustdoc This allows viewing failed merged doctests. --- src/librustdoc/doctest.rs | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index cab65181c940..6e0025fe7064 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -123,8 +123,13 @@ pub(crate) fn generate_args_file(file_path: &Path, options: &RustdocOptions) -> Ok(()) } -fn get_doctest_dir() -> io::Result { - TempFileBuilder::new().prefix("rustdoctest").tempdir() +fn get_doctest_dir(opts: &RustdocOptions) -> io::Result { + let mut builder = TempFileBuilder::new(); + builder.prefix("rustdoctest"); + if opts.codegen_options.save_temps { + builder.disable_cleanup(true); + } + builder.tempdir() } pub(crate) fn run(dcx: DiagCtxtHandle<'_>, input: Input, options: RustdocOptions) { @@ -197,7 +202,7 @@ pub(crate) fn run(dcx: DiagCtxtHandle<'_>, input: Input, options: RustdocOptions let externs = options.externs.clone(); let json_unused_externs = options.json_unused_externs; - let temp_dir = match get_doctest_dir() + let temp_dir = match get_doctest_dir(&options) .map_err(|error| format!("failed to create temporary directory: {error:?}")) { Ok(temp_dir) => temp_dir, @@ -207,6 +212,7 @@ pub(crate) fn run(dcx: DiagCtxtHandle<'_>, input: Input, options: RustdocOptions crate::wrap_return(dcx, generate_args_file(&args_path, &options)); let extract_doctests = options.output_format == OutputFormat::Doctest; + let save_temps = options.codegen_options.save_temps; let result = interface::run_compiler(config, |compiler| { let krate = rustc_interface::passes::parse(&compiler.sess); @@ -259,7 +265,9 @@ pub(crate) fn run(dcx: DiagCtxtHandle<'_>, input: Input, options: RustdocOptions eprintln!("{error}"); // Since some files in the temporary folder are still owned and alive, we need // to manually remove the folder. - let _ = std::fs::remove_dir_all(temp_dir.path()); + if !save_temps { + let _ = std::fs::remove_dir_all(temp_dir.path()); + } std::process::exit(1); } }; From 415953a317f04b0b5ad26b1ded3671a3e2a01532 Mon Sep 17 00:00:00 2001 From: Jynn Nelson Date: Wed, 3 Dec 2025 17:40:10 -0500 Subject: [PATCH 04/64] `--merge-doctests` is a default, not an override --- src/librustdoc/doctest/make.rs | 23 +++++++++-------- .../force-merge-default-not-override.rs | 25 +++++++++++++++++++ .../force-merge-default-not-override.stdout | 7 ++++++ 3 files changed, 44 insertions(+), 11 deletions(-) create mode 100644 tests/rustdoc-ui/doctest/force-merge-default-not-override.rs create mode 100644 tests/rustdoc-ui/doctest/force-merge-default-not-override.stdout diff --git a/src/librustdoc/doctest/make.rs b/src/librustdoc/doctest/make.rs index 1f5956168d7e..569206d6ec88 100644 --- a/src/librustdoc/doctest/make.rs +++ b/src/librustdoc/doctest/make.rs @@ -156,21 +156,22 @@ impl<'a> BuildDocTestBuilder<'a> { // Up until now, we've been dealing with settings for the whole crate. // Now, infer settings for this particular test. + // + // Avoid tests with incompatible attributes. + let opt_out = lang_str.is_some_and(|lang_str| { + lang_str.compile_fail || lang_str.test_harness || lang_str.standalone_crate + }); let can_be_merged = if can_merge_doctests == MergeDoctests::Auto { - let mut can_merge = false; - // Avoid tests with incompatible attributes. - can_merge |= lang_str.is_some_and(|lang_str| { - !lang_str.compile_fail && !lang_str.test_harness && !lang_str.standalone_crate - }); - // If it contains `#[feature]` or `#[no_std]`, we don't want it to be merged either. - can_merge &= !has_global_allocator - && crate_attrs.is_empty() + // We try to look at the contents of the test to detect whether it should be merged. + // This is not a complete list of possible failures, but it catches many cases. + let will_probably_fail = has_global_allocator + || !crate_attrs.is_empty() // If this is a merged doctest and a defined macro uses `$crate`, then the path will // not work, so better not put it into merged doctests. - && !(has_macro_def && everything_else.contains("$crate")); - can_merge + || (has_macro_def && everything_else.contains("$crate")); + !opt_out && !will_probably_fail } else { - can_merge_doctests != MergeDoctests::Never + can_merge_doctests != MergeDoctests::Never && !opt_out }; DocTestBuilder { supports_color, diff --git a/tests/rustdoc-ui/doctest/force-merge-default-not-override.rs b/tests/rustdoc-ui/doctest/force-merge-default-not-override.rs new file mode 100644 index 000000000000..9a1e86ade67f --- /dev/null +++ b/tests/rustdoc-ui/doctest/force-merge-default-not-override.rs @@ -0,0 +1,25 @@ +//@ check-pass +//@ edition: 2024 +//@ compile-flags: --test --test-args=--test-threads=1 --merge-doctests=yes -Z unstable-options +//@ normalize-stdout: "tests/rustdoc-ui/doctest" -> "$$DIR" +//@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME" +//@ normalize-stdout: "ran in \d+\.\d+s" -> "ran in $$TIME" +//@ normalize-stdout: "compilation took \d+\.\d+s" -> "compilation took $$TIME" +//@ normalize-stdout: ".rs:\d+:\d+" -> ".rs:$$LINE:$$COL" + +// FIXME: compiletest doesn't support `// RAW` for doctests because the progress messages aren't +// emitted as JSON. Instead the .stderr file tests that this doesn't contains a +// "merged compilation took ..." message. + +/// ```standalone_crate +/// let x = 12; +/// ``` +/// +/// These two doctests should be not be merged, even though this passes `--merge-doctests=yes`. +/// +/// ```standalone_crate +/// fn main() { +/// println!("owo"); +/// } +/// ``` +pub struct Foo; diff --git a/tests/rustdoc-ui/doctest/force-merge-default-not-override.stdout b/tests/rustdoc-ui/doctest/force-merge-default-not-override.stdout new file mode 100644 index 000000000000..24b16ec82f45 --- /dev/null +++ b/tests/rustdoc-ui/doctest/force-merge-default-not-override.stdout @@ -0,0 +1,7 @@ + +running 2 tests +test $DIR/force-merge-default-not-override.rs - Foo (line 14) ... ok +test $DIR/force-merge-default-not-override.rs - Foo (line 20) ... ok + +test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + From d21adb9158d1b3628855f49c58a3b65fc24c4332 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Thu, 4 Dec 2025 20:21:27 +0100 Subject: [PATCH 05/64] bootstrap: add `rustc-dev` install target --- src/bootstrap/src/core/build_steps/dist.rs | 4 ++-- src/bootstrap/src/core/build_steps/install.rs | 11 +++++++++++ src/bootstrap/src/core/builder/mod.rs | 1 + 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index 40149ee09427..caf0af35e401 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -892,8 +892,8 @@ impl Step for Std { #[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct RustcDev { /// The compiler that will build rustc which will be shipped in this component. - build_compiler: Compiler, - target: TargetSelection, + pub build_compiler: Compiler, + pub target: TargetSelection, } impl RustcDev { diff --git a/src/bootstrap/src/core/build_steps/install.rs b/src/bootstrap/src/core/build_steps/install.rs index d52cc52abbd3..d23fe029bcc7 100644 --- a/src/bootstrap/src/core/build_steps/install.rs +++ b/src/bootstrap/src/core/build_steps/install.rs @@ -279,6 +279,17 @@ install!((self, builder, _config), }); install_sh(builder, "rustc", self.build_compiler, Some(self.target), &tarball); }; + RustcDev, alias = "rustc-dev", Self::should_build(_config), IS_HOST: true, { + if let Some(tarball) = builder.ensure(dist::RustcDev { + build_compiler: self.build_compiler, target: self.target + }) { + install_sh(builder, "rustc-dev", self.build_compiler, Some(self.target), &tarball); + } else { + builder.info( + &format!("skipping Install RustcDev stage{} ({})", self.build_compiler.stage + 1, self.target), + ); + } + }; RustcCodegenCranelift, alias = "rustc-codegen-cranelift", Self::should_build(_config), IS_HOST: true, { if let Some(tarball) = builder.ensure(dist::CraneliftCodegenBackend { compilers: RustcPrivateCompilers::from_build_compiler(builder, self.build_compiler, self.target), diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs index 961d0cd855ae..0bf70883a47a 100644 --- a/src/bootstrap/src/core/builder/mod.rs +++ b/src/bootstrap/src/core/builder/mod.rs @@ -998,6 +998,7 @@ impl<'a> Builder<'a> { // binary path, we must install rustc before the tools. Otherwise, the rust-installer will // install the same binaries twice for each tool, leaving backup files (*.old) as a result. install::Rustc, + install::RustcDev, install::Cargo, install::RustAnalyzer, install::Rustfmt, From df007cf8008732cec446bdde0d9604c0232121ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Fri, 20 Jun 2025 22:50:22 +0200 Subject: [PATCH 06/64] rewrite doc attribute (non-doc-comments) --- compiler/rustc_attr_parsing/messages.ftl | 29 + .../rustc_attr_parsing/src/attributes/doc.rs | 385 +++++++++++++ .../rustc_attr_parsing/src/attributes/mod.rs | 1 + .../rustc_attr_parsing/src/attributes/util.rs | 33 +- compiler/rustc_attr_parsing/src/context.rs | 5 +- .../src/session_diagnostics.rs | 67 +++ .../rustc_hir/src/attrs/data_structures.rs | 73 ++- .../rustc_hir/src/attrs/encode_cross_crate.rs | 1 + .../rustc_hir/src/attrs/pretty_printing.rs | 20 + compiler/rustc_hir/src/lints.rs | 42 ++ compiler/rustc_hir_typeck/src/method/probe.rs | 6 +- compiler/rustc_passes/messages.ftl | 32 -- compiler/rustc_passes/src/check_attr.rs | 519 +++++------------- compiler/rustc_passes/src/errors.rs | 64 +-- .../rustc_resolve/src/late/diagnostics.rs | 6 +- 15 files changed, 779 insertions(+), 504 deletions(-) create mode 100644 compiler/rustc_attr_parsing/src/attributes/doc.rs diff --git a/compiler/rustc_attr_parsing/messages.ftl b/compiler/rustc_attr_parsing/messages.ftl index 02ddf8ac0023..4482266c6c2e 100644 --- a/compiler/rustc_attr_parsing/messages.ftl +++ b/compiler/rustc_attr_parsing/messages.ftl @@ -234,5 +234,34 @@ attr_parsing_unused_multiple = .suggestion = remove this attribute .note = attribute also specified here +attr_parsing_doc_alias_duplicated = doc alias is duplicated + .label = first defined here + attr_parsing_whole_archive_needs_static = linking modifier `whole-archive` is only compatible with `static` linking kind + +attr_parsing_unused_no_lints_note = + attribute `{$name}` without any lints has no effect + +attr_parsing_doc_alias_empty = + {$attr_str} attribute cannot have empty value + +attr_parsing_doc_alias_bad_char = + {$char_} character isn't allowed in {$attr_str} + +attr_parsing_doc_alias_start_end = + {$attr_str} cannot start or end with ' ' + +attr_parsing_doc_keyword_not_keyword = + nonexistent keyword `{$keyword}` used in `#[doc(keyword = "...")]` + .help = only existing keywords are allowed in core/std + +attr_parsing_doc_inline_conflict = + conflicting doc inlining attributes + .help = remove one of the conflicting attributes + +attr_parsing_doc_inline_conflict_first = + this attribute... + +attr_parsing_doc_inline_conflict_second = + {"."}..conflicts with this attribute diff --git a/compiler/rustc_attr_parsing/src/attributes/doc.rs b/compiler/rustc_attr_parsing/src/attributes/doc.rs new file mode 100644 index 000000000000..a5986170c192 --- /dev/null +++ b/compiler/rustc_attr_parsing/src/attributes/doc.rs @@ -0,0 +1,385 @@ +use rustc_attr_data_structures::lints::AttributeLintKind; +use rustc_attr_data_structures::{AttributeKind, DocAttribute, DocInline}; +use rustc_errors::MultiSpan; +use rustc_feature::template; +use rustc_span::{Span, Symbol, edition, sym}; + +use super::{AcceptMapping, AttributeParser}; +use crate::context::{AcceptContext, FinalizeContext, Stage}; +use crate::fluent_generated as fluent; +use crate::parser::{ArgParser, MetaItemOrLitParser, MetaItemParser, PathParser}; +use crate::session_diagnostics::{ + DocAliasBadChar, DocAliasEmpty, DocAliasStartEnd, DocKeywordConflict, DocKeywordNotKeyword, +}; + +#[derive(Default)] +pub(crate) struct DocParser { + attribute: DocAttribute, +} + +impl DocParser { + fn parse_single_test_doc_attr_item<'c, S: Stage>( + &mut self, + cx: &'c mut AcceptContext<'_, '_, S>, + mip: &'c MetaItemParser<'_>, + ) { + let path = mip.path(); + let args = mip.args(); + + match path.word_sym() { + Some(sym::no_crate_inject) => { + if !args.no_args() { + cx.expected_no_args(args.span().unwrap()); + return; + } + + if self.attribute.no_crate_inject.is_some() { + cx.duplicate_key(path.span(), sym::no_crate_inject); + return; + } + + self.attribute.no_crate_inject = Some(path.span()) + } + Some(sym::attr) => { + let Some(list) = args.list() else { + cx.expected_list(args.span().unwrap_or(path.span())); + return; + }; + + self.attribute.test_attrs.push(todo!()); + } + _ => { + cx.expected_specific_argument( + mip.span(), + [sym::no_crate_inject.as_str(), sym::attr.as_str()].to_vec(), + ); + } + } + } + + fn add_alias<'c, S: Stage>( + &mut self, + cx: &'c mut AcceptContext<'_, '_, S>, + alias: Symbol, + span: Span, + is_list: bool, + ) { + let attr_str = + &format!("`#[doc(alias{})]`", if is_list { "(\"...\")" } else { " = \"...\"" }); + if alias == sym::empty { + cx.emit_err(DocAliasEmpty { span, attr_str }); + return; + } + + let alias_str = alias.as_str(); + if let Some(c) = + alias_str.chars().find(|&c| c == '"' || c == '\'' || (c.is_whitespace() && c != ' ')) + { + cx.emit_err(DocAliasBadChar { span, attr_str, char_: c }); + return; + } + if alias_str.starts_with(' ') || alias_str.ends_with(' ') { + cx.emit_err(DocAliasStartEnd { span, attr_str }); + return; + } + + if let Some(first_definition) = self.attribute.aliases.get(&alias).copied() { + cx.emit_lint(AttributeLintKind::DuplicateDocAlias { first_definition }, span); + } + + self.attribute.aliases.insert(alias, span); + } + + fn parse_alias<'c, S: Stage>( + &mut self, + cx: &'c mut AcceptContext<'_, '_, S>, + path: &PathParser<'_>, + args: &ArgParser<'_>, + ) { + match args { + ArgParser::NoArgs => { + cx.expected_name_value(args.span().unwrap_or(path.span()), path.word_sym()); + } + ArgParser::List(list) => { + for i in list.mixed() { + let Some(alias) = i.lit().and_then(|i| i.value_str()) else { + cx.expected_string_literal(i.span(), i.lit()); + continue; + }; + + self.add_alias(cx, alias, i.span(), false); + } + } + ArgParser::NameValue(nv) => { + let Some(alias) = nv.value_as_str() else { + cx.expected_string_literal(nv.value_span, Some(nv.value_as_lit())); + return; + }; + self.add_alias(cx, alias, nv.value_span, false); + } + } + } + + fn parse_keyword<'c, S: Stage>( + &mut self, + cx: &'c mut AcceptContext<'_, '_, S>, + path: &PathParser<'_>, + args: &ArgParser<'_>, + ) { + let Some(nv) = args.name_value() else { + cx.expected_name_value(args.span().unwrap_or(path.span()), path.word_sym()); + return; + }; + + let Some(keyword) = nv.value_as_str() else { + cx.expected_string_literal(nv.value_span, Some(nv.value_as_lit())); + return; + }; + + fn is_doc_keyword(s: Symbol) -> bool { + // FIXME: Once rustdoc can handle URL conflicts on case insensitive file systems, we + // can remove the `SelfTy` case here, remove `sym::SelfTy`, and update the + // `#[doc(keyword = "SelfTy")` attribute in `library/std/src/keyword_docs.rs`. + s.is_reserved(|| edition::LATEST_STABLE_EDITION) || s.is_weak() || s == sym::SelfTy + } + + if !is_doc_keyword(keyword) { + cx.emit_err(DocKeywordNotKeyword { span: nv.value_span, keyword }); + } + + if self.attribute.keyword.is_some() { + cx.duplicate_key(path.span(), path.word_sym().unwrap()); + return; + } + + self.attribute.keyword = Some((keyword, path.span())); + } + + fn parse_inline<'c, S: Stage>( + &mut self, + cx: &'c mut AcceptContext<'_, '_, S>, + path: &PathParser<'_>, + args: &ArgParser<'_>, + inline: DocInline, + ) { + if !args.no_args() { + cx.expected_no_args(args.span().unwrap()); + return; + } + + let span = path.span(); + + if let Some((prev_inline, prev_span)) = self.attribute.inline { + if prev_inline == inline { + let mut spans = MultiSpan::from_spans(vec![prev_span, span]); + spans.push_span_label(prev_span, fluent::attr_parsing_doc_inline_conflict_first); + spans.push_span_label(span, fluent::attr_parsing_doc_inline_conflict_second); + cx.emit_err(DocKeywordConflict { spans }); + return; + } + } + + self.attribute.inline = Some((inline, span)); + } + + fn parse_single_doc_attr_item<'c, S: Stage>( + &mut self, + cx: &'c mut AcceptContext<'_, '_, S>, + mip: &MetaItemParser<'_>, + ) { + let path = mip.path(); + let args = mip.args(); + + macro_rules! no_args { + ($ident: ident) => {{ + if !args.no_args() { + cx.expected_no_args(args.span().unwrap()); + return; + } + + if self.attribute.$ident.is_some() { + cx.duplicate_key(path.span(), path.word_sym().unwrap()); + return; + } + + self.attribute.$ident = Some(path.span()); + }}; + } + macro_rules! string_arg { + ($ident: ident) => {{ + let Some(nv) = args.name_value() else { + cx.expected_name_value(args.span().unwrap_or(path.span()), path.word_sym()); + return; + }; + + let Some(s) = nv.value_as_str() else { + cx.expected_string_literal(nv.value_span, Some(nv.value_as_lit())); + return; + }; + + if self.attribute.$ident.is_some() { + cx.duplicate_key(path.span(), path.word_sym().unwrap()); + return; + } + + self.attribute.$ident = Some((s, path.span())); + }}; + } + + match path.word_sym() { + Some(sym::alias) => self.parse_alias(cx, path, args), + Some(sym::hidden) => no_args!(hidden), + Some(sym::html_favicon_url) => string_arg!(html_favicon_url), + Some(sym::html_logo_url) => string_arg!(html_logo_url), + Some(sym::html_no_source) => no_args!(html_no_source), + Some(sym::html_playground_url) => string_arg!(html_playground_url), + Some(sym::html_root_url) => string_arg!(html_root_url), + Some(sym::issue_tracker_base_url) => string_arg!(issue_tracker_base_url), + Some(sym::inline) => self.parse_inline(cx, path, args, DocInline::Inline), + Some(sym::no_inline) => self.parse_inline(cx, path, args, DocInline::NoInline), + Some(sym::masked) => no_args!(masked), + Some(sym::cfg) => no_args!(cfg), + Some(sym::cfg_hide) => no_args!(cfg_hide), + Some(sym::notable_trait) => no_args!(notable_trait), + Some(sym::keyword) => self.parse_keyword(cx, path, args), + Some(sym::fake_variadic) => no_args!(fake_variadic), + Some(sym::search_unbox) => no_args!(search_unbox), + Some(sym::rust_logo) => no_args!(rust_logo), + Some(sym::test) => { + let Some(list) = args.list() else { + cx.expected_list(args.span().unwrap_or(path.span())); + return; + }; + + for i in list.mixed() { + match i { + MetaItemOrLitParser::MetaItemParser(mip) => { + self.parse_single_test_doc_attr_item(cx, mip); + } + MetaItemOrLitParser::Lit(lit) => { + cx.unexpected_literal(lit.span); + } + MetaItemOrLitParser::Err(..) => { + // already had an error here, move on. + } + } + } + + // let path = rustc_ast_pretty::pprust::path_to_string(&i_meta.path); + // if i_meta.has_name(sym::spotlight) { + // self.tcx.emit_node_span_lint( + // INVALID_DOC_ATTRIBUTES, + // hir_id, + // i_meta.span, + // errors::DocTestUnknownSpotlight { path, span: i_meta.span }, + // ); + // } else if i_meta.has_name(sym::include) + // && let Some(value) = i_meta.value_str() + // { + // let applicability = if list.len() == 1 { + // Applicability::MachineApplicable + // } else { + // Applicability::MaybeIncorrect + // }; + // // If there are multiple attributes, the suggestion would suggest + // // deleting all of them, which is incorrect. + // self.tcx.emit_node_span_lint( + // INVALID_DOC_ATTRIBUTES, + // hir_id, + // i_meta.span, + // errors::DocTestUnknownInclude { + // path, + // value: value.to_string(), + // inner: match attr.style() { + // AttrStyle::Inner => "!", + // AttrStyle::Outer => "", + // }, + // sugg: (attr.span(), applicability), + // }, + // ); + // } else if i_meta.has_name(sym::passes) || i_meta.has_name(sym::no_default_passes) { + // self.tcx.emit_node_span_lint( + // INVALID_DOC_ATTRIBUTES, + // hir_id, + // i_meta.span, + // errors::DocTestUnknownPasses { path, span: i_meta.span }, + // ); + // } else if i_meta.has_name(sym::plugins) { + // self.tcx.emit_node_span_lint( + // INVALID_DOC_ATTRIBUTES, + // hir_id, + // i_meta.span, + // errors::DocTestUnknownPlugins { path, span: i_meta.span }, + // ); + // } else { + // self.tcx.emit_node_span_lint( + // INVALID_DOC_ATTRIBUTES, + // hir_id, + // i_meta.span, + // errors::DocTestUnknownAny { path }, + // ); + // } + } + _ => { + cx.expected_specific_argument( + mip.span(), + [ + sym::alias.as_str(), + sym::hidden.as_str(), + sym::html_favicon_url.as_str(), + sym::html_logo_url.as_str(), + sym::html_no_source.as_str(), + sym::html_playground_url.as_str(), + sym::html_root_url.as_str(), + sym::inline.as_str(), + sym::no_inline.as_str(), + sym::test.as_str(), + ] + .to_vec(), + ); + } + } + } + + fn accept_single_doc_attr<'c, S: Stage>( + &mut self, + cx: &'c mut AcceptContext<'_, '_, S>, + args: &'c ArgParser<'_>, + ) { + match args { + ArgParser::NoArgs => { + todo!() + } + ArgParser::List(items) => { + for i in items.mixed() { + match i { + MetaItemOrLitParser::MetaItemParser(mip) => { + self.parse_single_doc_attr_item(cx, mip); + } + MetaItemOrLitParser::Lit(lit) => todo!("error should've used equals"), + MetaItemOrLitParser::Err(..) => { + // already had an error here, move on. + } + } + } + } + ArgParser::NameValue(v) => { + panic!("this should be rare if at all possible"); + } + } + } +} + +impl AttributeParser for DocParser { + const ATTRIBUTES: AcceptMapping = &[( + &[sym::doc], + template!(List: "hidden|inline|...", NameValueStr: "string"), + |this, cx, args| { + this.accept_single_doc_attr(cx, args); + }, + )]; + + fn finalize(self, cx: &FinalizeContext<'_, '_, S>) -> Option { + todo!() + } +} diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs index 65e0957ca900..584f62ca51a3 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs @@ -40,6 +40,7 @@ pub(crate) mod crate_level; pub(crate) mod debugger; pub(crate) mod deprecation; pub(crate) mod dummy; +pub(crate) mod doc; pub(crate) mod inline; pub(crate) mod link_attrs; pub(crate) mod lint_helpers; diff --git a/compiler/rustc_attr_parsing/src/attributes/util.rs b/compiler/rustc_attr_parsing/src/attributes/util.rs index 520fd9da7c2a..ce555be6a47d 100644 --- a/compiler/rustc_attr_parsing/src/attributes/util.rs +++ b/compiler/rustc_attr_parsing/src/attributes/util.rs @@ -32,35 +32,6 @@ pub fn is_builtin_attr(attr: &impl AttributeExt) -> bool { || attr.ident().is_some_and(|ident| is_builtin_attr_name(ident.name)) } -pub fn is_doc_alias_attrs_contain_symbol<'tcx, T: AttributeExt + 'tcx>( - attrs: impl Iterator, - symbol: Symbol, -) -> bool { - let doc_attrs = attrs.filter(|attr| attr.has_name(sym::doc)); - for attr in doc_attrs { - let Some(values) = attr.meta_item_list() else { - continue; - }; - let alias_values = values.iter().filter(|v| v.has_name(sym::alias)); - for v in alias_values { - if let Some(nested) = v.meta_item_list() { - // #[doc(alias("foo", "bar"))] - let mut iter = nested.iter().filter_map(|item| item.lit()).map(|item| item.symbol); - if iter.any(|s| s == symbol) { - return true; - } - } else if let Some(meta) = v.meta_item() - && let Some(lit) = meta.name_value_literal() - { - // #[doc(alias = "foo")] - if lit.symbol == symbol { - return true; - } - } - } - } - false -} /// Parse a single integer. /// @@ -121,3 +92,7 @@ impl AcceptContext<'_, '_, S> { None } } + +pub fn find_crate_name(attrs: &[impl AttributeExt]) -> Option { + first_attr_value_str_by_name(attrs, sym::crate_name) +} diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index bc74eaad50bc..af73bf7f9fd2 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -33,6 +33,7 @@ use crate::attributes::crate_level::{ }; use crate::attributes::debugger::DebuggerViualizerParser; use crate::attributes::deprecation::DeprecationParser; +use crate::attributes::doc::DocParser; use crate::attributes::dummy::DummyParser; use crate::attributes::inline::{InlineParser, RustcForceInlineParser}; use crate::attributes::link_attrs::{ @@ -162,7 +163,7 @@ attribute_parsers!( BodyStabilityParser, ConfusablesParser, ConstStabilityParser, - MacroUseParser, + NakedParser, StabilityParser, UsedParser, @@ -427,7 +428,7 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> { &self, span: Span, found: String, - options: &'static [&'static str], + options: &[&'static str], ) -> ErrorGuaranteed { self.emit_err(UnknownMetaItem { span, item: found, expected: options }) } diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index 2b3108a8d3ed..f122b5a87549 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -4,6 +4,7 @@ use rustc_ast::{self as ast}; use rustc_errors::codes::*; use rustc_errors::{ Applicability, Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, + MultiSpan, }; use rustc_feature::AttributeTemplate; use rustc_hir::AttrPath; @@ -34,6 +35,40 @@ pub(crate) struct InvalidPredicate { pub predicate: String, } +#[derive(Diagnostic)] +#[diag(attr_parsing_doc_alias_empty)] +pub(crate) struct DocAliasEmpty<'a> { + #[primary_span] + pub span: Span, + pub attr_str: &'a str, +} + +#[derive(Diagnostic)] +#[diag(attr_parsing_doc_alias_bad_char)] +pub(crate) struct DocAliasBadChar<'a> { + #[primary_span] + pub span: Span, + pub attr_str: &'a str, + pub char_: char, +} + +#[derive(Diagnostic)] +#[diag(attr_parsing_doc_alias_start_end)] +pub(crate) struct DocAliasStartEnd<'a> { + #[primary_span] + pub span: Span, + pub attr_str: &'a str, +} + +#[derive(Diagnostic)] +#[diag(attr_parsing_doc_keyword_not_keyword)] +#[help] +pub(crate) struct DocKeywordNotKeyword { + #[primary_span] + pub span: Span, + pub keyword: Symbol, +} + /// Error code: E0541 pub(crate) struct UnknownMetaItem<'a> { pub span: Span, @@ -538,6 +573,38 @@ pub(crate) struct NakedFunctionIncompatibleAttribute { pub attr: String, } +#[derive(LintDiagnostic)] +#[diag(attr_parsing_doc_alias_duplicated)] +pub(crate) struct DocAliasDuplicated { + #[label] + pub first_defn: Span, +} + +#[derive(Diagnostic)] +#[diag(attr_parsing_doc_inline_conflict)] +#[help] +pub(crate) struct DocKeywordConflict { + #[primary_span] + pub spans: MultiSpan, +} + + #[derive(Subdiagnostic)] + pub(crate) enum UnusedNote { + #[note(attr_parsing_unused_empty_lints_note)] + EmptyList { name: Symbol }, + #[note(attr_parsing_unused_no_lints_note)] + NoLints { name: Symbol }, + } + + #[derive(LintDiagnostic)] + #[diag(attr_parsing_unused)] + pub(crate) struct Unused { + #[suggestion(code = "", applicability = "machine-applicable")] + pub attr_span: Span, + #[subdiagnostic] + pub note: UnusedNote, + } + #[derive(Diagnostic)] #[diag(attr_parsing_link_ordinal_out_of_range)] #[note] diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index aff79d055838..538c866567a9 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -5,6 +5,7 @@ pub use ReprAttr::*; use rustc_abi::Align; use rustc_ast::token::CommentKind; use rustc_ast::{AttrStyle, ast}; +use rustc_data_structures::fx::FxIndexMap; use rustc_error_messages::{DiagArgValue, IntoDiagArg}; use rustc_macros::{Decodable, Encodable, HashStable_Generic, PrintAttribute}; use rustc_span::def_id::DefId; @@ -420,6 +421,70 @@ impl WindowsSubsystemKind { } } +#[derive(Copy, Clone, Debug, PartialEq)] +#[derive(HashStable_Generic, Encodable, Decodable, PrintAttribute)] +pub enum DocInline { + Inline, + NoInline, +} + +#[derive(Clone, Debug, HashStable_Generic, Encodable, Decodable, PrintAttribute)] +pub struct DocAttribute { + pub aliases: FxIndexMap, + pub hidden: Option, + pub inline: Option<(DocInline, Span)>, + + // unstable + pub cfg: Option, + pub cfg_hide: Option, + + // builtin + pub fake_variadic: Option, + pub keyword: Option<(Symbol, Span)>, + pub masked: Option, + pub notable_trait: Option, + pub search_unbox: Option, + + // valid on crate + pub html_favicon_url: Option<(Symbol, Span)>, + pub html_logo_url: Option<(Symbol, Span)>, + pub html_playground_url: Option<(Symbol, Span)>, + pub html_root_url: Option<(Symbol, Span)>, + pub html_no_source: Option, + pub issue_tracker_base_url: Option<(Symbol, Span)>, + pub rust_logo: Option, + + // #[doc(test(...))] + pub test_attrs: ThinVec<()>, + pub no_crate_inject: Option, +} + +impl Default for DocAttribute { + fn default() -> Self { + Self { + aliases: FxIndexMap::default(), + hidden: None, + inline: None, + cfg: None, + cfg_hide: None, + fake_variadic: None, + keyword: None, + masked: None, + notable_trait: None, + search_unbox: None, + html_favicon_url: None, + html_logo_url: None, + html_playground_url: None, + html_root_url: None, + html_no_source: None, + issue_tracker_base_url: None, + rust_logo: None, + test_attrs: ThinVec::new(), + no_crate_inject: None, + } + } +} + /// Represents parsed *built-in* inert attributes. /// /// ## Overview @@ -551,7 +616,13 @@ pub enum AttributeKind { /// Represents `#[rustc_do_not_implement_via_object]`. DoNotImplementViaObject(Span), - /// Represents [`#[doc = "..."]`](https://doc.rust-lang.org/stable/rustdoc/write-documentation/the-doc-attribute.html). + /// Represents [`#[doc]`](https://doc.rust-lang.org/stable/rustdoc/write-documentation/the-doc-attribute.html). + /// Represents all other uses of the [`#[doc]`](https://doc.rust-lang.org/stable/rustdoc/write-documentation/the-doc-attribute.html) + /// attribute. + Doc(Box), + + /// Represents specifically [`#[doc = "..."]`](https://doc.rust-lang.org/stable/rustdoc/write-documentation/the-doc-attribute.html). + /// i.e. doc comments. DocComment { style: AttrStyle, kind: CommentKind, span: Span, comment: Symbol }, /// Represents `#[rustc_dummy]`. diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs index a685eb99b833..ad120648c1ee 100644 --- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs +++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs @@ -40,6 +40,7 @@ impl AttributeKind { DenyExplicitImpl(..) => No, Deprecation { .. } => Yes, DoNotImplementViaObject(..) => No, + Doc(_) => Yes, DocComment { .. } => Yes, Dummy => No, ExportName { .. } => Yes, diff --git a/compiler/rustc_hir/src/attrs/pretty_printing.rs b/compiler/rustc_hir/src/attrs/pretty_printing.rs index ea86dfbd9c80..75886fb08a2e 100644 --- a/compiler/rustc_hir/src/attrs/pretty_printing.rs +++ b/compiler/rustc_hir/src/attrs/pretty_printing.rs @@ -4,6 +4,7 @@ use rustc_abi::Align; use rustc_ast::token::CommentKind; use rustc_ast::{AttrStyle, IntTy, UintTy}; use rustc_ast_pretty::pp::Printer; +use rustc_data_structures::fx::FxIndexMap; use rustc_span::hygiene::Transparency; use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol}; use rustc_target::spec::SanitizerSet; @@ -64,6 +65,25 @@ impl PrintAttribute for ThinVec { p.word("]"); } } +impl PrintAttribute for FxIndexMap { + fn should_render(&self) -> bool { + self.is_empty() || self[0].should_render() + } + + fn print_attribute(&self, p: &mut Printer) { + let mut last_printed = false; + p.word("["); + for (i, _) in self { + if last_printed { + p.word_space(","); + } + i.print_attribute(p); + last_printed = i.should_render(); + } + p.word("]"); + } +} + macro_rules! print_skip { ($($t: ty),* $(,)?) => {$( impl PrintAttribute for $t { diff --git a/compiler/rustc_hir/src/lints.rs b/compiler/rustc_hir/src/lints.rs index eba2d182d2c4..abffb9437a51 100644 --- a/compiler/rustc_hir/src/lints.rs +++ b/compiler/rustc_hir/src/lints.rs @@ -31,3 +31,45 @@ pub struct AttributeLint { pub span: Span, pub kind: AttributeLintKind, } + +#[derive(Debug, HashStable_Generic)] +pub enum AttributeLintKind { + /// Copy of `IllFormedAttributeInput` + /// specifically for the `invalid_macro_export_arguments` lint until that is removed, + /// see + InvalidMacroExportArguments { + suggestions: Vec, + }, + UnusedDuplicate { + this: Span, + other: Span, + warning: bool, + }, + IllFormedAttributeInput { + suggestions: Vec, + }, + EmptyAttribute { + first_span: Span, + attr_path: AttrPath, + valid_without_list: bool, + }, + InvalidTarget { + name: AttrPath, + target: Target, + applied: Vec, + only: &'static str, + }, + InvalidStyle { + name: AttrPath, + is_used_as_inner: bool, + target: Target, + target_span: Span, + }, + UnsafeAttrOutsideUnsafe { + attribute_name_span: Span, + sugg_spans: (Span, Span), + }, + DuplicateDocAlias { + first_definition: Span, + }, +} diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index a8457134031c..e4e892ab10f4 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -3,7 +3,7 @@ use std::cell::{Cell, RefCell}; use std::cmp::max; use std::ops::Deref; -use rustc_attr_parsing::is_doc_alias_attrs_contain_symbol; +use rustc_attr_data_structures::{AttributeKind, find_attr}; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::sso::SsoHashSet; use rustc_errors::Applicability; @@ -2535,7 +2535,9 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { let hir_id = self.fcx.tcx.local_def_id_to_hir_id(local_def_id); let attrs = self.fcx.tcx.hir_attrs(hir_id); - if is_doc_alias_attrs_contain_symbol(attrs.into_iter(), method.name) { + if let Some(d) = find_attr!(attrs, AttributeKind::Doc(d) => d) + && d.aliases.contains_key(&method.name) + { return true; } diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 70e91c081776..93cd9a9702f7 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -106,18 +106,9 @@ passes_diagnostic_diagnostic_on_unimplemented_only_for_traits = passes_diagnostic_item_first_defined = the diagnostic item is first defined here -passes_doc_alias_bad_char = - {$char_} character isn't allowed in {$attr_str} - passes_doc_alias_bad_location = {$attr_str} isn't allowed on {$location} -passes_doc_alias_duplicated = doc alias is duplicated - .label = first defined here - -passes_doc_alias_empty = - {$attr_str} attribute cannot have empty value - passes_doc_alias_malformed = doc alias attribute expects a string `#[doc(alias = "a")]` or a list of strings `#[doc(alias("a", "b"))]` @@ -127,17 +118,6 @@ passes_doc_alias_not_an_alias = passes_doc_alias_not_string_literal = `#[doc(alias("a"))]` expects string literals -passes_doc_alias_start_end = - {$attr_str} cannot start or end with ' ' - -passes_doc_attr_expects_no_value = - `doc({$attr_name})` does not accept a value - .suggestion = use `doc({$attr_name})` - -passes_doc_attr_expects_string = - `doc({$attr_name})` expects a string value - .suggestion = use `doc({$attr_name} = "...")` - passes_doc_attr_not_crate_level = `#![doc({$attr_name} = "...")]` isn't allowed as a crate-level attribute @@ -163,15 +143,7 @@ passes_doc_expect_str = passes_doc_fake_variadic_not_valid = `#[doc(fake_variadic)]` must be used on the first of a set of tuple or fn pointer trait impls with varying arity -passes_doc_inline_conflict = - conflicting doc inlining attributes - .help = remove one of the conflicting attributes -passes_doc_inline_conflict_first = - this attribute... - -passes_doc_inline_conflict_second = - {"."}..conflicts with this attribute passes_doc_inline_only_use = this attribute can only be applied to a `use` item @@ -188,10 +160,6 @@ passes_doc_keyword_attribute_empty_mod = passes_doc_keyword_attribute_not_mod = `#[doc({$attr_name} = "...")]` should be used on modules -passes_doc_keyword_not_keyword = - nonexistent keyword `{$keyword}` used in `#[doc(keyword = "...")]` - .help = only existing keywords are allowed in core/std - passes_doc_keyword_only_impl = `#[doc(keyword = "...")]` should be used on impl blocks diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 128986798715..1a48e4360d86 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -141,8 +141,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { target: Target, item: Option>, ) { - let mut doc_aliases = FxHashMap::default(); - let mut specified_inline = None; let mut seen = FxHashMap::default(); let attrs = self.tcx.hir_attrs(hir_id); for attr in attrs { @@ -306,15 +304,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.check_diagnostic_on_const(attr.span(), hir_id, target, item) } [sym::thread_local, ..] => self.check_thread_local(attr, span, target), - [sym::doc, ..] => self.check_doc_attrs( - attr, - attr.span(), - attr_item.style, - hir_id, - target, - &mut specified_inline, - &mut doc_aliases, - ), [sym::no_link, ..] => self.check_no_link(hir_id, attr, span, target), [sym::rustc_no_implicit_autorefs, ..] => { self.check_applied_to_fn_or_method(hir_id, attr.span(), span, target) @@ -786,38 +775,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.dcx().emit_err(errors::DocExpectStr { attr_span: meta.span(), attr_name }); } - fn check_doc_alias_value( - &self, - meta: &MetaItemInner, - doc_alias: Symbol, - hir_id: HirId, - target: Target, - is_list: bool, - aliases: &mut FxHashMap, - ) { + fn check_doc_alias_value(&self, span: Span, alias: Symbol, hir_id: HirId, target: Target) { let tcx = self.tcx; - let span = meta.name_value_literal_span().unwrap_or_else(|| meta.span()); - let attr_str = - &format!("`#[doc(alias{})]`", if is_list { "(\"...\")" } else { " = \"...\"" }); - if doc_alias == sym::empty { - tcx.dcx().emit_err(errors::DocAliasEmpty { span, attr_str }); - return; - } - let doc_alias_str = doc_alias.as_str(); - if let Some(c) = doc_alias_str - .chars() - .find(|&c| c == '"' || c == '\'' || (c.is_whitespace() && c != ' ')) - { - tcx.dcx().emit_err(errors::DocAliasBadChar { span, attr_str, char_: c }); - return; - } - if doc_alias_str.starts_with(' ') || doc_alias_str.ends_with(' ') { - tcx.dcx().emit_err(errors::DocAliasStartEnd { span, attr_str }); - return; - } - - let span = meta.span(); if let Some(location) = match target { Target::AssocTy => { if let DefKind::Impl { .. } = @@ -874,20 +834,11 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | Target::MacroCall | Target::Delegation { .. } => None, } { - tcx.dcx().emit_err(errors::DocAliasBadLocation { span, attr_str, location }); - return; - } - if self.tcx.hir_opt_name(hir_id) == Some(doc_alias) { - tcx.dcx().emit_err(errors::DocAliasNotAnAlias { span, attr_str }); - return; - } - if let Err(entry) = aliases.try_insert(doc_alias_str.to_owned(), span) { - self.tcx.emit_node_span_lint( - UNUSED_ATTRIBUTES, - hir_id, - span, - errors::DocAliasDuplicated { first_defn: *entry.entry.get() }, - ); + // FIXME: emit proper error + // tcx.dcx().emit_err(errors::DocAliasBadLocation { + // span, + // errors::DocAliasDuplicated { first_defn: *entry.entry.get() }, + // ); } } @@ -927,7 +878,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { fn check_doc_keyword_and_attribute( &self, - meta: &MetaItemInner, + span: Span, hir_id: HirId, attr_kind: DocFakeItemKind, ) { @@ -938,16 +889,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { s.is_reserved(|| edition::LATEST_STABLE_EDITION) || s.is_weak() || s == sym::SelfTy } - // FIXME: This should support attributes with namespace like `diagnostic::do_not_recommend`. - fn is_builtin_attr(s: Symbol) -> bool { - rustc_feature::BUILTIN_ATTRIBUTE_MAP.contains_key(&s) - } - - let value = match meta.value_str() { - Some(value) if value != sym::empty => value, - _ => return self.doc_attr_str_error(meta, attr_kind.name()), - }; - let item_kind = match self.tcx.hir_node(hir_id) { hir::Node::Item(item) => Some(&item.kind), _ => None, @@ -955,21 +896,17 @@ impl<'tcx> CheckAttrVisitor<'tcx> { match item_kind { Some(ItemKind::Mod(_, module)) => { if !module.item_ids.is_empty() { - self.dcx().emit_err(errors::DocKeywordAttributeEmptyMod { - span: meta.span(), - attr_name: attr_kind.name(), - }); + self.dcx() + .emit_err(errors::DocKeywordEmptyMod { span, attr_name: attr_kind.name() }); return; } } _ => { - self.dcx().emit_err(errors::DocKeywordAttributeNotMod { - span: meta.span(), - attr_name: attr_kind.name(), - }); + self.dcx().emit_err(errors::DocKeywordNotMod { span, attr_name: attr_kind.name() }); return; } } + match attr_kind { DocFakeItemKind::Keyword => { if !is_doc_keyword(value) { @@ -990,7 +927,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - fn check_doc_fake_variadic(&self, meta: &MetaItemInner, hir_id: HirId) { + fn check_doc_fake_variadic(&self, span: Span, hir_id: HirId) { let item_kind = match self.tcx.hir_node(hir_id) { hir::Node::Item(item) => Some(&item.kind), _ => None, @@ -1008,18 +945,18 @@ impl<'tcx> CheckAttrVisitor<'tcx> { false }; if !is_valid { - self.dcx().emit_err(errors::DocFakeVariadicNotValid { span: meta.span() }); + self.dcx().emit_err(errors::DocFakeVariadicNotValid { span }); } } _ => { - self.dcx().emit_err(errors::DocKeywordOnlyImpl { span: meta.span() }); + self.dcx().emit_err(errors::DocKeywordOnlyImpl { span }); } } } - fn check_doc_search_unbox(&self, meta: &MetaItemInner, hir_id: HirId) { + fn check_doc_search_unbox(&self, span: Span, hir_id: HirId) { let hir::Node::Item(item) = self.tcx.hir_node(hir_id) else { - self.dcx().emit_err(errors::DocSearchUnboxInvalid { span: meta.span() }); + self.dcx().emit_err(errors::DocSearchUnboxInvalid { span }); return; }; match item.kind { @@ -1032,7 +969,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { }) => {} ItemKind::TyAlias(_, generics, _) if generics.params.len() != 0 => {} _ => { - self.dcx().emit_err(errors::DocSearchUnboxInvalid { span: meta.span() }); + self.dcx().emit_err(errors::DocSearchUnboxInvalid { span }); } } } @@ -1046,60 +983,32 @@ impl<'tcx> CheckAttrVisitor<'tcx> { /// already seen an inlining attribute for this item. /// If so, `specified_inline` holds the value and the span of /// the first `inline`/`no_inline` attribute. - fn check_doc_inline( - &self, - style: AttrStyle, - meta: &MetaItemInner, - hir_id: HirId, - target: Target, - specified_inline: &mut Option<(bool, Span)>, - ) { + fn check_doc_inline(&self, span: Span, hir_id: HirId, target: Target) { match target { - Target::Use | Target::ExternCrate => { - let do_inline = meta.has_name(sym::inline); - if let Some((prev_inline, prev_span)) = *specified_inline { - if do_inline != prev_inline { - let mut spans = MultiSpan::from_spans(vec![prev_span, meta.span()]); - spans.push_span_label(prev_span, fluent::passes_doc_inline_conflict_first); - spans.push_span_label( - meta.span(), - fluent::passes_doc_inline_conflict_second, - ); - self.dcx().emit_err(errors::DocKeywordConflict { spans }); - } - } else { - *specified_inline = Some((do_inline, meta.span())); - } - } + Target::Use | Target::ExternCrate => {} _ => { self.tcx.emit_node_span_lint( INVALID_DOC_ATTRIBUTES, hir_id, - meta.span(), + span, errors::DocInlineOnlyUse { - attr_span: meta.span(), - item_span: (style == AttrStyle::Outer).then(|| self.tcx.hir_span(hir_id)), + attr_span: span, + item_span: self.tcx.hir_span(hir_id), }, ); } } } - fn check_doc_masked( - &self, - style: AttrStyle, - meta: &MetaItemInner, - hir_id: HirId, - target: Target, - ) { + fn check_doc_masked(&self, span: Span, hir_id: HirId, target: Target) { if target != Target::ExternCrate { self.tcx.emit_node_span_lint( INVALID_DOC_ATTRIBUTES, hir_id, - meta.span(), + span, errors::DocMaskedOnlyExternCrate { - attr_span: meta.span(), - item_span: (style == AttrStyle::Outer).then(|| self.tcx.hir_span(hir_id)), + attr_span: span, + item_span: self.tcx.hir_span(hir_id), }, ); return; @@ -1109,125 +1018,38 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.tcx.emit_node_span_lint( INVALID_DOC_ATTRIBUTES, hir_id, - meta.span(), + span, errors::DocMaskedNotExternCrateSelf { - attr_span: meta.span(), - item_span: (style == AttrStyle::Outer).then(|| self.tcx.hir_span(hir_id)), + attr_span: span, + item_span: self.tcx.hir_span(hir_id), }, ); } } /// Checks that an attribute is *not* used at the crate level. Returns `true` if valid. - fn check_attr_not_crate_level( - &self, - meta: &MetaItemInner, - hir_id: HirId, - attr_name: &str, - ) -> bool { + fn check_attr_not_crate_level(&self, span: Span, hir_id: HirId, attr_name: &str) -> bool { if CRATE_HIR_ID == hir_id { - self.dcx().emit_err(errors::DocAttrNotCrateLevel { span: meta.span(), attr_name }); + self.dcx().emit_err(errors::DocAttrNotCrateLevel { span, attr_name }); return false; } true } /// Checks that an attribute is used at the crate level. Returns `true` if valid. - fn check_attr_crate_level( - &self, - attr_span: Span, - style: AttrStyle, - meta: &MetaItemInner, - hir_id: HirId, - ) -> bool { + fn check_attr_crate_level(&self, span: Span, hir_id: HirId) -> bool { if hir_id != CRATE_HIR_ID { - // insert a bang between `#` and `[...` - let bang_span = attr_span.lo() + BytePos(1); - let sugg = (style == AttrStyle::Outer - && self.tcx.hir_get_parent_item(hir_id) == CRATE_OWNER_ID) - .then_some(errors::AttrCrateLevelOnlySugg { - attr: attr_span.with_lo(bang_span).with_hi(bang_span), - }); self.tcx.emit_node_span_lint( INVALID_DOC_ATTRIBUTES, hir_id, - meta.span(), - errors::AttrCrateLevelOnly { sugg }, + span, + errors::AttrCrateLevelOnly {}, ); return false; } true } - fn check_doc_attr_string_value(&self, meta: &MetaItemInner, hir_id: HirId) { - if meta.value_str().is_none() { - self.tcx.emit_node_span_lint( - INVALID_DOC_ATTRIBUTES, - hir_id, - meta.span(), - errors::DocAttrExpectsString { attr_name: meta.name().unwrap() }, - ); - } - } - - fn check_doc_attr_no_value(&self, meta: &MetaItemInner, hir_id: HirId) { - if !meta.is_word() { - self.tcx.emit_node_span_lint( - INVALID_DOC_ATTRIBUTES, - hir_id, - meta.span(), - errors::DocAttrExpectsNoValue { attr_name: meta.name().unwrap() }, - ); - } - } - - /// Checks that `doc(test(...))` attribute contains only valid attributes and are at the right place. - fn check_test_attr( - &self, - attr_span: Span, - style: AttrStyle, - meta: &MetaItemInner, - hir_id: HirId, - ) { - if let Some(metas) = meta.meta_item_list() { - for i_meta in metas { - match (i_meta.name(), i_meta.meta_item()) { - (Some(sym::attr), _) => { - // Allowed everywhere like `#[doc]` - } - (Some(sym::no_crate_inject), _) => { - self.check_attr_crate_level(attr_span, style, meta, hir_id); - } - (_, Some(m)) => { - self.tcx.emit_node_span_lint( - INVALID_DOC_ATTRIBUTES, - hir_id, - i_meta.span(), - errors::DocTestUnknown { - path: rustc_ast_pretty::pprust::path_to_string(&m.path), - }, - ); - } - (_, None) => { - self.tcx.emit_node_span_lint( - INVALID_DOC_ATTRIBUTES, - hir_id, - i_meta.span(), - errors::DocTestLiteral, - ); - } - } - } - } else { - self.tcx.emit_node_span_lint( - INVALID_DOC_ATTRIBUTES, - hir_id, - meta.span(), - errors::DocTestTakesList, - ); - } - } - /// Check that the `#![doc(auto_cfg)]` attribute has the expected input. fn check_doc_auto_cfg(&self, meta: &MetaItem, hir_id: HirId) { match &meta.kind { @@ -1290,173 +1112,118 @@ impl<'tcx> CheckAttrVisitor<'tcx> { /// of one item. Read the documentation of [`check_doc_inline`] for more information. /// /// [`check_doc_inline`]: Self::check_doc_inline - fn check_doc_attrs( - &self, - attr: &Attribute, - attr_span: Span, - style: AttrStyle, - hir_id: HirId, - target: Target, - specified_inline: &mut Option<(bool, Span)>, - aliases: &mut FxHashMap, - ) { - if let Some(list) = attr.meta_item_list() { - for meta in &list { - if let Some(i_meta) = meta.meta_item() { - match i_meta.name() { - Some(sym::alias) => { - if self.check_attr_not_crate_level(meta, hir_id, "alias") { - self.check_doc_alias(meta, hir_id, target, aliases); - } - } + fn check_doc_attrs(&self, attr: &DocAttribute, hir_id: HirId, target: Target) { + let DocAttribute { + aliases, + // valid pretty much anywhere, not checked here? + // FIXME: should we? + hidden: _, + inline, + // FIXME: currently unchecked + cfg: _, + cfg_hide, + fake_variadic, + keyword, + masked, + // FIXME: currently unchecked + notable_trait: _, + search_unbox, + html_favicon_url, + html_logo_url, + html_playground_url, + html_root_url, + html_no_source, + issue_tracker_base_url, + rust_logo, + // allowed anywhere + test_attrs: _, + no_crate_inject, + } = attr; - Some(sym::keyword) => { - if self.check_attr_not_crate_level(meta, hir_id, "keyword") { - self.check_doc_keyword_and_attribute( - meta, - hir_id, - DocFakeItemKind::Keyword, - ); - } - } - - Some(sym::attribute) => { - if self.check_attr_not_crate_level(meta, hir_id, "attribute") { - self.check_doc_keyword_and_attribute( - meta, - hir_id, - DocFakeItemKind::Attribute, - ); - } - } - - Some(sym::fake_variadic) => { - if self.check_attr_not_crate_level(meta, hir_id, "fake_variadic") { - self.check_doc_fake_variadic(meta, hir_id); - } - } - - Some(sym::search_unbox) => { - if self.check_attr_not_crate_level(meta, hir_id, "fake_variadic") { - self.check_doc_search_unbox(meta, hir_id); - } - } - - Some(sym::test) => { - self.check_test_attr(attr_span, style, meta, hir_id); - } - - Some( - sym::html_favicon_url - | sym::html_logo_url - | sym::html_playground_url - | sym::issue_tracker_base_url - | sym::html_root_url, - ) => { - self.check_attr_crate_level(attr_span, style, meta, hir_id); - self.check_doc_attr_string_value(meta, hir_id); - } - - Some(sym::html_no_source) => { - self.check_attr_crate_level(attr_span, style, meta, hir_id); - self.check_doc_attr_no_value(meta, hir_id); - } - - Some(sym::auto_cfg) => { - self.check_doc_auto_cfg(i_meta, hir_id); - } - - Some(sym::inline | sym::no_inline) => { - self.check_doc_inline(style, meta, hir_id, target, specified_inline) - } - - Some(sym::masked) => self.check_doc_masked(style, meta, hir_id, target), - - Some(sym::cfg | sym::hidden | sym::notable_trait) => {} - - Some(sym::rust_logo) => { - if self.check_attr_crate_level(attr_span, style, meta, hir_id) - && !self.tcx.features().rustdoc_internals() - { - feature_err( - &self.tcx.sess, - sym::rustdoc_internals, - meta.span(), - fluent::passes_doc_rust_logo, - ) - .emit(); - } - } - - _ => { - let path = rustc_ast_pretty::pprust::path_to_string(&i_meta.path); - if i_meta.has_name(sym::spotlight) { - self.tcx.emit_node_span_lint( - INVALID_DOC_ATTRIBUTES, - hir_id, - i_meta.span, - errors::DocTestUnknownSpotlight { path, span: i_meta.span }, - ); - } else if i_meta.has_name(sym::include) - && let Some(value) = i_meta.value_str() - { - let applicability = if list.len() == 1 { - Applicability::MachineApplicable - } else { - Applicability::MaybeIncorrect - }; - // If there are multiple attributes, the suggestion would suggest - // deleting all of them, which is incorrect. - self.tcx.emit_node_span_lint( - INVALID_DOC_ATTRIBUTES, - hir_id, - i_meta.span, - errors::DocTestUnknownInclude { - path, - value: value.to_string(), - inner: match style { - AttrStyle::Inner => "!", - AttrStyle::Outer => "", - }, - sugg: (attr.span(), applicability), - }, - ); - } else if i_meta.has_name(sym::passes) - || i_meta.has_name(sym::no_default_passes) - { - self.tcx.emit_node_span_lint( - INVALID_DOC_ATTRIBUTES, - hir_id, - i_meta.span, - errors::DocTestUnknownPasses { path, span: i_meta.span }, - ); - } else if i_meta.has_name(sym::plugins) { - self.tcx.emit_node_span_lint( - INVALID_DOC_ATTRIBUTES, - hir_id, - i_meta.span, - errors::DocTestUnknownPlugins { path, span: i_meta.span }, - ); - } else { - self.tcx.emit_node_span_lint( - INVALID_DOC_ATTRIBUTES, - hir_id, - i_meta.span, - errors::DocTestUnknownAny { path }, - ); - } - } - } - } else { - self.tcx.emit_node_span_lint( - INVALID_DOC_ATTRIBUTES, - hir_id, - meta.span(), - errors::DocInvalid, - ); - } + for (alias, span) in aliases { + if self.check_attr_not_crate_level(*span, hir_id, "alias") { + self.check_doc_alias_value(*span, *alias, hir_id, target); } } + + if let Some((_, span)) = keyword { + if self.check_attr_not_crate_level(*span, hir_id, "keyword") { + self.check_doc_keyword(*span, hir_id); + } + } + + // FIXME: check doc attribute + // self.check_doc_keyword(meta, hir_id); + // self.check_doc_keyword_and_attribute( + // meta, + // hir_id, + // DocFakeItemKind::Keyword, + // ); + // } + // } + // Some(sym::attribute) => { + // if self.check_attr_not_crate_level(meta, hir_id, "attribute") { + // self.check_doc_keyword_and_attribute( + // meta, + // hir_id, + // DocFakeItemKind::Attribute, + // ); + + if let Some(span) = fake_variadic { + if self.check_attr_not_crate_level(*span, hir_id, "fake_variadic") { + self.check_doc_fake_variadic(*span, hir_id); + } + } + + if let Some(span) = search_unbox { + if self.check_attr_not_crate_level(*span, hir_id, "search_unbox") { + self.check_doc_search_unbox(*span, hir_id); + } + } + + for i in [ + html_favicon_url, + html_logo_url, + html_playground_url, + issue_tracker_base_url, + html_root_url, + ] { + if let Some((_, span)) = i { + self.check_attr_crate_level(*span, hir_id); + } + } + + for i in [html_no_source, no_crate_inject] { + if let Some(span) = i { + self.check_attr_crate_level(*span, hir_id); + } + } + + if let Some((_, span)) = inline { + self.check_doc_inline(*span, hir_id, target) + } + + if let Some(span) = rust_logo { + if self.check_attr_crate_level(*span, hir_id) + && !self.tcx.features().rustdoc_internals() + { + feature_err( + &self.tcx.sess, + sym::rustdoc_internals, + *span, + fluent::passes_doc_rust_logo, + ) + .emit(); + } + } + + if let Some(span) = masked { + self.check_doc_masked(*span, hir_id, target); + } + + if let Some(span) = cfg_hide { + self.check_attr_crate_level(*span, hir_id); + } } fn check_has_incoherent_inherent_impls(&self, attr: &Attribute, span: Span, target: Target) { diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 6aa0f5212af7..926aba5082de 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -30,12 +30,6 @@ pub(crate) struct DocAttrExpectsString { pub(crate) attr_name: Symbol, } -#[derive(LintDiagnostic)] -#[diag(passes_doc_attr_expects_no_value)] -pub(crate) struct DocAttrExpectsNoValue { - pub(crate) attr_name: Symbol, -} - #[derive(Diagnostic)] #[diag(passes_autodiff_attr)] pub(crate) struct AutoDiffAttr { @@ -143,31 +137,6 @@ pub(crate) struct DocExpectStr<'a> { pub attr_name: &'a str, } -#[derive(Diagnostic)] -#[diag(passes_doc_alias_empty)] -pub(crate) struct DocAliasEmpty<'a> { - #[primary_span] - pub span: Span, - pub attr_str: &'a str, -} - -#[derive(Diagnostic)] -#[diag(passes_doc_alias_bad_char)] -pub(crate) struct DocAliasBadChar<'a> { - #[primary_span] - pub span: Span, - pub attr_str: &'a str, - pub char_: char, -} - -#[derive(Diagnostic)] -#[diag(passes_doc_alias_start_end)] -pub(crate) struct DocAliasStartEnd<'a> { - #[primary_span] - pub span: Span, - pub attr_str: &'a str, -} - #[derive(Diagnostic)] #[diag(passes_doc_alias_bad_location)] pub(crate) struct DocAliasBadLocation<'a> { @@ -185,13 +154,6 @@ pub(crate) struct DocAliasNotAnAlias<'a> { pub attr_str: &'a str, } -#[derive(LintDiagnostic)] -#[diag(passes_doc_alias_duplicated)] -pub(crate) struct DocAliasDuplicated { - #[label] - pub first_defn: Span, -} - #[derive(Diagnostic)] #[diag(passes_doc_alias_not_string_literal)] pub(crate) struct DocAliasNotStringLiteral { @@ -261,14 +223,6 @@ pub(crate) struct DocSearchUnboxInvalid { pub span: Span, } -#[derive(Diagnostic)] -#[diag(passes_doc_inline_conflict)] -#[help] -pub(crate) struct DocKeywordConflict { - #[primary_span] - pub spans: MultiSpan, -} - #[derive(LintDiagnostic)] #[diag(passes_doc_inline_only_use)] #[note] @@ -276,7 +230,7 @@ pub(crate) struct DocInlineOnlyUse { #[label] pub attr_span: Span, #[label(passes_not_a_use_item_label)] - pub item_span: Option, + pub item_span: Span, } #[derive(LintDiagnostic)] @@ -286,7 +240,7 @@ pub(crate) struct DocMaskedOnlyExternCrate { #[label] pub attr_span: Span, #[label(passes_not_an_extern_crate_label)] - pub item_span: Option, + pub item_span: Span, } #[derive(LintDiagnostic)] @@ -295,7 +249,7 @@ pub(crate) struct DocMaskedNotExternCrateSelf { #[label] pub attr_span: Span, #[label(passes_extern_crate_self_label)] - pub item_span: Option, + pub item_span: Span, } #[derive(Diagnostic)] @@ -1353,17 +1307,7 @@ pub(crate) struct IneffectiveUnstableImpl; #[derive(LintDiagnostic)] #[diag(passes_attr_crate_level)] #[note] -pub(crate) struct AttrCrateLevelOnly { - #[subdiagnostic] - pub sugg: Option, -} - -#[derive(Subdiagnostic)] -#[suggestion(passes_suggestion, applicability = "maybe-incorrect", code = "!", style = "verbose")] -pub(crate) struct AttrCrateLevelOnlySugg { - #[primary_span] - pub attr: Span, -} +pub(crate) struct AttrCrateLevelOnly {} /// "sanitize attribute not allowed here" #[derive(Diagnostic)] diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 71baef458bbf..a18913c1c1c7 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -10,7 +10,7 @@ use rustc_ast::{ Item, ItemKind, MethodCall, NodeId, Path, PathSegment, Ty, TyKind, }; use rustc_ast_pretty::pprust::where_bound_predicate_to_string; -use rustc_attr_parsing::is_doc_alias_attrs_contain_symbol; +use rustc_attr_data_structures::{AttributeKind, find_attr}; use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; use rustc_errors::codes::*; use rustc_errors::{ @@ -903,7 +903,9 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { // confused by them. continue; } - if is_doc_alias_attrs_contain_symbol(r.tcx.get_attrs(did, sym::doc), item_name) { + if let Some(d) = find_attr!(r.tcx.get_all_attrs(did), AttributeKind::Doc(d) => d) + && d.aliases.contains_key(&item_name) + { return Some(did); } } From 3f08e4dcd9ab5820c742a0b7f0a3f8fb32d1bd6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Sun, 22 Jun 2025 17:29:23 +0200 Subject: [PATCH 07/64] start using parsed doc attributes everywhere --- compiler/rustc_hir/src/hir.rs | 4 ---- compiler/rustc_lint/src/builtin.rs | 20 +++++--------------- 2 files changed, 5 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 6444c862d520..e8a91dae0749 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1376,7 +1376,6 @@ impl AttributeExt for Attribute { fn doc_str(&self) -> Option { match &self { Attribute::Parsed(AttributeKind::DocComment { comment, .. }) => Some(*comment), - Attribute::Unparsed(_) if self.has_name(sym::doc) => self.value_str(), _ => None, } } @@ -1391,9 +1390,6 @@ impl AttributeExt for Attribute { Attribute::Parsed(AttributeKind::DocComment { kind, comment, .. }) => { Some((*comment, *kind)) } - Attribute::Unparsed(_) if self.has_name(sym::doc) => { - self.value_str().map(|s| (s, CommentKind::Line)) - } _ => None, } } diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index dd0aa848ed2c..0805ef47079b 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -25,7 +25,7 @@ use rustc_attr_parsing::AttributeParser; use rustc_errors::{Applicability, LintDiagnostic}; use rustc_feature::GateIssue; use rustc_hir as hir; -use rustc_hir::attrs::AttributeKind; +use rustc_hir::attrs::{AttributeKind, DocAttribute}; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LocalDefId}; use rustc_hir::intravisit::FnKind as HirFnKind; @@ -396,26 +396,16 @@ pub struct MissingDoc; impl_lint_pass!(MissingDoc => [MISSING_DOCS]); fn has_doc(attr: &hir::Attribute) -> bool { - if attr.is_doc_comment().is_some() { + if matches!(attr, hir::Attribute::Parsed(AttributeKind::DocComment { .. })) { return true; } - if !attr.has_name(sym::doc) { - return false; - } - - if attr.value_str().is_some() { + if let hir::Attribute::Parsed(AttributeKind::Doc(d)) = attr + && matches!(d.as_ref(), DocAttribute { hidden: Some(..), .. }) + { return true; } - if let Some(list) = attr.meta_item_list() { - for meta in list { - if meta.has_name(sym::hidden) { - return true; - } - } - } - false } From acb32df7b11d55d11c155aa22d03eeb33a581961 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 23 Oct 2025 16:59:19 +0200 Subject: [PATCH 08/64] Continue migration to new Attribute API for `doc` attribute --- Cargo.lock | 2 - compiler/rustc_ast/src/attr/mod.rs | 8 + compiler/rustc_attr_parsing/messages.ftl | 55 +++ .../rustc_attr_parsing/src/attributes/cfg.rs | 2 +- .../rustc_attr_parsing/src/attributes/doc.rs | 439 ++++++++++++------ .../rustc_attr_parsing/src/attributes/mod.rs | 2 +- .../rustc_attr_parsing/src/attributes/util.rs | 7 +- compiler/rustc_attr_parsing/src/context.rs | 2 + compiler/rustc_attr_parsing/src/interface.rs | 11 - compiler/rustc_attr_parsing/src/lib.rs | 3 +- .../src/session_diagnostics.rs | 114 ++++- .../rustc_hir/src/attrs/data_structures.rs | 33 +- compiler/rustc_hir/src/hir.rs | 4 + compiler/rustc_hir/src/lints.rs | 28 +- compiler/rustc_hir_typeck/Cargo.toml | 1 - compiler/rustc_hir_typeck/src/lib.rs | 2 - compiler/rustc_hir_typeck/src/method/probe.rs | 4 +- compiler/rustc_lint/src/builtin.rs | 2 +- compiler/rustc_lint/src/levels.rs | 6 +- compiler/rustc_metadata/src/rmeta/encoder.rs | 17 +- compiler/rustc_middle/src/ty/util.rs | 12 +- compiler/rustc_passes/Cargo.toml | 1 - compiler/rustc_passes/messages.ftl | 63 +-- compiler/rustc_passes/src/check_attr.rs | 247 ++-------- compiler/rustc_passes/src/errors.rs | 135 +----- .../rustc_resolve/src/late/diagnostics.rs | 5 +- 26 files changed, 597 insertions(+), 608 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 03a4d71f67c3..bb81cada72ea 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4011,7 +4011,6 @@ dependencies = [ "itertools", "rustc_abi", "rustc_ast", - "rustc_attr_parsing", "rustc_data_structures", "rustc_errors", "rustc_fluent_macro", @@ -4433,7 +4432,6 @@ dependencies = [ "rustc_abi", "rustc_ast", "rustc_ast_lowering", - "rustc_ast_pretty", "rustc_attr_parsing", "rustc_data_structures", "rustc_errors", diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index 901b645b8c4e..d54d900128bd 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -220,6 +220,11 @@ impl AttributeExt for Attribute { fn is_automatically_derived_attr(&self) -> bool { self.has_name(sym::automatically_derived) } + + fn is_doc_hidden(&self) -> bool { + self.has_name(sym::doc) + && self.meta_item_list().is_some_and(|l| list_contains_name(&l, sym::hidden)) + } } impl Attribute { @@ -830,6 +835,9 @@ pub trait AttributeExt: Debug { /// commented module (for inner doc) vs within its parent module (for outer /// doc). fn doc_resolution_scope(&self) -> Option; + + /// Returns `true` if this attribute contains `doc(hidden)`. + fn is_doc_hidden(&self) -> bool; } // FIXME(fn_delegation): use function delegation instead of manually forwarding diff --git a/compiler/rustc_attr_parsing/messages.ftl b/compiler/rustc_attr_parsing/messages.ftl index 4482266c6c2e..4d7716560fb2 100644 --- a/compiler/rustc_attr_parsing/messages.ftl +++ b/compiler/rustc_attr_parsing/messages.ftl @@ -256,6 +256,10 @@ attr_parsing_doc_keyword_not_keyword = nonexistent keyword `{$keyword}` used in `#[doc(keyword = "...")]` .help = only existing keywords are allowed in core/std +attr_parsing_doc_attribute_not_attribute = + nonexistent builtin attribute `{$attribute}` used in `#[doc(attribute = "...")]` + .help = only existing builtin attributes are allowed in core/std + attr_parsing_doc_inline_conflict = conflicting doc inlining attributes .help = remove one of the conflicting attributes @@ -265,3 +269,54 @@ attr_parsing_doc_inline_conflict_first = attr_parsing_doc_inline_conflict_second = {"."}..conflicts with this attribute + +attr_parsing_doc_auto_cfg_expects_hide_or_show = + only `hide` or `show` are allowed in `#[doc(auto_cfg(...))]` + +attr_parsing_doc_auto_cfg_hide_show_unexpected_item = + `#![doc(auto_cfg({$attr_name}(...)))]` only accepts identifiers or key/value items + +attr_parsing_doc_auto_cfg_hide_show_expects_list = + `#![doc(auto_cfg({$attr_name}(...)))]` expects a list of items + +attr_parsing_doc_invalid = + invalid `doc` attribute + +attr_parsing_doc_unknown_include = + unknown `doc` attribute `include` + .suggestion = use `doc = include_str!` instead + +attr_parsing_doc_unknown_spotlight = + unknown `doc` attribute `spotlight` + .note = `doc(spotlight)` was renamed to `doc(notable_trait)` + .suggestion = use `notable_trait` instead + .no_op_note = `doc(spotlight)` is now a no-op + +attr_parsing_doc_unknown_passes = + unknown `doc` attribute `{$name}` + .note = `doc` attribute `{$name}` no longer functions; see issue #44136 + .label = no longer functions + .no_op_note = `doc({$name})` is now a no-op + +attr_parsing_doc_unknown_plugins = + unknown `doc` attribute `plugins` + .note = `doc` attribute `plugins` no longer functions; see issue #44136 and CVE-2018-1000622 + .label = no longer functions + .no_op_note = `doc(plugins)` is now a no-op + +attr_parsing_doc_unknown_any = + unknown `doc` attribute `{$name}` + +attr_parsing_doc_auto_cfg_wrong_literal = + expected boolean for `#[doc(auto_cfg = ...)]` + +attr_parsing_doc_test_takes_list = + `#[doc(test(...)]` takes a list of attributes + +attr_parsing_doc_test_unknown = + unknown `doc(test)` attribute `{$name}` + +attr_parsing_doc_test_literal = `#![doc(test(...)]` does not take a literal + +attr_parsing_doc_alias_malformed = + doc alias attribute expects a string `#[doc(alias = "a")]` or a list of strings `#[doc(alias("a", "b"))]` diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg.rs b/compiler/rustc_attr_parsing/src/attributes/cfg.rs index 490e28ed64c5..6ffe25098308 100644 --- a/compiler/rustc_attr_parsing/src/attributes/cfg.rs +++ b/compiler/rustc_attr_parsing/src/attributes/cfg.rs @@ -171,7 +171,7 @@ fn parse_cfg_entry_target( Ok(CfgEntry::All(result, list.span)) } -fn parse_name_value( +pub(crate) fn parse_name_value( name: Symbol, name_span: Span, value: Option<&NameValueParser>, diff --git a/compiler/rustc_attr_parsing/src/attributes/doc.rs b/compiler/rustc_attr_parsing/src/attributes/doc.rs index a5986170c192..65651e617179 100644 --- a/compiler/rustc_attr_parsing/src/attributes/doc.rs +++ b/compiler/rustc_attr_parsing/src/attributes/doc.rs @@ -1,20 +1,99 @@ -use rustc_attr_data_structures::lints::AttributeLintKind; -use rustc_attr_data_structures::{AttributeKind, DocAttribute, DocInline}; +// FIXME: to be removed +#![allow(unused_imports)] + +use rustc_ast::ast::{AttrStyle, LitKind, MetaItemLit}; +use rustc_ast::token::CommentKind; use rustc_errors::MultiSpan; use rustc_feature::template; +use rustc_hir::attrs::{ + AttributeKind, CfgEntry, CfgHideShow, CfgInfo, DocAttribute, DocInline, HideOrShow, +}; +use rustc_hir::lints::AttributeLintKind; use rustc_span::{Span, Symbol, edition, sym}; +use thin_vec::ThinVec; +use super::prelude::{Allow, AllowedTargets, MethodKind, Target}; use super::{AcceptMapping, AttributeParser}; use crate::context::{AcceptContext, FinalizeContext, Stage}; use crate::fluent_generated as fluent; use crate::parser::{ArgParser, MetaItemOrLitParser, MetaItemParser, PathParser}; use crate::session_diagnostics::{ - DocAliasBadChar, DocAliasEmpty, DocAliasStartEnd, DocKeywordConflict, DocKeywordNotKeyword, + DocAliasBadChar, DocAliasEmpty, DocAliasMalformed, DocAliasStartEnd, DocAttributeNotAttribute, + DocKeywordConflict, DocKeywordNotKeyword, }; -#[derive(Default)] +fn check_keyword(cx: &mut AcceptContext<'_, '_, S>, keyword: Symbol, span: Span) -> bool { + // FIXME: Once rustdoc can handle URL conflicts on case insensitive file systems, we + // can remove the `SelfTy` case here, remove `sym::SelfTy`, and update the + // `#[doc(keyword = "SelfTy")` attribute in `library/std/src/keyword_docs.rs`. + if keyword.is_reserved(|| edition::LATEST_STABLE_EDITION) + || keyword.is_weak() + || keyword == sym::SelfTy + { + return true; + } + cx.emit_err(DocKeywordNotKeyword { span, keyword }); + false +} + +fn check_attribute( + cx: &mut AcceptContext<'_, '_, S>, + attribute: Symbol, + span: Span, +) -> bool { + // FIXME: This should support attributes with namespace like `diagnostic::do_not_recommend`. + if rustc_feature::BUILTIN_ATTRIBUTE_MAP.contains_key(&attribute) { + return true; + } + cx.emit_err(DocAttributeNotAttribute { span, attribute }); + false +} + +fn parse_keyword_and_attribute<'c, S, F>( + cx: &'c mut AcceptContext<'_, '_, S>, + path: &PathParser<'_>, + args: &ArgParser<'_>, + attr_value: &mut Option<(Symbol, Span)>, + callback: F, +) where + S: Stage, + F: FnOnce(&mut AcceptContext<'_, '_, S>, Symbol, Span) -> bool, +{ + let Some(nv) = args.name_value() else { + cx.expected_name_value(args.span().unwrap_or(path.span()), path.word_sym()); + return; + }; + + let Some(value) = nv.value_as_str() else { + cx.expected_string_literal(nv.value_span, Some(nv.value_as_lit())); + return; + }; + + if !callback(cx, value, nv.value_span) { + return; + } + + if attr_value.is_some() { + cx.duplicate_key(path.span(), path.word_sym().unwrap()); + return; + } + + *attr_value = Some((value, path.span())); +} + +#[derive(Debug)] +struct DocComment { + style: AttrStyle, + kind: CommentKind, + span: Span, + comment: Symbol, +} + +#[derive(Default, Debug)] pub(crate) struct DocParser { attribute: DocAttribute, + nb_doc_attrs: usize, + doc_comment: Option, } impl DocParser { @@ -28,8 +107,8 @@ impl DocParser { match path.word_sym() { Some(sym::no_crate_inject) => { - if !args.no_args() { - cx.expected_no_args(args.span().unwrap()); + if let Err(span) = args.no_args() { + cx.expected_no_args(span); return; } @@ -42,17 +121,20 @@ impl DocParser { } Some(sym::attr) => { let Some(list) = args.list() else { - cx.expected_list(args.span().unwrap_or(path.span())); + cx.expected_list(cx.attr_span); return; }; - self.attribute.test_attrs.push(todo!()); + // FIXME: convert list into a Vec of `AttributeKind`. + for _ in list.mixed() { + // self.attribute.test_attrs.push(AttributeKind::parse()); + } } - _ => { - cx.expected_specific_argument( - mip.span(), - [sym::no_crate_inject.as_str(), sym::attr.as_str()].to_vec(), - ); + Some(name) => { + cx.emit_lint(AttributeLintKind::DocTestUnknown { name }, path.span()); + } + None => { + cx.emit_lint(AttributeLintKind::DocTestLiteral, path.span()); } } } @@ -98,7 +180,7 @@ impl DocParser { ) { match args { ArgParser::NoArgs => { - cx.expected_name_value(args.span().unwrap_or(path.span()), path.word_sym()); + cx.emit_err(DocAliasMalformed { span: args.span().unwrap_or(path.span()) }); } ArgParser::List(list) => { for i in list.mixed() { @@ -120,41 +202,6 @@ impl DocParser { } } - fn parse_keyword<'c, S: Stage>( - &mut self, - cx: &'c mut AcceptContext<'_, '_, S>, - path: &PathParser<'_>, - args: &ArgParser<'_>, - ) { - let Some(nv) = args.name_value() else { - cx.expected_name_value(args.span().unwrap_or(path.span()), path.word_sym()); - return; - }; - - let Some(keyword) = nv.value_as_str() else { - cx.expected_string_literal(nv.value_span, Some(nv.value_as_lit())); - return; - }; - - fn is_doc_keyword(s: Symbol) -> bool { - // FIXME: Once rustdoc can handle URL conflicts on case insensitive file systems, we - // can remove the `SelfTy` case here, remove `sym::SelfTy`, and update the - // `#[doc(keyword = "SelfTy")` attribute in `library/std/src/keyword_docs.rs`. - s.is_reserved(|| edition::LATEST_STABLE_EDITION) || s.is_weak() || s == sym::SelfTy - } - - if !is_doc_keyword(keyword) { - cx.emit_err(DocKeywordNotKeyword { span: nv.value_span, keyword }); - } - - if self.attribute.keyword.is_some() { - cx.duplicate_key(path.span(), path.word_sym().unwrap()); - return; - } - - self.attribute.keyword = Some((keyword, path.span())); - } - fn parse_inline<'c, S: Stage>( &mut self, cx: &'c mut AcceptContext<'_, '_, S>, @@ -162,8 +209,8 @@ impl DocParser { args: &ArgParser<'_>, inline: DocInline, ) { - if !args.no_args() { - cx.expected_no_args(args.span().unwrap()); + if let Err(span) = args.no_args() { + cx.expected_no_args(span); return; } @@ -182,6 +229,103 @@ impl DocParser { self.attribute.inline = Some((inline, span)); } + fn parse_cfg<'c, S: Stage>( + &mut self, + cx: &'c mut AcceptContext<'_, '_, S>, + args: &ArgParser<'_>, + ) { + if let Some(cfg_entry) = super::cfg::parse_cfg(cx, args) { + self.attribute.cfg = Some(cfg_entry); + } + } + + fn parse_auto_cfg<'c, S: Stage>( + &mut self, + cx: &'c mut AcceptContext<'_, '_, S>, + path: &PathParser<'_>, + args: &ArgParser<'_>, + ) { + match args { + ArgParser::NoArgs => { + cx.expected_list(args.span().unwrap_or(path.span())); + } + ArgParser::List(list) => { + for meta in list.mixed() { + let MetaItemOrLitParser::MetaItemParser(item) = meta else { + cx.emit_lint(AttributeLintKind::DocAutoCfgExpectsHideOrShow, meta.span()); + continue; + }; + let (kind, attr_name) = match item.path().word_sym() { + Some(sym::hide) => (HideOrShow::Hide, sym::hide), + Some(sym::show) => (HideOrShow::Show, sym::show), + _ => { + cx.emit_lint( + AttributeLintKind::DocAutoCfgExpectsHideOrShow, + item.span(), + ); + continue; + } + }; + let ArgParser::List(list) = item.args() else { + cx.emit_lint( + AttributeLintKind::DocAutoCfgHideShowExpectsList { attr_name }, + item.span(), + ); + continue; + }; + + let mut cfg_hide_show = CfgHideShow { kind, values: ThinVec::new() }; + + for item in list.mixed() { + let MetaItemOrLitParser::MetaItemParser(sub_item) = item else { + cx.emit_lint( + AttributeLintKind::DocAutoCfgHideShowUnexpectedItem { attr_name }, + item.span(), + ); + continue; + }; + match sub_item.args() { + a @ (ArgParser::NoArgs | ArgParser::NameValue(_)) => { + let Some(name) = sub_item.path().word_sym() else { + cx.expected_identifier(sub_item.path().span()); + continue; + }; + if let Ok(CfgEntry::NameValue { name, name_span, value, .. }) = + super::cfg::parse_name_value( + name, + sub_item.path().span(), + a.name_value(), + sub_item.span(), + cx, + ) + { + cfg_hide_show.values.push(CfgInfo { name, name_span, value }) + } + } + _ => { + cx.emit_lint( + AttributeLintKind::DocAutoCfgHideShowUnexpectedItem { + attr_name, + }, + sub_item.span(), + ); + continue; + } + } + } + } + } + ArgParser::NameValue(nv) => { + let MetaItemLit { kind: LitKind::Bool(bool_value), span, .. } = nv.value_as_lit() + else { + cx.emit_lint(AttributeLintKind::DocAutoCfgWrongLiteral, nv.value_span); + return; + }; + self.attribute.auto_cfg_change = Some((*bool_value, *span)); + } + } + } + fn parse_single_doc_attr_item<'c, S: Stage>( &mut self, cx: &'c mut AcceptContext<'_, '_, S>, @@ -192,8 +336,8 @@ impl DocParser { macro_rules! no_args { ($ident: ident) => {{ - if !args.no_args() { - cx.expected_no_args(args.span().unwrap()); + if let Err(span) = args.no_args() { + cx.expected_no_args(span); return; } @@ -217,10 +361,12 @@ impl DocParser { return; }; - if self.attribute.$ident.is_some() { - cx.duplicate_key(path.span(), path.word_sym().unwrap()); - return; - } + // FIXME: It's errorring when the attribute is passed multiple times on the command + // line. + // if self.attribute.$ident.is_some() { + // cx.duplicate_key(path.span(), path.word_sym().unwrap()); + // return; + // } self.attribute.$ident = Some((s, path.span())); }}; @@ -238,16 +384,32 @@ impl DocParser { Some(sym::inline) => self.parse_inline(cx, path, args, DocInline::Inline), Some(sym::no_inline) => self.parse_inline(cx, path, args, DocInline::NoInline), Some(sym::masked) => no_args!(masked), - Some(sym::cfg) => no_args!(cfg), - Some(sym::cfg_hide) => no_args!(cfg_hide), + Some(sym::cfg) => self.parse_cfg(cx, args), Some(sym::notable_trait) => no_args!(notable_trait), - Some(sym::keyword) => self.parse_keyword(cx, path, args), + Some(sym::keyword) => parse_keyword_and_attribute( + cx, + path, + args, + &mut self.attribute.keyword, + check_keyword, + ), + Some(sym::attribute) => parse_keyword_and_attribute( + cx, + path, + args, + &mut self.attribute.attribute, + check_attribute, + ), Some(sym::fake_variadic) => no_args!(fake_variadic), Some(sym::search_unbox) => no_args!(search_unbox), Some(sym::rust_logo) => no_args!(rust_logo), + Some(sym::auto_cfg) => self.parse_auto_cfg(cx, path, args), Some(sym::test) => { let Some(list) = args.list() else { - cx.expected_list(args.span().unwrap_or(path.span())); + cx.emit_lint( + AttributeLintKind::DocTestTakesList, + args.span().unwrap_or(path.span()), + ); return; }; @@ -264,80 +426,32 @@ impl DocParser { } } } - - // let path = rustc_ast_pretty::pprust::path_to_string(&i_meta.path); - // if i_meta.has_name(sym::spotlight) { - // self.tcx.emit_node_span_lint( - // INVALID_DOC_ATTRIBUTES, - // hir_id, - // i_meta.span, - // errors::DocTestUnknownSpotlight { path, span: i_meta.span }, - // ); - // } else if i_meta.has_name(sym::include) - // && let Some(value) = i_meta.value_str() - // { - // let applicability = if list.len() == 1 { - // Applicability::MachineApplicable - // } else { - // Applicability::MaybeIncorrect - // }; - // // If there are multiple attributes, the suggestion would suggest - // // deleting all of them, which is incorrect. - // self.tcx.emit_node_span_lint( - // INVALID_DOC_ATTRIBUTES, - // hir_id, - // i_meta.span, - // errors::DocTestUnknownInclude { - // path, - // value: value.to_string(), - // inner: match attr.style() { - // AttrStyle::Inner => "!", - // AttrStyle::Outer => "", - // }, - // sugg: (attr.span(), applicability), - // }, - // ); - // } else if i_meta.has_name(sym::passes) || i_meta.has_name(sym::no_default_passes) { - // self.tcx.emit_node_span_lint( - // INVALID_DOC_ATTRIBUTES, - // hir_id, - // i_meta.span, - // errors::DocTestUnknownPasses { path, span: i_meta.span }, - // ); - // } else if i_meta.has_name(sym::plugins) { - // self.tcx.emit_node_span_lint( - // INVALID_DOC_ATTRIBUTES, - // hir_id, - // i_meta.span, - // errors::DocTestUnknownPlugins { path, span: i_meta.span }, - // ); - // } else { - // self.tcx.emit_node_span_lint( - // INVALID_DOC_ATTRIBUTES, - // hir_id, - // i_meta.span, - // errors::DocTestUnknownAny { path }, - // ); - // } } - _ => { - cx.expected_specific_argument( - mip.span(), - [ - sym::alias.as_str(), - sym::hidden.as_str(), - sym::html_favicon_url.as_str(), - sym::html_logo_url.as_str(), - sym::html_no_source.as_str(), - sym::html_playground_url.as_str(), - sym::html_root_url.as_str(), - sym::inline.as_str(), - sym::no_inline.as_str(), - sym::test.as_str(), - ] - .to_vec(), + Some(sym::spotlight) => { + cx.emit_lint(AttributeLintKind::DocUnknownSpotlight, path.span()); + } + Some(sym::include) if let Some(nv) = args.name_value() => { + let inner = match cx.attr_style { + AttrStyle::Outer => "", + AttrStyle::Inner => "!", + }; + cx.emit_lint( + AttributeLintKind::DocUnknownInclude { inner, value: nv.value_as_lit().symbol }, + path.span(), ); } + Some(name @ (sym::passes | sym::no_default_passes)) => { + cx.emit_lint(AttributeLintKind::DocUnknownPasses { name }, path.span()); + } + Some(sym::plugins) => { + cx.emit_lint(AttributeLintKind::DocUnknownPlugins, path.span()); + } + Some(name) => { + cx.emit_lint(AttributeLintKind::DocUnknownAny { name }, path.span()); + } + None => { + // FIXME: is there anything to do in this case? + } } } @@ -354,17 +468,30 @@ impl DocParser { for i in items.mixed() { match i { MetaItemOrLitParser::MetaItemParser(mip) => { + self.nb_doc_attrs += 1; self.parse_single_doc_attr_item(cx, mip); } - MetaItemOrLitParser::Lit(lit) => todo!("error should've used equals"), + MetaItemOrLitParser::Lit(lit) => { + cx.expected_name_value(lit.span, None); + } MetaItemOrLitParser::Err(..) => { // already had an error here, move on. } } } } - ArgParser::NameValue(v) => { - panic!("this should be rare if at all possible"); + ArgParser::NameValue(nv) => { + let Some(comment) = nv.value_as_str() else { + cx.expected_string_literal(nv.value_span, Some(nv.value_as_lit())); + return; + }; + + self.doc_comment = Some(DocComment { + style: cx.attr_style, + kind: CommentKind::Block, + span: nv.value_span, + comment, + }); } } } @@ -373,13 +500,49 @@ impl DocParser { impl AttributeParser for DocParser { const ATTRIBUTES: AcceptMapping = &[( &[sym::doc], - template!(List: "hidden|inline|...", NameValueStr: "string"), + template!(List: &["hidden", "inline", "test"], NameValueStr: "string"), |this, cx, args| { this.accept_single_doc_attr(cx, args); }, )]; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + Allow(Target::ExternCrate), + Allow(Target::Use), + Allow(Target::Static), + Allow(Target::Const), + Allow(Target::Fn), + Allow(Target::Mod), + Allow(Target::ForeignMod), + Allow(Target::TyAlias), + Allow(Target::Enum), + Allow(Target::Variant), + Allow(Target::Struct), + Allow(Target::Field), + Allow(Target::Union), + Allow(Target::Trait), + Allow(Target::TraitAlias), + Allow(Target::Impl { of_trait: true }), + Allow(Target::Impl { of_trait: false }), + Allow(Target::AssocConst), + Allow(Target::Method(MethodKind::Inherent)), + Allow(Target::Method(MethodKind::Trait { body: true })), + Allow(Target::Method(MethodKind::Trait { body: false })), + Allow(Target::Method(MethodKind::TraitImpl)), + Allow(Target::AssocTy), + Allow(Target::ForeignFn), + Allow(Target::ForeignStatic), + Allow(Target::ForeignTy), + Allow(Target::MacroDef), + Allow(Target::Crate), + ]); - fn finalize(self, cx: &FinalizeContext<'_, '_, S>) -> Option { - todo!() + fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option { + if let Some(DocComment { style, kind, span, comment }) = self.doc_comment { + Some(AttributeKind::DocComment { style, kind, span, comment }) + } else if self.nb_doc_attrs != 0 { + Some(AttributeKind::Doc(Box::new(self.attribute))) + } else { + None + } } } diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs index 584f62ca51a3..64bcb02b0b74 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs @@ -39,8 +39,8 @@ pub(crate) mod confusables; pub(crate) mod crate_level; pub(crate) mod debugger; pub(crate) mod deprecation; -pub(crate) mod dummy; pub(crate) mod doc; +pub(crate) mod dummy; pub(crate) mod inline; pub(crate) mod link_attrs; pub(crate) mod lint_helpers; diff --git a/compiler/rustc_attr_parsing/src/attributes/util.rs b/compiler/rustc_attr_parsing/src/attributes/util.rs index ce555be6a47d..105f7164bf3b 100644 --- a/compiler/rustc_attr_parsing/src/attributes/util.rs +++ b/compiler/rustc_attr_parsing/src/attributes/util.rs @@ -5,7 +5,7 @@ use rustc_ast::attr::AttributeExt; use rustc_feature::is_builtin_attr_name; use rustc_hir::RustcVersion; use rustc_hir::limit::Limit; -use rustc_span::{Symbol, sym}; +use rustc_span::Symbol; use crate::context::{AcceptContext, Stage}; use crate::parser::{ArgParser, NameValueParser}; @@ -32,7 +32,6 @@ pub fn is_builtin_attr(attr: &impl AttributeExt) -> bool { || attr.ident().is_some_and(|ident| is_builtin_attr_name(ident.name)) } - /// Parse a single integer. /// /// Used by attributes that take a single integer as argument, such as @@ -92,7 +91,3 @@ impl AcceptContext<'_, '_, S> { None } } - -pub fn find_crate_name(attrs: &[impl AttributeExt]) -> Option { - first_attr_value_str_by_name(attrs, sym::crate_name) -} diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index af73bf7f9fd2..5d15588033fd 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -163,6 +163,8 @@ attribute_parsers!( BodyStabilityParser, ConfusablesParser, ConstStabilityParser, + DocParser, + MacroUseParser, NakedParser, StabilityParser, diff --git a/compiler/rustc_attr_parsing/src/interface.rs b/compiler/rustc_attr_parsing/src/interface.rs index b26a4a29cd2e..363e1fcac507 100644 --- a/compiler/rustc_attr_parsing/src/interface.rs +++ b/compiler/rustc_attr_parsing/src/interface.rs @@ -298,17 +298,6 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { comment: *symbol, })) } - // // FIXME: make doc attributes go through a proper attribute parser - // ast::AttrKind::Normal(n) if n.has_name(sym::doc) => { - // let p = GenericMetaItemParser::from_attr(&n, self.dcx()); - // - // attributes.push(Attribute::Parsed(AttributeKind::DocComment { - // style: attr.style, - // kind: CommentKind::Line, - // span: attr.span, - // comment: p.args().name_value(), - // })) - // } ast::AttrKind::Normal(n) => { attr_paths.push(PathParser(Cow::Borrowed(&n.item.path))); let attr_path = AttrPath::from_ast(&n.item.path, lower_span); diff --git a/compiler/rustc_attr_parsing/src/lib.rs b/compiler/rustc_attr_parsing/src/lib.rs index 7cef70f88e1c..37a3189f892e 100644 --- a/compiler/rustc_attr_parsing/src/lib.rs +++ b/compiler/rustc_attr_parsing/src/lib.rs @@ -80,6 +80,7 @@ #![feature(decl_macro)] #![recursion_limit = "256"] // tidy-alphabetical-end +#![feature(if_let_guard)] #[macro_use] /// All the individual attribute parsers for each of rustc's built-in attributes. @@ -107,7 +108,7 @@ pub use attributes::cfg::{ }; pub use attributes::cfg_old::*; pub use attributes::cfg_select::*; -pub use attributes::util::{is_builtin_attr, is_doc_alias_attrs_contain_symbol, parse_version}; +pub use attributes::util::{is_builtin_attr, parse_version}; pub use context::{Early, Late, OmitDoc, ShouldEmit}; pub use interface::AttributeParser; pub use session_diagnostics::ParsedDescription; diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index f122b5a87549..26b615448e3b 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -69,6 +69,15 @@ pub(crate) struct DocKeywordNotKeyword { pub keyword: Symbol, } +#[derive(Diagnostic)] +#[diag(attr_parsing_doc_attribute_not_attribute)] +#[help] +pub(crate) struct DocAttributeNotAttribute { + #[primary_span] + pub span: Span, + pub attribute: Symbol, +} + /// Error code: E0541 pub(crate) struct UnknownMetaItem<'a> { pub span: Span, @@ -588,23 +597,6 @@ pub(crate) struct DocKeywordConflict { pub spans: MultiSpan, } - #[derive(Subdiagnostic)] - pub(crate) enum UnusedNote { - #[note(attr_parsing_unused_empty_lints_note)] - EmptyList { name: Symbol }, - #[note(attr_parsing_unused_no_lints_note)] - NoLints { name: Symbol }, - } - - #[derive(LintDiagnostic)] - #[diag(attr_parsing_unused)] - pub(crate) struct Unused { - #[suggestion(code = "", applicability = "machine-applicable")] - pub attr_span: Span, - #[subdiagnostic] - pub note: UnusedNote, - } - #[derive(Diagnostic)] #[diag(attr_parsing_link_ordinal_out_of_range)] #[note] @@ -1011,3 +1003,91 @@ pub(crate) struct CfgAttrBadDelim { #[subdiagnostic] pub sugg: MetaBadDelimSugg, } + +#[derive(LintDiagnostic)] +#[diag(attr_parsing_doc_auto_cfg_expects_hide_or_show)] +pub(crate) struct DocAutoCfgExpectsHideOrShow; + +#[derive(LintDiagnostic)] +#[diag(attr_parsing_doc_auto_cfg_hide_show_unexpected_item)] +pub(crate) struct DocAutoCfgHideShowUnexpectedItem { + pub attr_name: Symbol, +} + +#[derive(LintDiagnostic)] +#[diag(attr_parsing_doc_auto_cfg_hide_show_expects_list)] +pub(crate) struct DocAutoCfgHideShowExpectsList { + pub attr_name: Symbol, +} + +#[derive(LintDiagnostic)] +#[diag(attr_parsing_doc_invalid)] +pub(crate) struct DocInvalid; + +#[derive(LintDiagnostic)] +#[diag(attr_parsing_doc_unknown_include)] +pub(crate) struct DocUnknownInclude { + pub inner: &'static str, + pub value: Symbol, + #[suggestion(code = "#{inner}[doc = include_str!(\"{value}\")]")] + pub sugg: (Span, Applicability), +} + +#[derive(LintDiagnostic)] +#[diag(attr_parsing_doc_unknown_spotlight)] +#[note] +#[note(attr_parsing_no_op_note)] +pub(crate) struct DocUnknownSpotlight { + #[suggestion(style = "short", applicability = "machine-applicable", code = "notable_trait")] + pub sugg_span: Span, +} + +#[derive(LintDiagnostic)] +#[diag(attr_parsing_doc_unknown_passes)] +#[note] +#[note(attr_parsing_no_op_note)] +pub(crate) struct DocUnknownPasses { + pub name: Symbol, + #[label] + pub note_span: Span, +} + +#[derive(LintDiagnostic)] +#[diag(attr_parsing_doc_unknown_plugins)] +#[note] +#[note(attr_parsing_no_op_note)] +pub(crate) struct DocUnknownPlugins { + #[label] + pub label_span: Span, +} + +#[derive(LintDiagnostic)] +#[diag(attr_parsing_doc_unknown_any)] +pub(crate) struct DocUnknownAny { + pub name: Symbol, +} + +#[derive(LintDiagnostic)] +#[diag(attr_parsing_doc_auto_cfg_wrong_literal)] +pub(crate) struct DocAutoCfgWrongLiteral; + +#[derive(LintDiagnostic)] +#[diag(attr_parsing_doc_test_takes_list)] +pub(crate) struct DocTestTakesList; + +#[derive(LintDiagnostic)] +#[diag(attr_parsing_doc_test_unknown)] +pub(crate) struct DocTestUnknown { + pub name: Symbol, +} + +#[derive(LintDiagnostic)] +#[diag(attr_parsing_doc_test_literal)] +pub(crate) struct DocTestLiteral; + +#[derive(Diagnostic)] +#[diag(attr_parsing_doc_alias_malformed)] +pub(crate) struct DocAliasMalformed { + #[primary_span] + pub span: Span, +} diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index 538c866567a9..39008914f9ef 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -428,6 +428,26 @@ pub enum DocInline { NoInline, } +#[derive(Copy, Clone, Debug, PartialEq)] +#[derive(HashStable_Generic, Encodable, Decodable, PrintAttribute)] +pub enum HideOrShow { + Hide, + Show, +} + +#[derive(Clone, Debug, HashStable_Generic, Encodable, Decodable, PrintAttribute)] +pub struct CfgInfo { + pub name: Symbol, + pub name_span: Span, + pub value: Option<(Symbol, Span)>, +} + +#[derive(Clone, Debug, HashStable_Generic, Encodable, Decodable, PrintAttribute)] +pub struct CfgHideShow { + pub kind: HideOrShow, + pub values: ThinVec, +} + #[derive(Clone, Debug, HashStable_Generic, Encodable, Decodable, PrintAttribute)] pub struct DocAttribute { pub aliases: FxIndexMap, @@ -435,12 +455,15 @@ pub struct DocAttribute { pub inline: Option<(DocInline, Span)>, // unstable - pub cfg: Option, - pub cfg_hide: Option, + pub cfg: Option, + pub auto_cfg: ThinVec, + /// This is for `#[doc(auto_cfg = false|true)]`. + pub auto_cfg_change: Option<(bool, Span)>, // builtin pub fake_variadic: Option, pub keyword: Option<(Symbol, Span)>, + pub attribute: Option<(Symbol, Span)>, pub masked: Option, pub notable_trait: Option, pub search_unbox: Option, @@ -455,7 +478,7 @@ pub struct DocAttribute { pub rust_logo: Option, // #[doc(test(...))] - pub test_attrs: ThinVec<()>, + pub test_attrs: ThinVec, pub no_crate_inject: Option, } @@ -466,9 +489,11 @@ impl Default for DocAttribute { hidden: None, inline: None, cfg: None, - cfg_hide: None, + auto_cfg: ThinVec::new(), + auto_cfg_change: None, fake_variadic: None, keyword: None, + attribute: None, masked: None, notable_trait: None, search_unbox: None, diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index e8a91dae0749..e6a0f430b63a 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1414,6 +1414,10 @@ impl AttributeExt for Attribute { ) ) } + + fn is_doc_hidden(&self) -> bool { + matches!(self, Attribute::Parsed(AttributeKind::Doc(d)) if d.hidden.is_some()) + } } // FIXME(fn_delegation): use function delegation instead of manually forwarding diff --git a/compiler/rustc_hir/src/lints.rs b/compiler/rustc_hir/src/lints.rs index abffb9437a51..2d13ceabf8ca 100644 --- a/compiler/rustc_hir/src/lints.rs +++ b/compiler/rustc_hir/src/lints.rs @@ -2,7 +2,7 @@ use rustc_data_structures::fingerprint::Fingerprint; pub use rustc_lint_defs::AttributeLintKind; use rustc_lint_defs::LintId; use rustc_macros::HashStable_Generic; -use rustc_span::Span; +use rustc_span::{Span, Symbol}; use crate::HirId; @@ -72,4 +72,30 @@ pub enum AttributeLintKind { DuplicateDocAlias { first_definition: Span, }, + DocAutoCfgExpectsHideOrShow, + DocAutoCfgHideShowUnexpectedItem { + attr_name: Symbol, + }, + DocAutoCfgHideShowExpectsList { + attr_name: Symbol, + }, + DocInvalid, + DocUnknownInclude { + inner: &'static str, + value: Symbol, + }, + DocUnknownSpotlight, + DocUnknownPasses { + name: Symbol, + }, + DocUnknownPlugins, + DocUnknownAny { + name: Symbol, + }, + DocAutoCfgWrongLiteral, + DocTestTakesList, + DocTestUnknown { + name: Symbol, + }, + DocTestLiteral, } diff --git a/compiler/rustc_hir_typeck/Cargo.toml b/compiler/rustc_hir_typeck/Cargo.toml index f00125c3e090..246134665174 100644 --- a/compiler/rustc_hir_typeck/Cargo.toml +++ b/compiler/rustc_hir_typeck/Cargo.toml @@ -8,7 +8,6 @@ edition = "2024" itertools = "0.12" rustc_abi = { path = "../rustc_abi" } rustc_ast = { path = "../rustc_ast" } -rustc_attr_parsing = { path = "../rustc_attr_parsing" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_fluent_macro = { path = "../rustc_fluent_macro" } diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index 734d8963d6fd..d3ef1d63e8ba 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -1,6 +1,4 @@ // tidy-alphabetical-start -#![allow(rustc::diagnostic_outside_of_impl)] -#![allow(rustc::untranslatable_diagnostic)] #![feature(assert_matches)] #![feature(box_patterns)] #![feature(if_let_guard)] diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index e4e892ab10f4..1a25f6a582f2 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -3,12 +3,12 @@ use std::cell::{Cell, RefCell}; use std::cmp::max; use std::ops::Deref; -use rustc_attr_data_structures::{AttributeKind, find_attr}; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::sso::SsoHashSet; use rustc_errors::Applicability; +use rustc_hir::attrs::AttributeKind; use rustc_hir::def::DefKind; -use rustc_hir::{self as hir, ExprKind, HirId, Node}; +use rustc_hir::{self as hir, ExprKind, HirId, Node, find_attr}; use rustc_hir_analysis::autoderef::{self, Autoderef}; use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse}; use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes, InferOk, TyCtxtInferExt}; diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 0805ef47079b..ae973a3c49c2 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -825,7 +825,7 @@ fn warn_if_doc(cx: &EarlyContext<'_>, node_span: Span, node_kind: &str, attrs: & let span = sugared_span.take().unwrap_or(attr.span); - if is_doc_comment || attr.has_name(sym::doc) { + if is_doc_comment { let sub = match attr.kind { AttrKind::DocComment(CommentKind::Line, _) | AttrKind::Normal(..) => { BuiltinUnusedDocCommentSub::PlainHelp diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index ac47897b5688..0f6452a2bc99 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -657,11 +657,7 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { } // `#[doc(hidden)]` disables missing_docs check. - if attr.has_name(sym::doc) - && attr - .meta_item_list() - .is_some_and(|l| ast::attr::list_contains_name(&l, sym::hidden)) - { + if attr.is_doc_hidden() { self.insert( LintId::of(MISSING_DOCS), LevelAndSource { diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 86719581a209..9a1cf7f349fd 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -870,25 +870,20 @@ fn analyze_attr(attr: &hir::Attribute, state: &mut AnalyzeAttrState<'_>) -> bool && !rustc_feature::encode_cross_crate(name) { // Attributes not marked encode-cross-crate don't need to be encoded for downstream crates. - } else if attr.doc_str().is_some() { + } else if let hir::Attribute::Parsed(AttributeKind::DocComment { .. }) = attr { // We keep all doc comments reachable to rustdoc because they might be "imported" into // downstream crates if they use `#[doc(inline)]` to copy an item's documentation into // their own. if state.is_exported { should_encode = true; } - } else if attr.has_name(sym::doc) { + } else if let hir::Attribute::Parsed(AttributeKind::Doc(d)) = attr { // If this is a `doc` attribute that doesn't have anything except maybe `inline` (as in // `#[doc(inline)]`), then we can remove it. It won't be inlinable in downstream crates. - if let Some(item_list) = attr.meta_item_list() { - for item in item_list { - if !item.has_name(sym::inline) { - should_encode = true; - if item.has_name(sym::hidden) { - state.is_doc_hidden = true; - break; - } - } + if d.inline.is_none() { + should_encode = true; + if d.hidden.is_some() { + state.is_doc_hidden = true; } } } else if let &[sym::diagnostic, seg] = &*attr.path() { diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 782ea3906ef1..fc03ad52b4bf 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -4,12 +4,14 @@ use std::{fmt, iter}; use rustc_abi::{Float, Integer, IntegerType, Size}; use rustc_apfloat::Float as _; +use rustc_ast::attr::AttributeExt; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::ErrorGuaranteed; use rustc_hashes::Hash128; use rustc_hir as hir; +use rustc_hir::attrs::AttributeKind; use rustc_hir::def::{CtorOf, DefKind, Res}; use rustc_hir::def_id::{CrateNum, DefId, LocalDefId}; use rustc_hir::limit::Limit; @@ -1664,16 +1666,14 @@ pub fn reveal_opaque_types_in_bounds<'tcx>( /// Determines whether an item is directly annotated with `doc(hidden)`. fn is_doc_hidden(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { - tcx.get_attrs(def_id, sym::doc) - .filter_map(|attr| attr.meta_item_list()) - .any(|items| items.iter().any(|item| item.has_name(sym::hidden))) + let attrs = tcx.hir_attrs(tcx.local_def_id_to_hir_id(def_id)); + attrs.iter().any(|attr| attr.is_doc_hidden()) } /// Determines whether an item is annotated with `doc(notable_trait)`. pub fn is_doc_notable_trait(tcx: TyCtxt<'_>, def_id: DefId) -> bool { - tcx.get_attrs(def_id, sym::doc) - .filter_map(|attr| attr.meta_item_list()) - .any(|items| items.iter().any(|item| item.has_name(sym::notable_trait))) + let attrs = tcx.get_all_attrs(def_id); + attrs.iter().any(|attr| matches!(attr, hir::Attribute::Parsed(AttributeKind::Doc(doc)) if doc.notable_trait.is_some())) } /// Determines whether an item is an intrinsic (which may be via Abi or via the `rustc_intrinsic` attribute). diff --git a/compiler/rustc_passes/Cargo.toml b/compiler/rustc_passes/Cargo.toml index ba81ef3103bd..10da57f56ecf 100644 --- a/compiler/rustc_passes/Cargo.toml +++ b/compiler/rustc_passes/Cargo.toml @@ -8,7 +8,6 @@ edition = "2024" rustc_abi = { path = "../rustc_abi" } rustc_ast = { path = "../rustc_ast" } rustc_ast_lowering = { path = "../rustc_ast_lowering" } -rustc_ast_pretty = { path = "../rustc_ast_pretty" } rustc_attr_parsing = { path = "../rustc_attr_parsing" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 93cd9a9702f7..007ce22c01e6 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -107,39 +107,14 @@ passes_diagnostic_item_first_defined = the diagnostic item is first defined here passes_doc_alias_bad_location = - {$attr_str} isn't allowed on {$location} - -passes_doc_alias_malformed = - doc alias attribute expects a string `#[doc(alias = "a")]` or a list of strings `#[doc(alias("a", "b"))]` + doc alias attribute isn't allowed on {$location} passes_doc_alias_not_an_alias = {$attr_str} is the same as the item's name -passes_doc_alias_not_string_literal = - `#[doc(alias("a"))]` expects string literals - passes_doc_attr_not_crate_level = `#![doc({$attr_name} = "...")]` isn't allowed as a crate-level attribute -passes_doc_attribute_not_attribute = - nonexistent builtin attribute `{$attribute}` used in `#[doc(attribute = "...")]` - .help = only existing builtin attributes are allowed in core/std - -passes_doc_auto_cfg_expects_hide_or_show = - only `hide` or `show` are allowed in `#[doc(auto_cfg(...))]` - -passes_doc_auto_cfg_hide_show_expects_list = - `#![doc(auto_cfg({$attr_name}(...)))]` expects a list of items - -passes_doc_auto_cfg_hide_show_unexpected_item = - `#![doc(auto_cfg({$attr_name}(...)))]` only accepts identifiers or key/value items - -passes_doc_auto_cfg_wrong_literal = - expected boolean for `#[doc(auto_cfg = ...)]` - -passes_doc_expect_str = - doc {$attr_name} attribute expects a string: #[doc({$attr_name} = "a")] - passes_doc_fake_variadic_not_valid = `#[doc(fake_variadic)]` must be used on the first of a set of tuple or fn pointer trait impls with varying arity @@ -151,9 +126,6 @@ passes_doc_inline_only_use = .not_a_use_item_label = not a `use` item .note = read for more information -passes_doc_invalid = - invalid `doc` attribute - passes_doc_keyword_attribute_empty_mod = `#[doc({$attr_name} = "...")]` should be used on empty modules @@ -180,39 +152,6 @@ passes_doc_rust_logo = passes_doc_search_unbox_invalid = `#[doc(search_unbox)]` should be used on generic structs and enums -passes_doc_test_literal = `#![doc(test(...)]` does not take a literal - -passes_doc_test_takes_list = - `#[doc(test(...)]` takes a list of attributes - -passes_doc_test_unknown = - unknown `doc(test)` attribute `{$path}` - -passes_doc_test_unknown_any = - unknown `doc` attribute `{$path}` - -passes_doc_test_unknown_include = - unknown `doc` attribute `{$path}` - .suggestion = use `doc = include_str!` instead - -passes_doc_test_unknown_passes = - unknown `doc` attribute `{$path}` - .note = `doc` attribute `{$path}` no longer functions; see issue #44136 - .label = no longer functions - .no_op_note = `doc({$path})` is now a no-op - -passes_doc_test_unknown_plugins = - unknown `doc` attribute `{$path}` - .note = `doc` attribute `{$path}` no longer functions; see issue #44136 and CVE-2018-1000622 - .label = no longer functions - .no_op_note = `doc({$path})` is now a no-op - -passes_doc_test_unknown_spotlight = - unknown `doc` attribute `{$path}` - .note = `doc(spotlight)` was renamed to `doc(notable_trait)` - .suggestion = use `notable_trait` instead - .no_op_note = `doc(spotlight)` is now a no-op - passes_duplicate_diagnostic_item_in_crate = duplicate diagnostic item in crate `{$crate_name}`: `{$name}` .note = the diagnostic item is first defined in crate `{$orig_crate_name}` diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 1a48e4360d86..bae15de4bf88 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -10,22 +10,24 @@ use std::collections::hash_map::Entry; use std::slice; use rustc_abi::{Align, ExternAbi, Size}; -use rustc_ast::{AttrStyle, LitKind, MetaItem, MetaItemInner, MetaItemKind, ast}; +use rustc_ast::{AttrStyle, LitKind, MetaItemKind, ast}; use rustc_attr_parsing::{AttributeParser, Late}; use rustc_data_structures::fx::FxHashMap; -use rustc_errors::{Applicability, DiagCtxtHandle, IntoDiagArg, MultiSpan, StashKey}; +use rustc_errors::{DiagCtxtHandle, IntoDiagArg, StashKey}; use rustc_feature::{ ACCEPTED_LANG_FEATURES, AttributeDuplicates, AttributeType, BUILTIN_ATTRIBUTE_MAP, BuiltinAttribute, }; -use rustc_hir::attrs::{AttributeKind, InlineAttr, MirDialect, MirPhase, ReprAttr, SanitizerSet}; +use rustc_hir::attrs::{ + AttributeKind, DocAttribute, InlineAttr, MirDialect, MirPhase, ReprAttr, SanitizerSet, +}; use rustc_hir::def::DefKind; use rustc_hir::def_id::LocalModDefId; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{ - self as hir, Attribute, CRATE_HIR_ID, CRATE_OWNER_ID, Constness, FnSig, ForeignItem, HirId, - Item, ItemKind, MethodKind, PartialConstStability, Safety, Stability, StabilityLevel, Target, - TraitItem, find_attr, + self as hir, Attribute, CRATE_HIR_ID, Constness, FnSig, ForeignItem, HirId, Item, ItemKind, + MethodKind, PartialConstStability, Safety, Stability, StabilityLevel, Target, TraitItem, + find_attr, }; use rustc_macros::LintDiagnostic; use rustc_middle::hir::nested_filter; @@ -43,7 +45,7 @@ use rustc_session::lint::builtin::{ }; use rustc_session::parse::feature_err; use rustc_span::edition::Edition; -use rustc_span::{BytePos, DUMMY_SP, Span, Symbol, edition, sym}; +use rustc_span::{BytePos, DUMMY_SP, Span, Symbol, sym}; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::infer::{TyCtxtInferExt, ValuePairs}; use rustc_trait_selection::traits::ObligationCtxt; @@ -106,21 +108,6 @@ impl IntoDiagArg for ProcMacroKind { } } -#[derive(Clone, Copy)] -enum DocFakeItemKind { - Attribute, - Keyword, -} - -impl DocFakeItemKind { - fn name(self) -> &'static str { - match self { - Self::Attribute => "attribute", - Self::Keyword => "keyword", - } - } -} - struct CheckAttrVisitor<'tcx> { tcx: TyCtxt<'tcx>, @@ -223,6 +210,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { Attribute::Parsed(AttributeKind::MacroExport { span, .. }) => { self.check_macro_export(hir_id, *span, target) }, + Attribute::Parsed(AttributeKind::Doc(attr)) => self.check_doc_attrs(attr, hir_id, target), Attribute::Parsed( AttributeKind::BodyStability { .. } | AttributeKind::ConstStabilityIndirect @@ -771,13 +759,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - fn doc_attr_str_error(&self, meta: &MetaItemInner, attr_name: &str) { - self.dcx().emit_err(errors::DocExpectStr { attr_span: meta.span(), attr_name }); - } - - fn check_doc_alias_value(&self, span: Span, alias: Symbol, hir_id: HirId, target: Target) { - let tcx = self.tcx; - + fn check_doc_alias_value(&self, span: Span, hir_id: HirId, target: Target, alias: Symbol) { if let Some(location) = match target { Target::AssocTy => { if let DefKind::Impl { .. } = @@ -834,96 +816,12 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | Target::MacroCall | Target::Delegation { .. } => None, } { - // FIXME: emit proper error - // tcx.dcx().emit_err(errors::DocAliasBadLocation { - // span, - // errors::DocAliasDuplicated { first_defn: *entry.entry.get() }, - // ); + self.tcx.dcx().emit_err(errors::DocAliasBadLocation { span, location }); + return; } - } - - fn check_doc_alias( - &self, - meta: &MetaItemInner, - hir_id: HirId, - target: Target, - aliases: &mut FxHashMap, - ) { - if let Some(values) = meta.meta_item_list() { - for v in values { - match v.lit() { - Some(l) => match l.kind { - LitKind::Str(s, _) => { - self.check_doc_alias_value(v, s, hir_id, target, true, aliases); - } - _ => { - self.tcx - .dcx() - .emit_err(errors::DocAliasNotStringLiteral { span: v.span() }); - } - }, - None => { - self.tcx - .dcx() - .emit_err(errors::DocAliasNotStringLiteral { span: v.span() }); - } - } - } - } else if let Some(doc_alias) = meta.value_str() { - self.check_doc_alias_value(meta, doc_alias, hir_id, target, false, aliases) - } else { - self.dcx().emit_err(errors::DocAliasMalformed { span: meta.span() }); - } - } - - fn check_doc_keyword_and_attribute( - &self, - span: Span, - hir_id: HirId, - attr_kind: DocFakeItemKind, - ) { - fn is_doc_keyword(s: Symbol) -> bool { - // FIXME: Once rustdoc can handle URL conflicts on case insensitive file systems, we - // can remove the `SelfTy` case here, remove `sym::SelfTy`, and update the - // `#[doc(keyword = "SelfTy")` attribute in `library/std/src/keyword_docs.rs`. - s.is_reserved(|| edition::LATEST_STABLE_EDITION) || s.is_weak() || s == sym::SelfTy - } - - let item_kind = match self.tcx.hir_node(hir_id) { - hir::Node::Item(item) => Some(&item.kind), - _ => None, - }; - match item_kind { - Some(ItemKind::Mod(_, module)) => { - if !module.item_ids.is_empty() { - self.dcx() - .emit_err(errors::DocKeywordEmptyMod { span, attr_name: attr_kind.name() }); - return; - } - } - _ => { - self.dcx().emit_err(errors::DocKeywordNotMod { span, attr_name: attr_kind.name() }); - return; - } - } - - match attr_kind { - DocFakeItemKind::Keyword => { - if !is_doc_keyword(value) { - self.dcx().emit_err(errors::DocKeywordNotKeyword { - span: meta.name_value_literal_span().unwrap_or_else(|| meta.span()), - keyword: value, - }); - } - } - DocFakeItemKind::Attribute => { - if !is_builtin_attr(value) { - self.dcx().emit_err(errors::DocAttributeNotAttribute { - span: meta.name_value_literal_span().unwrap_or_else(|| meta.span()), - attribute: value, - }); - } - } + if self.tcx.hir_opt_name(hir_id) == Some(alias) { + self.tcx.dcx().emit_err(errors::DocAliasNotAnAlias { span, attr_str: alias }); + return; } } @@ -1027,6 +925,25 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } + fn check_doc_keyword_and_attribute(&self, span: Span, hir_id: HirId, attr_name: &'static str) { + let item_kind = match self.tcx.hir_node(hir_id) { + hir::Node::Item(item) => Some(&item.kind), + _ => None, + }; + match item_kind { + Some(ItemKind::Mod(_, module)) => { + if !module.item_ids.is_empty() { + self.dcx().emit_err(errors::DocKeywordAttributeEmptyMod { span, attr_name }); + return; + } + } + _ => { + self.dcx().emit_err(errors::DocKeywordAttributeNotMod { span, attr_name }); + return; + } + } + } + /// Checks that an attribute is *not* used at the crate level. Returns `true` if valid. fn check_attr_not_crate_level(&self, span: Span, hir_id: HirId, attr_name: &str) -> bool { if CRATE_HIR_ID == hir_id { @@ -1050,62 +967,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { true } - /// Check that the `#![doc(auto_cfg)]` attribute has the expected input. - fn check_doc_auto_cfg(&self, meta: &MetaItem, hir_id: HirId) { - match &meta.kind { - MetaItemKind::Word => {} - MetaItemKind::NameValue(lit) => { - if !matches!(lit.kind, LitKind::Bool(_)) { - self.tcx.emit_node_span_lint( - INVALID_DOC_ATTRIBUTES, - hir_id, - meta.span, - errors::DocAutoCfgWrongLiteral, - ); - } - } - MetaItemKind::List(list) => { - for item in list { - let Some(attr_name @ (sym::hide | sym::show)) = item.name() else { - self.tcx.emit_node_span_lint( - INVALID_DOC_ATTRIBUTES, - hir_id, - meta.span, - errors::DocAutoCfgExpectsHideOrShow, - ); - continue; - }; - if let Some(list) = item.meta_item_list() { - for item in list { - let valid = item.meta_item().is_some_and(|meta| { - meta.path.segments.len() == 1 - && matches!( - &meta.kind, - MetaItemKind::Word | MetaItemKind::NameValue(_) - ) - }); - if !valid { - self.tcx.emit_node_span_lint( - INVALID_DOC_ATTRIBUTES, - hir_id, - item.span(), - errors::DocAutoCfgHideShowUnexpectedItem { attr_name }, - ); - } - } - } else { - self.tcx.emit_node_span_lint( - INVALID_DOC_ATTRIBUTES, - hir_id, - meta.span, - errors::DocAutoCfgHideShowExpectsList { attr_name }, - ); - } - } - } - } - } - /// Runs various checks on `#[doc]` attributes. /// /// `specified_inline` should be initialized to `None` and kept for the scope @@ -1121,7 +982,10 @@ impl<'tcx> CheckAttrVisitor<'tcx> { inline, // FIXME: currently unchecked cfg: _, - cfg_hide, + // already check in attr_parsing + auto_cfg: _, + // already check in attr_parsing + auto_cfg_change: _, fake_variadic, keyword, masked, @@ -1138,36 +1002,23 @@ impl<'tcx> CheckAttrVisitor<'tcx> { // allowed anywhere test_attrs: _, no_crate_inject, + attribute, } = attr; for (alias, span) in aliases { if self.check_attr_not_crate_level(*span, hir_id, "alias") { - self.check_doc_alias_value(*span, *alias, hir_id, target); + self.check_doc_alias_value(*span, hir_id, target, *alias); } } if let Some((_, span)) = keyword { - if self.check_attr_not_crate_level(*span, hir_id, "keyword") { - self.check_doc_keyword(*span, hir_id); - } + self.check_attr_not_crate_level(*span, hir_id, "keyword"); + self.check_doc_keyword_and_attribute(*span, hir_id, "keyword"); + } + if let Some((_, span)) = attribute { + self.check_attr_not_crate_level(*span, hir_id, "attribute"); + self.check_doc_keyword_and_attribute(*span, hir_id, "attribute"); } - - // FIXME: check doc attribute - // self.check_doc_keyword(meta, hir_id); - // self.check_doc_keyword_and_attribute( - // meta, - // hir_id, - // DocFakeItemKind::Keyword, - // ); - // } - // } - // Some(sym::attribute) => { - // if self.check_attr_not_crate_level(meta, hir_id, "attribute") { - // self.check_doc_keyword_and_attribute( - // meta, - // hir_id, - // DocFakeItemKind::Attribute, - // ); if let Some(span) = fake_variadic { if self.check_attr_not_crate_level(*span, hir_id, "fake_variadic") { @@ -1220,10 +1071,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { if let Some(span) = masked { self.check_doc_masked(*span, hir_id, target); } - - if let Some(span) = cfg_hide { - self.check_attr_crate_level(*span, hir_id); - } } fn check_has_incoherent_inherent_impls(&self, attr: &Attribute, span: Span, target: Target) { diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 926aba5082de..b693aaf76923 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -24,12 +24,6 @@ pub(crate) struct IncorrectDoNotRecommendLocation; #[diag(passes_incorrect_do_not_recommend_args)] pub(crate) struct DoNotRecommendDoesNotExpectArgs; -#[derive(LintDiagnostic)] -#[diag(passes_doc_attr_expects_string)] -pub(crate) struct DocAttrExpectsString { - pub(crate) attr_name: Symbol, -} - #[derive(Diagnostic)] #[diag(passes_autodiff_attr)] pub(crate) struct AutoDiffAttr { @@ -129,43 +123,20 @@ pub(crate) struct AttrShouldBeAppliedToStatic { pub defn_span: Span, } -#[derive(Diagnostic)] -#[diag(passes_doc_expect_str)] -pub(crate) struct DocExpectStr<'a> { - #[primary_span] - pub attr_span: Span, - pub attr_name: &'a str, -} - #[derive(Diagnostic)] #[diag(passes_doc_alias_bad_location)] pub(crate) struct DocAliasBadLocation<'a> { #[primary_span] pub span: Span, - pub attr_str: &'a str, pub location: &'a str, } #[derive(Diagnostic)] #[diag(passes_doc_alias_not_an_alias)] -pub(crate) struct DocAliasNotAnAlias<'a> { - #[primary_span] - pub span: Span, - pub attr_str: &'a str, -} - -#[derive(Diagnostic)] -#[diag(passes_doc_alias_not_string_literal)] -pub(crate) struct DocAliasNotStringLiteral { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(passes_doc_alias_malformed)] -pub(crate) struct DocAliasMalformed { +pub(crate) struct DocAliasNotAnAlias { #[primary_span] pub span: Span, + pub attr_str: Symbol, } #[derive(Diagnostic)] @@ -176,24 +147,6 @@ pub(crate) struct DocKeywordAttributeEmptyMod { pub attr_name: &'static str, } -#[derive(Diagnostic)] -#[diag(passes_doc_keyword_not_keyword)] -#[help] -pub(crate) struct DocKeywordNotKeyword { - #[primary_span] - pub span: Span, - pub keyword: Symbol, -} - -#[derive(Diagnostic)] -#[diag(passes_doc_attribute_not_attribute)] -#[help] -pub(crate) struct DocAttributeNotAttribute { - #[primary_span] - pub span: Span, - pub attribute: Symbol, -} - #[derive(Diagnostic)] #[diag(passes_doc_keyword_attribute_not_mod)] pub(crate) struct DocKeywordAttributeNotMod { @@ -260,90 +213,6 @@ pub(crate) struct DocAttrNotCrateLevel<'a> { pub attr_name: &'a str, } -#[derive(LintDiagnostic)] -#[diag(passes_doc_test_unknown)] -pub(crate) struct DocTestUnknown { - pub path: String, -} - -#[derive(LintDiagnostic)] -#[diag(passes_doc_test_literal)] -pub(crate) struct DocTestLiteral; - -#[derive(LintDiagnostic)] -#[diag(passes_doc_test_takes_list)] -pub(crate) struct DocTestTakesList; - -#[derive(LintDiagnostic)] -#[diag(passes_doc_auto_cfg_wrong_literal)] -pub(crate) struct DocAutoCfgWrongLiteral; - -#[derive(LintDiagnostic)] -#[diag(passes_doc_auto_cfg_expects_hide_or_show)] -pub(crate) struct DocAutoCfgExpectsHideOrShow; - -#[derive(LintDiagnostic)] -#[diag(passes_doc_auto_cfg_hide_show_expects_list)] -pub(crate) struct DocAutoCfgHideShowExpectsList { - pub attr_name: Symbol, -} - -#[derive(LintDiagnostic)] -#[diag(passes_doc_auto_cfg_hide_show_unexpected_item)] -pub(crate) struct DocAutoCfgHideShowUnexpectedItem { - pub attr_name: Symbol, -} - -#[derive(LintDiagnostic)] -#[diag(passes_doc_test_unknown_any)] -pub(crate) struct DocTestUnknownAny { - pub path: String, -} - -#[derive(LintDiagnostic)] -#[diag(passes_doc_test_unknown_spotlight)] -#[note] -#[note(passes_no_op_note)] -pub(crate) struct DocTestUnknownSpotlight { - pub path: String, - #[suggestion(style = "short", applicability = "machine-applicable", code = "notable_trait")] - pub span: Span, -} - -#[derive(LintDiagnostic)] -#[diag(passes_doc_test_unknown_passes)] -#[note] -#[note(passes_no_op_note)] -pub(crate) struct DocTestUnknownPasses { - pub path: String, - #[label] - pub span: Span, -} - -#[derive(LintDiagnostic)] -#[diag(passes_doc_test_unknown_plugins)] -#[note] -#[note(passes_no_op_note)] -pub(crate) struct DocTestUnknownPlugins { - pub path: String, - #[label] - pub span: Span, -} - -#[derive(LintDiagnostic)] -#[diag(passes_doc_test_unknown_include)] -pub(crate) struct DocTestUnknownInclude { - pub path: String, - pub value: String, - pub inner: &'static str, - #[suggestion(code = "#{inner}[doc = include_str!(\"{value}\")]")] - pub sugg: (Span, Applicability), -} - -#[derive(LintDiagnostic)] -#[diag(passes_doc_invalid)] -pub(crate) struct DocInvalid; - #[derive(Diagnostic)] #[diag(passes_has_incoherent_inherent_impl)] pub(crate) struct HasIncoherentInherentImpl { diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index a18913c1c1c7..069944b638c7 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -10,7 +10,6 @@ use rustc_ast::{ Item, ItemKind, MethodCall, NodeId, Path, PathSegment, Ty, TyKind, }; use rustc_ast_pretty::pprust::where_bound_predicate_to_string; -use rustc_attr_data_structures::{AttributeKind, find_attr}; use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; use rustc_errors::codes::*; use rustc_errors::{ @@ -18,6 +17,7 @@ use rustc_errors::{ struct_span_code_err, }; use rustc_hir as hir; +use rustc_hir::attrs::AttributeKind; use rustc_hir::def::Namespace::{self, *}; use rustc_hir::def::{self, CtorKind, CtorOf, DefKind, MacroKinds}; use rustc_hir::def_id::{CRATE_DEF_ID, DefId}; @@ -903,7 +903,8 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { // confused by them. continue; } - if let Some(d) = find_attr!(r.tcx.get_all_attrs(did), AttributeKind::Doc(d) => d) + if let Some(d) = + hir::find_attr!(r.tcx.get_all_attrs(did), AttributeKind::Doc(d) => d) && d.aliases.contains_key(&item_name) { return Some(did); From 131323f91002ac5277c3ae05046757adb5c48965 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 25 Nov 2025 23:54:10 +0100 Subject: [PATCH 09/64] Migrate `doc(cfg)` to new `Attribute` API --- Cargo.lock | 1 + src/librustdoc/Cargo.toml | 1 + src/librustdoc/clean/cfg.rs | 494 +++++++++++-------- src/librustdoc/clean/inline.rs | 2 +- src/librustdoc/clean/mod.rs | 141 ++---- src/librustdoc/clean/types.rs | 79 ++- src/librustdoc/clean/utils.rs | 27 +- src/librustdoc/doctest.rs | 44 +- src/librustdoc/doctest/rust.rs | 61 ++- src/librustdoc/html/render/context.rs | 50 +- src/librustdoc/html/render/search_index.rs | 4 +- src/librustdoc/html/sources.rs | 6 +- src/librustdoc/lib.rs | 2 - src/librustdoc/passes/check_doc_cfg.rs | 100 ++-- src/librustdoc/passes/collect_trait_impls.rs | 22 +- src/librustdoc/passes/propagate_doc_cfg.rs | 64 +-- 16 files changed, 552 insertions(+), 546 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bb81cada72ea..23708adcc499 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4870,6 +4870,7 @@ dependencies = [ "minifier", "pulldown-cmark-escape", "regex", + "rustc_proc_macro", "rustdoc-json-types", "serde", "serde_json", diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml index 0bc38220614f..371da896b9fc 100644 --- a/src/librustdoc/Cargo.toml +++ b/src/librustdoc/Cargo.toml @@ -18,6 +18,7 @@ minifier = { version = "0.3.5", default-features = false } pulldown-cmark-escape = { version = "0.11.0", features = ["simd"] } regex = "1" rustdoc-json-types = { path = "../rustdoc-json-types" } +rustc_proc_macro = { path = "../../compiler/rustc_proc_macro" } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" smallvec = "1.8.1" diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs index 6c77e41965dc..38d3a47f8ca0 100644 --- a/src/librustdoc/clean/cfg.rs +++ b/src/librustdoc/clean/cfg.rs @@ -9,11 +9,13 @@ use std::{fmt, mem, ops}; use itertools::Either; use rustc_ast::{LitKind, MetaItem, MetaItemInner, MetaItemKind, MetaItemLit}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_hir::attrs::AttributeKind; +use rustc_data_structures::thin_vec::{ThinVec, thin_vec}; +use rustc_hir::Attribute; +use rustc_hir::attrs::{AttributeKind, CfgEntry}; use rustc_middle::ty::TyCtxt; use rustc_session::parse::ParseSess; -use rustc_span::Span; use rustc_span::symbol::{Symbol, sym}; +use rustc_span::{DUMMY_SP, Span}; use {rustc_ast as ast, rustc_hir as hir}; use crate::display::{Joined as _, MaybeDisplay, Wrapped}; @@ -23,20 +25,7 @@ use crate::html::escape::Escape; mod tests; #[derive(Clone, Debug, PartialEq, Eq, Hash)] -pub(crate) enum Cfg { - /// Accepts all configurations. - True, - /// Denies all configurations. - False, - /// A generic configuration option, e.g., `test` or `target_os = "linux"`. - Cfg(Symbol, Option), - /// Negates a configuration requirement, i.e., `not(x)`. - Not(Box), - /// Union of a list of configuration requirements, i.e., `any(...)`. - Any(Vec), - /// Intersection of a list of configuration requirements, i.e., `all(...)`. - All(Vec), -} +pub(crate) struct Cfg(CfgEntry); #[derive(PartialEq, Debug)] pub(crate) struct InvalidCfgError { @@ -44,27 +33,95 @@ pub(crate) struct InvalidCfgError { pub(crate) span: Span, } +/// Whether the configuration consists of just `Cfg` or `Not`. +fn is_simple_cfg(cfg: &CfgEntry) -> bool { + match cfg { + CfgEntry::Bool(..) + | CfgEntry::NameValue { .. } + | CfgEntry::Not(..) + | CfgEntry::Version(..) => true, + CfgEntry::All(..) | CfgEntry::Any(..) => false, + } +} + +/// Whether the configuration consists of just `Cfg`, `Not` or `All`. +fn is_all_cfg(cfg: &CfgEntry) -> bool { + match cfg { + CfgEntry::Bool(..) + | CfgEntry::NameValue { .. } + | CfgEntry::Not(..) + | CfgEntry::Version(..) + | CfgEntry::All(..) => true, + CfgEntry::Any(..) => false, + } +} + +fn strip_hidden(cfg: &CfgEntry, hidden: &FxHashSet) -> Option { + match cfg { + CfgEntry::Bool(..) => Some(cfg.clone()), + CfgEntry::NameValue { .. } => { + if !hidden.contains(&SimpleCfg::from(cfg)) { + Some(cfg.clone()) + } else { + None + } + } + CfgEntry::Not(cfg, _) => { + if let Some(cfg) = strip_hidden(cfg, hidden) { + Some(CfgEntry::Not(Box::new(cfg), DUMMY_SP)) + } else { + None + } + } + CfgEntry::Any(cfgs, _) => { + let cfgs = + cfgs.iter().filter_map(|cfg| strip_hidden(cfg, hidden)).collect::>(); + if cfgs.is_empty() { None } else { Some(CfgEntry::Any(cfgs, DUMMY_SP)) } + } + CfgEntry::All(cfgs, _) => { + let cfgs = + cfgs.iter().filter_map(|cfg| strip_hidden(cfg, hidden)).collect::>(); + if cfgs.is_empty() { None } else { Some(CfgEntry::All(cfgs, DUMMY_SP)) } + } + CfgEntry::Version(..) => { + // FIXME: Should be handled. + Some(cfg.clone()) + } + } +} + +fn should_capitalize_first_letter(cfg: &CfgEntry) -> bool { + match cfg { + CfgEntry::Bool(..) | CfgEntry::Not(..) | CfgEntry::Version(..) => true, + CfgEntry::Any(sub_cfgs, _) | CfgEntry::All(sub_cfgs, _) => { + sub_cfgs.first().map(should_capitalize_first_letter).unwrap_or(false) + } + CfgEntry::NameValue { name, .. } => { + *name == sym::debug_assertions || *name == sym::target_endian + } + } +} + impl Cfg { /// Parses a `MetaItemInner` into a `Cfg`. fn parse_nested( nested_cfg: &MetaItemInner, - exclude: &FxHashSet, + exclude: &FxHashSet, ) -> Result, InvalidCfgError> { match nested_cfg { MetaItemInner::MetaItem(cfg) => Cfg::parse_without(cfg, exclude), - MetaItemInner::Lit(MetaItemLit { kind: LitKind::Bool(b), .. }) => match *b { - true => Ok(Some(Cfg::True)), - false => Ok(Some(Cfg::False)), - }, + MetaItemInner::Lit(MetaItemLit { kind: LitKind::Bool(b), .. }) => { + Ok(Some(Cfg(CfgEntry::Bool(*b, DUMMY_SP)))) + } MetaItemInner::Lit(lit) => { Err(InvalidCfgError { msg: "unexpected literal", span: lit.span }) } } } - pub(crate) fn parse_without( + fn parse_without( cfg: &MetaItem, - exclude: &FxHashSet, + exclude: &FxHashSet, ) -> Result, InvalidCfgError> { let name = match cfg.ident() { Some(ident) => ident.name, @@ -77,13 +134,29 @@ impl Cfg { }; match cfg.kind { MetaItemKind::Word => { - let cfg = Cfg::Cfg(name, None); - if exclude.contains(&cfg) { Ok(None) } else { Ok(Some(cfg)) } + if exclude.contains(&SimpleCfg::new(name)) { + Ok(None) + } else { + Ok(Some(Cfg(CfgEntry::NameValue { + name, + value: None, + name_span: DUMMY_SP, + span: DUMMY_SP, + }))) + } } MetaItemKind::NameValue(ref lit) => match lit.kind { LitKind::Str(value, _) => { - let cfg = Cfg::Cfg(name, Some(value)); - if exclude.contains(&cfg) { Ok(None) } else { Ok(Some(cfg)) } + if exclude.contains(&SimpleCfg::new_value(name, value)) { + Ok(None) + } else { + Ok(Some(Cfg(CfgEntry::NameValue { + name, + value: Some((value, DUMMY_SP)), + name_span: DUMMY_SP, + span: DUMMY_SP, + }))) + } } _ => Err(InvalidCfgError { // FIXME: if the main #[cfg] syntax decided to support non-string literals, @@ -97,8 +170,12 @@ impl Cfg { let mut sub_cfgs = items.iter().filter_map(|i| Cfg::parse_nested(i, exclude).transpose()); let ret = match name { - sym::all => sub_cfgs.try_fold(Cfg::True, |x, y| Ok(x & y?)), - sym::any => sub_cfgs.try_fold(Cfg::False, |x, y| Ok(x | y?)), + sym::all => { + sub_cfgs.try_fold(Cfg(CfgEntry::Bool(true, DUMMY_SP)), |x, y| Ok(x & y?)) + } + sym::any => { + sub_cfgs.try_fold(Cfg(CfgEntry::Bool(false, DUMMY_SP)), |x, y| Ok(x | y?)) + } sym::not => { if orig_len == 1 { let mut sub_cfgs = sub_cfgs.collect::>(); @@ -136,36 +213,32 @@ impl Cfg { /// /// Equivalent to `attr::cfg_matches`. pub(crate) fn matches(&self, psess: &ParseSess) -> bool { - match *self { - Cfg::False => false, - Cfg::True => true, - Cfg::Not(ref child) => !child.matches(psess), - Cfg::All(ref sub_cfgs) => sub_cfgs.iter().all(|sub_cfg| sub_cfg.matches(psess)), - Cfg::Any(ref sub_cfgs) => sub_cfgs.iter().any(|sub_cfg| sub_cfg.matches(psess)), - Cfg::Cfg(name, value) => psess.config.contains(&(name, value)), - } - } - - /// Whether the configuration consists of just `Cfg` or `Not`. - fn is_simple(&self) -> bool { - match self { - Cfg::False | Cfg::True | Cfg::Cfg(..) | Cfg::Not(..) => true, - Cfg::All(..) | Cfg::Any(..) => false, - } - } - - /// Whether the configuration consists of just `Cfg`, `Not` or `All`. - fn is_all(&self) -> bool { - match self { - Cfg::False | Cfg::True | Cfg::Cfg(..) | Cfg::Not(..) | Cfg::All(..) => true, - Cfg::Any(..) => false, + fn cfg_matches(cfg: &CfgEntry, psess: &ParseSess) -> bool { + match cfg { + CfgEntry::Bool(v, _) => *v, + CfgEntry::Not(child, _) => !cfg_matches(child, psess), + CfgEntry::All(sub_cfgs, _) => { + sub_cfgs.iter().all(|sub_cfg| cfg_matches(sub_cfg, psess)) + } + CfgEntry::Any(sub_cfgs, _) => { + sub_cfgs.iter().any(|sub_cfg| cfg_matches(sub_cfg, psess)) + } + CfgEntry::NameValue { name, value, .. } => { + psess.config.contains(&(*name, value.clone().map(|(s, _)| s))) + } + CfgEntry::Version(..) => { + // FIXME: should be handled. + false + } + } } + cfg_matches(&self.0, psess) } /// Renders the configuration for human display, as a short HTML description. pub(crate) fn render_short_html(&self) -> String { - let mut msg = Display(self, Format::ShortHtml).to_string(); - if self.should_capitalize_first_letter() + let mut msg = Display(&self.0, Format::ShortHtml).to_string(); + if should_capitalize_first_letter(&self.0) && let Some(i) = msg.find(|c: char| c.is_ascii_alphanumeric()) { msg[i..i + 1].make_ascii_uppercase(); @@ -183,9 +256,9 @@ impl Cfg { }; let mut msg = if matches!(format, Format::LongHtml) { - format!("Available{on}{}", Display(self, format)) + format!("Available{on}{}", Display(&self.0, format)) } else { - format!("Available{on}{}", Display(self, format)) + format!("Available{on}{}", Display(&self.0, format)) }; if self.should_append_only_to_description() { msg.push_str(" only"); @@ -205,27 +278,20 @@ impl Cfg { self.render_long_inner(Format::LongPlain) } - fn should_capitalize_first_letter(&self) -> bool { - match *self { - Cfg::False | Cfg::True | Cfg::Not(..) => true, - Cfg::Any(ref sub_cfgs) | Cfg::All(ref sub_cfgs) => { - sub_cfgs.first().map(Cfg::should_capitalize_first_letter).unwrap_or(false) - } - Cfg::Cfg(name, _) => name == sym::debug_assertions || name == sym::target_endian, - } - } - fn should_append_only_to_description(&self) -> bool { - match self { - Cfg::False | Cfg::True => false, - Cfg::Any(..) | Cfg::All(..) | Cfg::Cfg(..) => true, - Cfg::Not(box Cfg::Cfg(..)) => true, - Cfg::Not(..) => false, + match self.0 { + CfgEntry::Bool(..) => false, + CfgEntry::Any(..) + | CfgEntry::All(..) + | CfgEntry::NameValue { .. } + | CfgEntry::Version(..) => true, + CfgEntry::Not(box CfgEntry::NameValue { .. }, _) => true, + CfgEntry::Not(..) => false, } } fn should_use_with_in_description(&self) -> bool { - matches!(self, Cfg::Cfg(sym::target_feature, _)) + matches!(self.0, CfgEntry::NameValue { name, .. } if name == sym::target_feature) } /// Attempt to simplify this cfg by assuming that `assume` is already known to be true, will @@ -236,20 +302,20 @@ impl Cfg { pub(crate) fn simplify_with(&self, assume: &Self) -> Option { if self == assume { None - } else if let Cfg::All(a) = self { - let mut sub_cfgs: Vec = if let Cfg::All(b) = assume { + } else if let CfgEntry::All(a, _) = &self.0 { + let mut sub_cfgs: ThinVec = if let CfgEntry::All(b, _) = &assume.0 { a.iter().filter(|a| !b.contains(a)).cloned().collect() } else { - a.iter().filter(|&a| a != assume).cloned().collect() + a.iter().filter(|&a| *a != assume.0).cloned().collect() }; let len = sub_cfgs.len(); match len { 0 => None, - 1 => sub_cfgs.pop(), - _ => Some(Cfg::All(sub_cfgs)), + 1 => sub_cfgs.pop().map(Cfg), + _ => Some(Cfg(CfgEntry::All(sub_cfgs, DUMMY_SP))), } - } else if let Cfg::All(b) = assume - && b.contains(self) + } else if let CfgEntry::All(b, _) = &assume.0 + && b.contains(&self.0) { None } else { @@ -258,81 +324,50 @@ impl Cfg { } fn omit_preposition(&self) -> bool { - matches!(self, Cfg::True | Cfg::False) - } - - pub(crate) fn strip_hidden(&self, hidden: &FxHashSet) -> Option { - match self { - Self::True | Self::False => Some(self.clone()), - Self::Cfg(..) => { - if !hidden.contains(self) { - Some(self.clone()) - } else { - None - } - } - Self::Not(cfg) => { - if let Some(cfg) = cfg.strip_hidden(hidden) { - Some(Self::Not(Box::new(cfg))) - } else { - None - } - } - Self::Any(cfgs) => { - let cfgs = - cfgs.iter().filter_map(|cfg| cfg.strip_hidden(hidden)).collect::>(); - if cfgs.is_empty() { None } else { Some(Self::Any(cfgs)) } - } - Self::All(cfgs) => { - let cfgs = - cfgs.iter().filter_map(|cfg| cfg.strip_hidden(hidden)).collect::>(); - if cfgs.is_empty() { None } else { Some(Self::All(cfgs)) } - } - } + matches!(self.0, CfgEntry::Bool(..)) } } impl ops::Not for Cfg { type Output = Cfg; fn not(self) -> Cfg { - match self { - Cfg::False => Cfg::True, - Cfg::True => Cfg::False, - Cfg::Not(cfg) => *cfg, - s => Cfg::Not(Box::new(s)), - } + Cfg(match self.0 { + CfgEntry::Bool(v, s) => CfgEntry::Bool(!v, s), + CfgEntry::Not(cfg, _) => *cfg, + s => CfgEntry::Not(Box::new(s), DUMMY_SP), + }) } } impl ops::BitAndAssign for Cfg { fn bitand_assign(&mut self, other: Cfg) { - match (self, other) { - (Cfg::False, _) | (_, Cfg::True) => {} - (s, Cfg::False) => *s = Cfg::False, - (s @ Cfg::True, b) => *s = b, - (Cfg::All(a), Cfg::All(ref mut b)) => { + match (&mut self.0, other.0) { + (CfgEntry::Bool(false, _), _) | (_, CfgEntry::Bool(true, _)) => {} + (s, CfgEntry::Bool(false, _)) => *s = CfgEntry::Bool(false, DUMMY_SP), + (s @ CfgEntry::Bool(true, _), b) => *s = b, + (CfgEntry::All(a, _), CfgEntry::All(ref mut b, _)) => { for c in b.drain(..) { if !a.contains(&c) { a.push(c); } } } - (Cfg::All(a), ref mut b) => { + (CfgEntry::All(a, _), ref mut b) => { if !a.contains(b) { - a.push(mem::replace(b, Cfg::True)); + a.push(mem::replace(b, CfgEntry::Bool(true, DUMMY_SP))); } } - (s, Cfg::All(mut a)) => { - let b = mem::replace(s, Cfg::True); + (s, CfgEntry::All(mut a, _)) => { + let b = mem::replace(s, CfgEntry::Bool(true, DUMMY_SP)); if !a.contains(&b) { a.push(b); } - *s = Cfg::All(a); + *s = CfgEntry::All(a, DUMMY_SP); } (s, b) => { if *s != b { - let a = mem::replace(s, Cfg::True); - *s = Cfg::All(vec![a, b]); + let a = mem::replace(s, CfgEntry::Bool(true, DUMMY_SP)); + *s = CfgEntry::All(thin_vec![a, b], DUMMY_SP); } } } @@ -349,32 +384,34 @@ impl ops::BitAnd for Cfg { impl ops::BitOrAssign for Cfg { fn bitor_assign(&mut self, other: Cfg) { - match (self, other) { - (Cfg::True, _) | (_, Cfg::False) | (_, Cfg::True) => {} - (s @ Cfg::False, b) => *s = b, - (Cfg::Any(a), Cfg::Any(ref mut b)) => { + match (&mut self.0, other.0) { + (CfgEntry::Bool(true, _), _) + | (_, CfgEntry::Bool(false, _)) + | (_, CfgEntry::Bool(true, _)) => {} + (s @ CfgEntry::Bool(false, _), b) => *s = b, + (CfgEntry::Any(a, _), CfgEntry::Any(ref mut b, _)) => { for c in b.drain(..) { if !a.contains(&c) { a.push(c); } } } - (Cfg::Any(a), ref mut b) => { + (CfgEntry::Any(a, _), ref mut b) => { if !a.contains(b) { - a.push(mem::replace(b, Cfg::True)); + a.push(mem::replace(b, CfgEntry::Bool(true, DUMMY_SP))); } } - (s, Cfg::Any(mut a)) => { - let b = mem::replace(s, Cfg::True); + (s, CfgEntry::Any(mut a, _)) => { + let b = mem::replace(s, CfgEntry::Bool(true, DUMMY_SP)); if !a.contains(&b) { a.push(b); } - *s = Cfg::Any(a); + *s = CfgEntry::Any(a, DUMMY_SP); } (s, b) => { if *s != b { - let a = mem::replace(s, Cfg::True); - *s = Cfg::Any(vec![a, b]); + let a = mem::replace(s, CfgEntry::Bool(true, DUMMY_SP)); + *s = CfgEntry::Any(thin_vec![a, b], DUMMY_SP); } } } @@ -417,7 +454,7 @@ impl Format { } /// Pretty-print wrapper for a `Cfg`. Also indicates what form of rendering should be used. -struct Display<'a>(&'a Cfg, Format); +struct Display<'a>(&'a CfgEntry, Format); impl Display<'_> { fn code_wrappers(&self) -> Wrapped<&'static str> { @@ -427,17 +464,21 @@ impl Display<'_> { fn display_sub_cfgs( &self, fmt: &mut fmt::Formatter<'_>, - sub_cfgs: &[Cfg], + sub_cfgs: &[CfgEntry], separator: &str, ) -> fmt::Result { use fmt::Display as _; let short_longhand = self.1.is_long() && { - let all_crate_features = - sub_cfgs.iter().all(|sub_cfg| matches!(sub_cfg, Cfg::Cfg(sym::feature, Some(_)))); - let all_target_features = sub_cfgs - .iter() - .all(|sub_cfg| matches!(sub_cfg, Cfg::Cfg(sym::target_feature, Some(_)))); + let all_crate_features = sub_cfgs.iter().all(|sub_cfg| { + matches!(sub_cfg, CfgEntry::NameValue { name: sym::feature, value: Some(_), .. }) + }); + let all_target_features = sub_cfgs.iter().all(|sub_cfg| { + matches!( + sub_cfg, + CfgEntry::NameValue { name: sym::target_feature, value: Some(_), .. } + ) + }); if all_crate_features { fmt.write_str("crate features ")?; @@ -454,14 +495,14 @@ impl Display<'_> { sub_cfgs .iter() .map(|sub_cfg| { - if let Cfg::Cfg(_, Some(feat)) = sub_cfg + if let CfgEntry::NameValue { value: Some((feat, _)), .. } = sub_cfg && short_longhand { Either::Left(self.code_wrappers().wrap(feat)) } else { Either::Right( Wrapped::with_parens() - .when(!sub_cfg.is_all()) + .when(!is_all_cfg(sub_cfg)) .wrap(Display(sub_cfg, self.1)), ) } @@ -476,39 +517,45 @@ impl Display<'_> { impl fmt::Display for Display<'_> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.0 { - Cfg::Not(box Cfg::Any(sub_cfgs)) => { - let separator = - if sub_cfgs.iter().all(Cfg::is_simple) { " nor " } else { ", nor " }; + match &self.0 { + CfgEntry::Not(box CfgEntry::Any(sub_cfgs, _), _) => { + let separator = if sub_cfgs.iter().all(is_simple_cfg) { " nor " } else { ", nor " }; fmt.write_str("neither ")?; sub_cfgs .iter() .map(|sub_cfg| { Wrapped::with_parens() - .when(!sub_cfg.is_all()) + .when(!is_all_cfg(sub_cfg)) .wrap(Display(sub_cfg, self.1)) }) .joined(separator, fmt) } - Cfg::Not(box simple @ Cfg::Cfg(..)) => write!(fmt, "non-{}", Display(simple, self.1)), - Cfg::Not(box c) => write!(fmt, "not ({})", Display(c, self.1)), - - Cfg::Any(sub_cfgs) => { - let separator = if sub_cfgs.iter().all(Cfg::is_simple) { " or " } else { ", or " }; - self.display_sub_cfgs(fmt, sub_cfgs, separator) + CfgEntry::Not(box simple @ CfgEntry::NameValue { .. }, _) => { + write!(fmt, "non-{}", Display(simple, self.1)) } - Cfg::All(sub_cfgs) => self.display_sub_cfgs(fmt, sub_cfgs, " and "), + CfgEntry::Not(box c, _) => write!(fmt, "not ({})", Display(c, self.1)), - Cfg::True => fmt.write_str("everywhere"), - Cfg::False => fmt.write_str("nowhere"), + CfgEntry::Any(sub_cfgs, _) => { + let separator = if sub_cfgs.iter().all(is_simple_cfg) { " or " } else { ", or " }; + self.display_sub_cfgs(fmt, sub_cfgs.as_slice(), separator) + } + CfgEntry::All(sub_cfgs, _) => self.display_sub_cfgs(fmt, sub_cfgs.as_slice(), " and "), - &Cfg::Cfg(name, value) => { - let human_readable = match (name, value) { + CfgEntry::Bool(v, _) => { + if *v { + fmt.write_str("everywhere") + } else { + fmt.write_str("nowhere") + } + } + + &CfgEntry::NameValue { name, value, .. } => { + let human_readable = match (*name, value) { (sym::unix, None) => "Unix", (sym::windows, None) => "Windows", (sym::debug_assertions, None) => "debug-assertions enabled", - (sym::target_os, Some(os)) => match os.as_str() { + (sym::target_os, Some((os, _))) => match os.as_str() { "android" => "Android", "cygwin" => "Cygwin", "dragonfly" => "DragonFly BSD", @@ -533,7 +580,7 @@ impl fmt::Display for Display<'_> { "visionos" => "visionOS", _ => "", }, - (sym::target_arch, Some(arch)) => match arch.as_str() { + (sym::target_arch, Some((arch, _))) => match arch.as_str() { "aarch64" => "AArch64", "arm" => "ARM", "loongarch32" => "LoongArch LA32", @@ -556,14 +603,14 @@ impl fmt::Display for Display<'_> { "x86_64" => "x86-64", _ => "", }, - (sym::target_vendor, Some(vendor)) => match vendor.as_str() { + (sym::target_vendor, Some((vendor, _))) => match vendor.as_str() { "apple" => "Apple", "pc" => "PC", "sun" => "Sun", "fortanix" => "Fortanix", _ => "", }, - (sym::target_env, Some(env)) => match env.as_str() { + (sym::target_env, Some((env, _))) => match env.as_str() { "gnu" => "GNU", "msvc" => "MSVC", "musl" => "musl", @@ -572,16 +619,20 @@ impl fmt::Display for Display<'_> { "sgx" => "SGX", _ => "", }, - (sym::target_endian, Some(endian)) => return write!(fmt, "{endian}-endian"), - (sym::target_pointer_width, Some(bits)) => return write!(fmt, "{bits}-bit"), - (sym::target_feature, Some(feat)) => match self.1 { + (sym::target_endian, Some((endian, _))) => { + return write!(fmt, "{endian}-endian"); + } + (sym::target_pointer_width, Some((bits, _))) => { + return write!(fmt, "{bits}-bit"); + } + (sym::target_feature, Some((feat, _))) => match self.1 { Format::LongHtml => { return write!(fmt, "target feature {feat}"); } Format::LongPlain => return write!(fmt, "target feature `{feat}`"), Format::ShortHtml => return write!(fmt, "{feat}"), }, - (sym::feature, Some(feat)) => match self.1 { + (sym::feature, Some((feat, _))) => match self.1 { Format::LongHtml => { return write!(fmt, "crate feature {feat}"); } @@ -594,13 +645,47 @@ impl fmt::Display for Display<'_> { fmt.write_str(human_readable) } else { let value = value - .map(|v| fmt::from_fn(move |f| write!(f, "={}", self.1.escape(v.as_str())))) + .map(|(v, _)| { + fmt::from_fn(move |f| write!(f, "={}", self.1.escape(v.as_str()))) + }) .maybe_display(); self.code_wrappers() .wrap(format_args!("{}{value}", self.1.escape(name.as_str()))) .fmt(fmt) } } + + CfgEntry::Version(..) => { + // FIXME: Should we handle it? + Ok(()) + } + } + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +struct SimpleCfg { + name: Symbol, + value: Option, +} + +impl SimpleCfg { + fn new(name: Symbol) -> Self { + Self { name, value: None } + } + + fn new_value(name: Symbol, value: Symbol) -> Self { + Self { name, value: Some(value) } + } +} + +impl<'a> From<&'a CfgEntry> for SimpleCfg { + fn from(cfg: &'a CfgEntry) -> Self { + match cfg { + CfgEntry::NameValue { name, value, .. } => { + SimpleCfg { name: *name, value: (*value).map(|(v, _)| v) } + } + _ => SimpleCfg { name: sym::empty, value: None }, } } } @@ -610,7 +695,7 @@ impl fmt::Display for Display<'_> { pub(crate) struct CfgInfo { /// List of currently active `doc(auto_cfg(hide(...)))` cfgs, minus currently active /// `doc(auto_cfg(show(...)))` cfgs. - hidden_cfg: FxHashSet, + hidden_cfg: FxHashSet, /// Current computed `cfg`. Each time we enter a new item, this field is updated as well while /// taking into account the `hidden_cfg` information. current_cfg: Cfg, @@ -626,11 +711,11 @@ impl Default for CfgInfo { fn default() -> Self { Self { hidden_cfg: FxHashSet::from_iter([ - Cfg::Cfg(sym::test, None), - Cfg::Cfg(sym::doc, None), - Cfg::Cfg(sym::doctest, None), + SimpleCfg::new(sym::test), + SimpleCfg::new(sym::doc), + SimpleCfg::new(sym::doctest), ]), - current_cfg: Cfg::True, + current_cfg: Cfg(CfgEntry::Bool(true, DUMMY_SP)), auto_cfg_active: true, parent_is_doc_cfg: false, } @@ -672,21 +757,24 @@ fn handle_auto_cfg_hide_show( { for item in items { // FIXME: Report in case `Cfg::parse` reports an error? - if let Ok(Cfg::Cfg(key, value)) = Cfg::parse(item) { + let Ok(cfg) = Cfg::parse(item) else { continue }; + if let CfgEntry::NameValue { name, value, .. } = cfg.0 { + let value = value.map(|(v, _)| v); + let simple = SimpleCfg::from(&cfg.0); if is_show { - if let Some(span) = new_hide_attrs.get(&(key, value)) { + if let Some(span) = new_hide_attrs.get(&(name, value)) { show_hide_show_conflict_error(tcx, item.span(), *span); } else { - new_show_attrs.insert((key, value), item.span()); + new_show_attrs.insert((name, value), item.span()); } - cfg_info.hidden_cfg.remove(&Cfg::Cfg(key, value)); + cfg_info.hidden_cfg.remove(&simple); } else { - if let Some(span) = new_show_attrs.get(&(key, value)) { + if let Some(span) = new_show_attrs.get(&(name, value)) { show_hide_show_conflict_error(tcx, item.span(), *span); } else { - new_hide_attrs.insert((key, value), item.span()); + new_hide_attrs.insert((name, value), item.span()); } - cfg_info.hidden_cfg.insert(Cfg::Cfg(key, value)); + cfg_info.hidden_cfg.insert(simple); } } } @@ -737,28 +825,21 @@ pub(crate) fn extract_cfg_from_attrs<'a, I: Iterator let mut doc_cfg = attrs .clone() - .filter(|attr| attr.has_name(sym::doc)) - .flat_map(|attr| attr.meta_item_list().unwrap_or_default()) - .filter(|attr| attr.has_name(sym::cfg)) + .filter_map(|attr| match attr { + Attribute::Parsed(AttributeKind::Doc(d)) => Some(d), + _ => None, + }) .peekable(); // If the item uses `doc(cfg(...))`, then we ignore the other `cfg(...)` attributes. if doc_cfg.peek().is_some() { - let sess = tcx.sess; // We overwrite existing `cfg`. if !cfg_info.parent_is_doc_cfg { - cfg_info.current_cfg = Cfg::True; + cfg_info.current_cfg = Cfg(CfgEntry::Bool(true, DUMMY_SP)); cfg_info.parent_is_doc_cfg = true; } for attr in doc_cfg { - if let Some(cfg_mi) = - attr.meta_item().and_then(|attr| rustc_expand::config::parse_cfg_old(attr, sess)) - { - match Cfg::parse(cfg_mi) { - Ok(new_cfg) => cfg_info.current_cfg &= new_cfg, - Err(e) => { - sess.dcx().span_err(e.span, e.msg); - } - } + if let Some(new_cfg) = attr.cfg.clone() { + cfg_info.current_cfg &= Cfg(new_cfg); } } } else { @@ -833,7 +914,12 @@ pub(crate) fn extract_cfg_from_attrs<'a, I: Iterator // Treat `#[target_feature(enable = "feat")]` attributes as if they were // `#[doc(cfg(target_feature = "feat"))]` attributes as well. for (feature, _) in features { - cfg_info.current_cfg &= Cfg::Cfg(sym::target_feature, Some(*feature)); + cfg_info.current_cfg &= Cfg(CfgEntry::NameValue { + name: sym::target_feature, + value: Some((*feature, DUMMY_SP)), + name_span: DUMMY_SP, + span: DUMMY_SP, + }); } continue; } else if !cfg_info.parent_is_doc_cfg @@ -851,7 +937,7 @@ pub(crate) fn extract_cfg_from_attrs<'a, I: Iterator if !cfg_info.auto_cfg_active && !cfg_info.parent_is_doc_cfg { None } else if cfg_info.parent_is_doc_cfg { - if cfg_info.current_cfg == Cfg::True { + if matches!(cfg_info.current_cfg.0, CfgEntry::Bool(true, _)) { None } else { Some(Arc::new(cfg_info.current_cfg.clone())) @@ -859,9 +945,9 @@ pub(crate) fn extract_cfg_from_attrs<'a, I: Iterator } else { // If `doc(auto_cfg)` feature is enabled, we want to collect all `cfg` items, we remove the // hidden ones afterward. - match cfg_info.current_cfg.strip_hidden(&cfg_info.hidden_cfg) { - None | Some(Cfg::True) => None, - Some(cfg) => Some(Arc::new(cfg)), + match strip_hidden(&cfg_info.current_cfg.0, &cfg_info.hidden_cfg) { + None | Some(CfgEntry::Bool(true, _)) => None, + Some(cfg) => Some(Arc::new(Cfg(cfg))), } } } diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 849df566b4bd..c86a655c083a 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -640,7 +640,7 @@ pub(crate) fn build_impl( for_, items: trait_items, polarity, - kind: if utils::has_doc_flag(tcx, did, sym::fake_variadic) { + kind: if utils::has_doc_flag(tcx, did, |d| d.fake_variadic.is_some()) { ImplKind::FakeVariadic } else { ImplKind::Normal diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 1f9ce68584ce..6fd578628388 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -34,13 +34,11 @@ use std::borrow::Cow; use std::collections::BTreeMap; use std::mem; -use rustc_ast::token::{Token, TokenKind}; -use rustc_ast::tokenstream::{TokenStream, TokenTree}; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet, IndexEntry}; use rustc_data_structures::thin_vec::ThinVec; use rustc_errors::codes::*; use rustc_errors::{FatalError, struct_span_code_err}; -use rustc_hir::attrs::AttributeKind; +use rustc_hir::attrs::{AttributeKind, DocAttribute, DocInline}; use rustc_hir::def::{CtorKind, DefKind, MacroKinds, Res}; use rustc_hir::def_id::{DefId, DefIdMap, DefIdSet, LOCAL_CRATE, LocalDefId}; use rustc_hir::{LangItem, PredicateOrigin, find_attr}; @@ -198,12 +196,9 @@ fn generate_item_with_correct_attrs( // For glob re-exports the item may or may not exist to be re-exported (potentially the // cfgs on the path up until the glob can be removed, and only cfgs on the globbed item // itself matter), for non-inlined re-exports see #85043. - let import_is_inline = - hir_attr_lists(inline::load_attrs(cx, import_id.to_def_id()), sym::doc) - .get_word_attr(sym::inline) - .is_some() - || (is_glob_import(cx.tcx, import_id) - && (cx.document_hidden() || !cx.tcx.is_doc_hidden(def_id))); + let import_is_inline = find_attr!(inline::load_attrs(cx, import_id.to_def_id()), AttributeKind::Doc(d) if d.inline.is_some()) + || (is_glob_import(cx.tcx, import_id) + && (cx.document_hidden() || !cx.tcx.is_doc_hidden(def_id))); attrs.extend(get_all_import_attributes(cx, import_id, def_id, is_inline)); is_inline = is_inline || import_is_inline; } @@ -2635,63 +2630,6 @@ fn get_all_import_attributes<'hir>( attrs } -fn filter_tokens_from_list( - args_tokens: &TokenStream, - should_retain: impl Fn(&TokenTree) -> bool, -) -> Vec { - let mut tokens = Vec::with_capacity(args_tokens.len()); - let mut skip_next_comma = false; - for token in args_tokens.iter() { - match token { - TokenTree::Token(Token { kind: TokenKind::Comma, .. }, _) if skip_next_comma => { - skip_next_comma = false; - } - token if should_retain(token) => { - skip_next_comma = false; - tokens.push(token.clone()); - } - _ => { - skip_next_comma = true; - } - } - } - tokens -} - -fn filter_doc_attr_ident(ident: Symbol, is_inline: bool) -> bool { - if is_inline { - ident == sym::hidden || ident == sym::inline || ident == sym::no_inline - } else { - ident == sym::cfg - } -} - -/// Remove attributes from `normal` that should not be inherited by `use` re-export. -/// Before calling this function, make sure `normal` is a `#[doc]` attribute. -fn filter_doc_attr(args: &mut hir::AttrArgs, is_inline: bool) { - match args { - hir::AttrArgs::Delimited(args) => { - let tokens = filter_tokens_from_list(&args.tokens, |token| { - !matches!( - token, - TokenTree::Token( - Token { - kind: TokenKind::Ident( - ident, - _, - ), - .. - }, - _, - ) if filter_doc_attr_ident(*ident, is_inline), - ) - }); - args.tokens = TokenStream::new(tokens); - } - hir::AttrArgs::Empty | hir::AttrArgs::Eq { .. } => {} - } -} - /// When inlining items, we merge their attributes (and all the reexports attributes too) with the /// final reexport. For example: /// @@ -2719,25 +2657,34 @@ fn add_without_unwanted_attributes<'hir>( import_parent: Option, ) { for attr in new_attrs { - if attr.is_doc_comment().is_some() { - attrs.push((Cow::Borrowed(attr), import_parent)); - continue; - } - let mut attr = attr.clone(); match attr { - hir::Attribute::Unparsed(ref mut normal) if let [ident] = &*normal.path.segments => { - let ident = ident.name; - if ident == sym::doc { - filter_doc_attr(&mut normal.args, is_inline); - attrs.push((Cow::Owned(attr), import_parent)); - } else if is_inline || ident != sym::cfg_trace { + hir::Attribute::Parsed(AttributeKind::DocComment { .. }) => { + attrs.push((Cow::Borrowed(attr), import_parent)); + } + hir::Attribute::Parsed(AttributeKind::Doc(box d)) => { + // Remove attributes from `normal` that should not be inherited by `use` re-export. + let DocAttribute { hidden, inline, cfg, .. } = d; + let mut attr = DocAttribute::default(); + if is_inline { + attr.inline = inline.clone(); + attr.hidden = hidden.clone(); + } else { + attr.cfg = cfg.clone(); + } + attrs.push(( + Cow::Owned(hir::Attribute::Parsed(AttributeKind::Doc(Box::new(attr)))), + import_parent, + )); + } + hir::Attribute::Unparsed(normal) if let [ident] = &*normal.path.segments => { + if is_inline || ident.name != sym::cfg_trace { // If it's not a `cfg()` attribute, we keep it. - attrs.push((Cow::Owned(attr), import_parent)); + attrs.push((Cow::Borrowed(attr), import_parent)); } } // FIXME: make sure to exclude `#[cfg_trace]` here when it is ported to the new parsers hir::Attribute::Parsed(..) => { - attrs.push((Cow::Owned(attr), import_parent)); + attrs.push((Cow::Borrowed(attr), import_parent)); } _ => {} } @@ -2939,7 +2886,7 @@ fn clean_impl<'tcx>( } else { ty::ImplPolarity::Positive }, - kind: if utils::has_doc_flag(tcx, def_id.to_def_id(), sym::fake_variadic) { + kind: if utils::has_doc_flag(tcx, def_id.to_def_id(), |d| d.fake_variadic.is_some()) { ImplKind::FakeVariadic } else { ImplKind::Normal @@ -2967,13 +2914,10 @@ fn clean_extern_crate<'tcx>( let attrs = cx.tcx.hir_attrs(krate.hir_id()); let ty_vis = cx.tcx.visibility(krate.owner_id); let please_inline = ty_vis.is_public() - && attrs.iter().any(|a| { - a.has_name(sym::doc) - && match a.meta_item_list() { - Some(l) => ast::attr::list_contains_name(&l, sym::inline), - None => false, - } - }) + && attrs.iter().any(|a| matches!( + a, + hir::Attribute::Parsed(AttributeKind::Doc(d)) if d.inline.is_some_and(|(i, _)| i == DocInline::Inline)) + ) && !cx.is_json_output(); let krate_owner_def_id = krate.owner_id.def_id; @@ -3035,7 +2979,11 @@ fn clean_use_statement_inner<'tcx>( let visibility = cx.tcx.visibility(import.owner_id); let attrs = cx.tcx.hir_attrs(import.hir_id()); - let inline_attr = hir_attr_lists(attrs, sym::doc).get_word_attr(sym::inline); + let inline_attr = find_attr!( + attrs, + AttributeKind::Doc(d) if d.inline.is_some_and(|(i, _)| i == DocInline::Inline) => d + ) + .and_then(|d| d.inline); let pub_underscore = visibility.is_public() && name == Some(kw::Underscore); let current_mod = cx.tcx.parent_module_from_def_id(import.owner_id.def_id); let import_def_id = import.owner_id.def_id; @@ -3053,10 +3001,10 @@ fn clean_use_statement_inner<'tcx>( let is_visible_from_parent_mod = visibility.is_accessible_from(parent_mod, cx.tcx) && !current_mod.is_top_level_module(); - if pub_underscore && let Some(ref inline) = inline_attr { + if pub_underscore && let Some((_, inline_span)) = inline_attr { struct_span_code_err!( cx.tcx.dcx(), - inline.span(), + inline_span, E0780, "anonymous imports cannot be inlined" ) @@ -3071,16 +3019,9 @@ fn clean_use_statement_inner<'tcx>( let mut denied = cx.is_json_output() || !(visibility.is_public() || (cx.document_private() && is_visible_from_parent_mod)) || pub_underscore - || attrs.iter().any(|a| { - a.has_name(sym::doc) - && match a.meta_item_list() { - Some(l) => { - ast::attr::list_contains_name(&l, sym::no_inline) - || ast::attr::list_contains_name(&l, sym::hidden) - } - None => false, - } - }); + || attrs.iter().any(|a| matches!( + a, + hir::Attribute::Parsed(AttributeKind::Doc(d)) if d.hidden.is_some() || d.inline.is_some_and(|(i, _)| i == DocInline::NoInline))); // Also check whether imports were asked to be inlined, in case we're trying to re-export a // crate in Rust 2018+ diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index f1b0f4a68bea..12dcb198bd21 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -9,11 +9,11 @@ use itertools::Either; use rustc_abi::{ExternAbi, VariantIdx}; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::thin_vec::ThinVec; -use rustc_hir::attrs::{AttributeKind, DeprecatedSince, Deprecation}; +use rustc_hir::attrs::{AttributeKind, DeprecatedSince, Deprecation, DocAttribute}; use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE, LocalDefId}; use rustc_hir::lang_items::LangItem; -use rustc_hir::{BodyId, ConstStability, Mutability, Stability, StableSince, find_attr}; +use rustc_hir::{Attribute, BodyId, ConstStability, Mutability, Stability, StableSince, find_attr}; use rustc_index::IndexVec; use rustc_metadata::rendered_const; use rustc_middle::span_bug; @@ -190,12 +190,13 @@ impl ExternalCrate { // Failing that, see if there's an attribute specifying where to find this // external crate let did = self.crate_num.as_def_id(); - tcx.get_attrs(did, sym::doc) - .flat_map(|attr| attr.meta_item_list().unwrap_or_default()) - .filter(|a| a.has_name(sym::html_root_url)) - .filter_map(|a| a.value_str()) + tcx.get_all_attrs(did) + .iter() + .find_map(|a| match a { + Attribute::Parsed(AttributeKind::Doc(d)) => d.html_root_url.map(|(url, _)| url), + _ => None, + }) .map(to_remote) - .next() .or_else(|| extern_url.map(to_remote)) // NOTE: only matters if `extern_url_takes_precedence` is false .unwrap_or(Unknown) // Well, at least we tried. } @@ -228,26 +229,34 @@ impl ExternalCrate { } pub(crate) fn keywords(&self, tcx: TyCtxt<'_>) -> impl Iterator { - self.retrieve_keywords_or_documented_attributes(tcx, sym::keyword) + self.retrieve_keywords_or_documented_attributes(tcx, true) } pub(crate) fn documented_attributes( &self, tcx: TyCtxt<'_>, ) -> impl Iterator { - self.retrieve_keywords_or_documented_attributes(tcx, sym::attribute) + self.retrieve_keywords_or_documented_attributes(tcx, false) } fn retrieve_keywords_or_documented_attributes( &self, tcx: TyCtxt<'_>, - name: Symbol, + look_for_keyword: bool, ) -> impl Iterator { let as_target = move |did: DefId, tcx: TyCtxt<'_>| -> Option<(DefId, Symbol)> { - tcx.get_attrs(did, sym::doc) - .flat_map(|attr| attr.meta_item_list().unwrap_or_default()) - .filter(|meta| meta.has_name(name)) - .find_map(|meta| meta.value_str()) - .map(|value| (did, value)) + tcx.get_all_attrs(did) + .iter() + .find_map(|attr| match attr { + Attribute::Parsed(AttributeKind::Doc(d)) => { + if look_for_keyword { + d.keyword + } else { + d.attribute + } + } + _ => None, + }) + .map(|(value, _)| (did, value)) }; self.mapped_root_modules(tcx, as_target) } @@ -993,28 +1002,14 @@ pub(crate) struct Attributes { } impl Attributes { - pub(crate) fn lists(&self, name: Symbol) -> impl Iterator { - hir_attr_lists(&self.other_attrs[..], name) - } - - pub(crate) fn has_doc_flag(&self, flag: Symbol) -> bool { - for attr in &self.other_attrs { - if !attr.has_name(sym::doc) { - continue; - } - - if let Some(items) = attr.meta_item_list() - && items.iter().filter_map(|i| i.meta_item()).any(|it| it.has_name(flag)) - { - return true; - } - } - - false + pub(crate) fn has_doc_flag bool>(&self, callback: F) -> bool { + self.other_attrs + .iter() + .any(|a| matches!(a, Attribute::Parsed(AttributeKind::Doc(d)) if callback(d))) } pub(crate) fn is_doc_hidden(&self) -> bool { - self.has_doc_flag(sym::hidden) + find_attr!(&self.other_attrs, AttributeKind::Doc(d) if d.hidden.is_some()) } pub(crate) fn from_hir(attrs: &[hir::Attribute]) -> Attributes { @@ -1061,19 +1056,11 @@ impl Attributes { pub(crate) fn get_doc_aliases(&self) -> Box<[Symbol]> { let mut aliases = FxIndexSet::default(); - for attr in - hir_attr_lists(&self.other_attrs[..], sym::doc).filter(|a| a.has_name(sym::alias)) - { - if let Some(values) = attr.meta_item_list() { - for l in values { - if let Some(lit) = l.lit() - && let ast::LitKind::Str(s, _) = lit.kind - { - aliases.insert(s); - } + for attr in &self.other_attrs { + if let Attribute::Parsed(AttributeKind::Doc(d)) = attr { + for (alias, _) in &d.aliases { + aliases.insert(*alias); } - } else if let Some(value) = attr.value_str() { - aliases.insert(value); } } aliases.into_iter().collect::>().into() diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index cb5cd6523afe..4c3f26701bab 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -6,6 +6,8 @@ use std::{ascii, mem}; use rustc_ast::join_path_idents; use rustc_ast::tokenstream::TokenTree; use rustc_data_structures::thin_vec::{ThinVec, thin_vec}; +use rustc_hir::Attribute; +use rustc_hir::attrs::{AttributeKind, DocAttribute}; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId}; use rustc_metadata::rendered_const; @@ -46,7 +48,7 @@ pub(crate) fn krate(cx: &mut DocContext<'_>) -> Crate { if cx.tcx.is_compiler_builtins(it.item_id.krate()) { cx.cache.masked_crates.insert(it.item_id.krate()); } else if it.is_extern_crate() - && it.attrs.has_doc_flag(sym::masked) + && it.attrs.has_doc_flag(|d| d.masked.is_some()) && let Some(def_id) = it.item_id.as_def_id() && let Some(local_def_id) = def_id.as_local() && let Some(cnum) = cx.tcx.extern_mod_stmt_cnum(local_def_id) @@ -562,24 +564,17 @@ pub(crate) fn find_nearest_parent_module(tcx: TyCtxt<'_>, def_id: DefId) -> Opti } } -/// Checks for the existence of `hidden` in the attribute below if `flag` is `sym::hidden`: -/// -/// ``` -/// #[doc(hidden)] -/// pub fn foo() {} -/// ``` -/// /// This function exists because it runs on `hir::Attributes` whereas the other is a /// `clean::Attributes` method. -pub(crate) fn has_doc_flag(tcx: TyCtxt<'_>, did: DefId, flag: Symbol) -> bool { - attrs_have_doc_flag(tcx.get_attrs(did, sym::doc), flag) -} - -pub(crate) fn attrs_have_doc_flag<'a>( - mut attrs: impl Iterator, - flag: Symbol, +pub(crate) fn has_doc_flag bool>( + tcx: TyCtxt<'_>, + did: DefId, + callback: F, ) -> bool { - attrs.any(|attr| attr.meta_item_list().is_some_and(|l| ast::attr::list_contains_name(&l, flag))) + tcx.get_all_attrs(did).iter().any(|attr| match attr { + Attribute::Parsed(AttributeKind::Doc(d)) => callback(d), + _ => false, + }) } /// A link to `doc.rust-lang.org` that includes the channel name. Use this instead of manual links diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 481aa392007c..7541311be05d 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -9,6 +9,7 @@ use std::hash::{Hash, Hasher}; use std::io::{self, Write}; use std::path::{Path, PathBuf}; use std::process::{self, Command, Stdio}; +use std::str::FromStr; use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::{Arc, Mutex}; use std::time::{Duration, Instant}; @@ -19,14 +20,15 @@ pub(crate) use markdown::test as test_markdown; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxHasher, FxIndexMap, FxIndexSet}; use rustc_errors::emitter::HumanReadableErrorType; use rustc_errors::{ColorConfig, DiagCtxtHandle}; -use rustc_hir as hir; -use rustc_hir::CRATE_HIR_ID; +use rustc_hir::attrs::AttributeKind; use rustc_hir::def_id::LOCAL_CRATE; +use rustc_hir::{Attribute, CRATE_HIR_ID}; use rustc_interface::interface; +use rustc_middle::ty::TyCtxt; +use rustc_proc_macro::{TokenStream, TokenTree}; use rustc_session::config::{self, CrateType, ErrorOutputType, Input}; use rustc_session::lint; use rustc_span::edition::Edition; -use rustc_span::symbol::sym; use rustc_span::{FileName, Span}; use rustc_target::spec::{Target, TargetTuple}; use tempfile::{Builder as TempFileBuilder, TempDir}; @@ -212,8 +214,7 @@ pub(crate) fn run(dcx: DiagCtxtHandle<'_>, input: Input, options: RustdocOptions let collector = rustc_interface::create_and_enter_global_ctxt(compiler, krate, |tcx| { let crate_name = tcx.crate_name(LOCAL_CRATE).to_string(); - let crate_attrs = tcx.hir_attrs(CRATE_HIR_ID); - let opts = scrape_test_config(crate_name, crate_attrs, args_path); + let opts = scrape_test_config(tcx, crate_name, args_path); let hir_collector = HirCollector::new( ErrorCodes::from(compiler.sess.opts.unstable_features.is_nightly_build()), @@ -417,8 +418,8 @@ pub(crate) fn run_tests( // Look for `#![doc(test(no_crate_inject))]`, used by crates in the std facade. fn scrape_test_config( + tcx: TyCtxt<'_>, crate_name: String, - attrs: &[hir::Attribute], args_file: PathBuf, ) -> GlobalTestOptions { let mut opts = GlobalTestOptions { @@ -428,19 +429,26 @@ fn scrape_test_config( args_file, }; - let test_attrs: Vec<_> = attrs - .iter() - .filter(|a| a.has_name(sym::doc)) - .flat_map(|a| a.meta_item_list().unwrap_or_default()) - .filter(|a| a.has_name(sym::test)) - .collect(); - let attrs = test_attrs.iter().flat_map(|a| a.meta_item_list().unwrap_or(&[])); - - for attr in attrs { - if attr.has_name(sym::no_crate_inject) { - opts.no_crate_inject = true; + let source_map = tcx.sess.source_map(); + 'main: for attr in tcx.hir_attrs(CRATE_HIR_ID) { + let Attribute::Parsed(AttributeKind::Doc(d)) = attr else { continue }; + for attr_span in &d.test_attrs { + // FIXME: This is ugly, remove when `test_attrs` has been ported to new attribute API. + if let Ok(snippet) = source_map.span_to_snippet(*attr_span) + && let Ok(stream) = TokenStream::from_str(&snippet) + { + // NOTE: `test(attr(..))` is handled when discovering the individual tests + if stream.into_iter().any(|token| { + matches!( + token, + TokenTree::Ident(i) if i.to_string() == "no_crate_inject", + ) + }) { + opts.no_crate_inject = true; + break 'main; + } + } } - // NOTE: `test(attr(..))` is handled when discovering the individual tests } opts diff --git a/src/librustdoc/doctest/rust.rs b/src/librustdoc/doctest/rust.rs index 4d3f976c2a6d..e119344a806a 100644 --- a/src/librustdoc/doctest/rust.rs +++ b/src/librustdoc/doctest/rust.rs @@ -2,16 +2,18 @@ use std::cell::Cell; use std::env; +use std::str::FromStr; use std::sync::Arc; -use rustc_ast_pretty::pprust; +use rustc_hir::attrs::AttributeKind; use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId}; -use rustc_hir::{self as hir, CRATE_HIR_ID, intravisit}; +use rustc_hir::{self as hir, Attribute, CRATE_HIR_ID, intravisit}; use rustc_middle::hir::nested_filter; use rustc_middle::ty::TyCtxt; +use rustc_proc_macro::{TokenStream, TokenTree}; use rustc_resolve::rustdoc::span_of_fragments; use rustc_span::source_map::SourceMap; -use rustc_span::{BytePos, DUMMY_SP, FileName, Pos, Span, sym}; +use rustc_span::{BytePos, DUMMY_SP, FileName, Pos, Span}; use super::{DocTestVisitor, ScrapedDocTest}; use crate::clean::{Attributes, CfgInfo, extract_cfg_from_attrs}; @@ -126,23 +128,46 @@ impl HirCollector<'_> { return; } + let source_map = self.tcx.sess.source_map(); // Try collecting `#[doc(test(attr(...)))]` let old_global_crate_attrs_len = self.collector.global_crate_attrs.len(); - for doc_test_attrs in ast_attrs - .iter() - .filter(|a| a.has_name(sym::doc)) - .flat_map(|a| a.meta_item_list().unwrap_or_default()) - .filter(|a| a.has_name(sym::test)) - { - let Some(doc_test_attrs) = doc_test_attrs.meta_item_list() else { continue }; - for attr in doc_test_attrs - .iter() - .filter(|a| a.has_name(sym::attr)) - .flat_map(|a| a.meta_item_list().unwrap_or_default()) - .map(pprust::meta_list_item_to_string) - { - // Add the additional attributes to the global_crate_attrs vector - self.collector.global_crate_attrs.push(attr); + for attr in ast_attrs { + let Attribute::Parsed(AttributeKind::Doc(d)) = attr else { continue }; + for attr_span in &d.test_attrs { + // FIXME: This is ugly, remove when `test_attrs` has been ported to new attribute API. + if let Ok(snippet) = source_map.span_to_snippet(*attr_span) + && let Ok(stream) = TokenStream::from_str(&snippet) + { + let mut iter = stream.into_iter().peekable(); + while let Some(token) = iter.next() { + if let TokenTree::Ident(i) = token { + let i = i.to_string(); + let peek = iter.peek(); + match peek { + Some(TokenTree::Group(g)) => { + let g = g.to_string(); + iter.next(); + // Add the additional attributes to the global_crate_attrs vector + self.collector.global_crate_attrs.push(format!("{i}{g}")); + } + Some(TokenTree::Punct(p)) if p.as_char() == '=' => { + let p = p.to_string(); + iter.next(); + if let Some(last) = iter.next() { + // Add the additional attributes to the global_crate_attrs vector + self.collector + .global_crate_attrs + .push(format!("{i}{p}{last}")); + } + } + _ => { + // Add the additional attributes to the global_crate_attrs vector + self.collector.global_crate_attrs.push(i.to_string()); + } + } + } + } + } } } diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs index e42997d5b4a1..3d4dff4a17d2 100644 --- a/src/librustdoc/html/render/context.rs +++ b/src/librustdoc/html/render/context.rs @@ -8,11 +8,13 @@ use std::sync::mpsc::{Receiver, channel}; use askama::Template; use rustc_ast::join_path_syms; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; +use rustc_hir::Attribute; +use rustc_hir::attrs::AttributeKind; use rustc_hir::def_id::{DefIdMap, LOCAL_CRATE}; use rustc_middle::ty::TyCtxt; use rustc_session::Session; use rustc_span::edition::Edition; -use rustc_span::{BytePos, FileName, Symbol, sym}; +use rustc_span::{BytePos, FileName, Symbol}; use tracing::info; use super::print_item::{full_path, print_item, print_item_path}; @@ -260,7 +262,9 @@ impl<'tcx> Context<'tcx> { short_title, description: &desc, resource_suffix: &self.shared.resource_suffix, - rust_logo: has_doc_flag(self.tcx(), LOCAL_CRATE.as_def_id(), sym::rust_logo), + rust_logo: has_doc_flag(self.tcx(), LOCAL_CRATE.as_def_id(), |d| { + d.rust_logo.is_some() + }), }; layout::render( &self.shared.layout, @@ -522,27 +526,25 @@ impl<'tcx> Context<'tcx> { // Crawl the crate attributes looking for attributes which control how we're // going to emit HTML - for attr in krate.module.attrs.lists(sym::doc) { - match (attr.name(), attr.value_str()) { - (Some(sym::html_favicon_url), Some(s)) => { - layout.favicon = s.to_string(); - } - (Some(sym::html_logo_url), Some(s)) => { - layout.logo = s.to_string(); - } - (Some(sym::html_playground_url), Some(s)) => { - playground = Some(markdown::Playground { - crate_name: Some(krate.name(tcx)), - url: s.to_string(), - }); - } - (Some(sym::issue_tracker_base_url), Some(s)) => { - issue_tracker_base_url = Some(s.to_string()); - } - (Some(sym::html_no_source), None) if attr.is_word() => { - include_sources = false; - } - _ => {} + for attr in &krate.module.attrs.other_attrs { + let Attribute::Parsed(AttributeKind::Doc(d)) = attr else { continue }; + if let Some((html_favicon_url, _)) = d.html_favicon_url { + layout.favicon = html_favicon_url.to_string(); + } + if let Some((html_logo_url, _)) = d.html_logo_url { + layout.logo = html_logo_url.to_string(); + } + if let Some((html_playground_url, _)) = d.html_playground_url { + playground = Some(markdown::Playground { + crate_name: Some(krate.name(tcx)), + url: html_playground_url.to_string(), + }); + } + if let Some((s, _)) = d.issue_tracker_base_url { + issue_tracker_base_url = Some(s.to_string()); + } + if d.html_no_source.is_some() { + include_sources = false; } } @@ -645,7 +647,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { static_root_path: shared.static_root_path.as_deref(), description: "List of all items in this crate", resource_suffix: &shared.resource_suffix, - rust_logo: has_doc_flag(self.tcx(), LOCAL_CRATE.as_def_id(), sym::rust_logo), + rust_logo: has_doc_flag(self.tcx(), LOCAL_CRATE.as_def_id(), |d| d.rust_logo.is_some()), }; let all = shared.all.replace(AllTypes::new()); let mut sidebar = String::new(); diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs index a4cbef8c3917..12b207dda569 100644 --- a/src/librustdoc/html/render/search_index.rs +++ b/src/librustdoc/html/render/search_index.rs @@ -1609,7 +1609,9 @@ pub(crate) fn build_index( let Cache { ref paths, ref external_paths, ref exact_paths, .. } = *cache; let search_unbox = match id { RenderTypeId::Mut => false, - RenderTypeId::DefId(defid) => utils::has_doc_flag(tcx, defid, sym::search_unbox), + RenderTypeId::DefId(defid) => { + utils::has_doc_flag(tcx, defid, |d| d.search_unbox.is_some()) + } RenderTypeId::Primitive( PrimitiveType::Reference | PrimitiveType::RawPointer | PrimitiveType::Tuple, ) => true, diff --git a/src/librustdoc/html/sources.rs b/src/librustdoc/html/sources.rs index f04f94432b80..55f8ddab25b1 100644 --- a/src/librustdoc/html/sources.rs +++ b/src/librustdoc/html/sources.rs @@ -8,7 +8,7 @@ use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_hir::def_id::LOCAL_CRATE; use rustc_middle::ty::TyCtxt; use rustc_session::Session; -use rustc_span::{FileName, FileNameDisplayPreference, RealFileName, sym}; +use rustc_span::{FileName, FileNameDisplayPreference, RealFileName}; use tracing::info; use super::render::Context; @@ -236,7 +236,9 @@ impl SourceCollector<'_, '_> { static_root_path: shared.static_root_path.as_deref(), description: &desc, resource_suffix: &shared.resource_suffix, - rust_logo: has_doc_flag(self.cx.tcx(), LOCAL_CRATE.as_def_id(), sym::rust_logo), + rust_logo: has_doc_flag(self.cx.tcx(), LOCAL_CRATE.as_def_id(), |d| { + d.rust_logo.is_some() + }), }; let source_context = SourceContext::Standalone { file_path }; let v = layout::render( diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index e4601bfb20d7..a0e359032f9b 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -32,11 +32,9 @@ extern crate rustc_abi; extern crate rustc_ast; extern crate rustc_ast_pretty; -extern crate rustc_attr_parsing; extern crate rustc_data_structures; extern crate rustc_driver; extern crate rustc_errors; -extern crate rustc_expand; extern crate rustc_feature; extern crate rustc_hir; extern crate rustc_hir_analysis; diff --git a/src/librustdoc/passes/check_doc_cfg.rs b/src/librustdoc/passes/check_doc_cfg.rs index 3284da77a022..63dc375a13c6 100644 --- a/src/librustdoc/passes/check_doc_cfg.rs +++ b/src/librustdoc/passes/check_doc_cfg.rs @@ -1,3 +1,5 @@ +#![allow(dead_code, unused_imports)] + use rustc_hir::HirId; use rustc_hir::def_id::LocalDefId; use rustc_middle::ty::TyCtxt; @@ -14,63 +16,59 @@ pub(crate) const CHECK_DOC_CFG: Pass = Pass { description: "checks `#[doc(cfg(...))]` for stability feature and unexpected cfgs", }; -pub(crate) fn check_doc_cfg(krate: Crate, cx: &mut DocContext<'_>) -> Crate { - let mut checker = DocCfgChecker { cx }; - checker.visit_crate(&krate); +pub(crate) fn check_doc_cfg(krate: Crate, _cx: &mut DocContext<'_>) -> Crate { + // let mut checker = DocCfgChecker { cx }; + // checker.visit_crate(&krate); krate } -struct RustdocCfgMatchesLintEmitter<'a>(TyCtxt<'a>, HirId); +// struct RustdocCfgMatchesLintEmitter<'a>(TyCtxt<'a>, HirId); -impl<'a> rustc_attr_parsing::CfgMatchesLintEmitter for RustdocCfgMatchesLintEmitter<'a> { - fn emit_span_lint( - &self, - sess: &rustc_session::Session, - lint: &'static rustc_lint::Lint, - sp: rustc_span::Span, - builtin_diag: rustc_lint_defs::BuiltinLintDiag, - ) { - self.0.node_span_lint(lint, self.1, sp, |diag| { - rustc_lint::decorate_builtin_lint(sess, Some(self.0), builtin_diag, diag) - }); - } -} +// impl<'a> rustc_attr_parsing::CfgMatchesLintEmitter for RustdocCfgMatchesLintEmitter<'a> { +// fn emit_span_lint( +// &self, +// sess: &rustc_session::Session, +// lint: &'static rustc_lint::Lint, +// sp: rustc_span::Span, +// builtin_diag: rustc_lint_defs::BuiltinLintDiag, +// ) { +// self.0.node_span_lint(lint, self.1, sp, |diag| { +// rustc_lint::decorate_builtin_lint(sess, Some(self.0), builtin_diag, diag) +// }); +// } +// } -struct DocCfgChecker<'a, 'tcx> { - cx: &'a mut DocContext<'tcx>, -} +// struct DocCfgChecker<'a, 'tcx> { +// cx: &'a mut DocContext<'tcx>, +// } -impl DocCfgChecker<'_, '_> { - fn check_attrs(&mut self, attrs: &Attributes, did: LocalDefId) { - let doc_cfgs = attrs - .other_attrs - .iter() - .filter(|attr| attr.has_name(sym::doc)) - .flat_map(|attr| attr.meta_item_list().unwrap_or_default()) - .filter(|attr| attr.has_name(sym::cfg)); +// impl DocCfgChecker<'_, '_> { +// fn check_attrs(&mut self, attrs: &Attributes, did: LocalDefId) { +// for attr in &attrs.other_attrs { +// let Attribute::Parsed(AttributeKind::Doc(d)) = attr else { continue }; +// let Some(doc_cfg) = d.cfg else { continue }; - for doc_cfg in doc_cfgs { - if let Some([cfg_mi]) = doc_cfg.meta_item_list() { - let _ = rustc_attr_parsing::cfg_matches( - cfg_mi, - &self.cx.tcx.sess, - RustdocCfgMatchesLintEmitter( - self.cx.tcx, - self.cx.tcx.local_def_id_to_hir_id(did), - ), - Some(self.cx.tcx.features()), - ); - } - } - } -} +// if let Some([cfg_mi]) = doc_cfg.meta_item_list() { +// let _ = rustc_attr_parsing::cfg_matches( +// cfg_mi, +// &self.cx.tcx.sess, +// RustdocCfgMatchesLintEmitter( +// self.cx.tcx, +// self.cx.tcx.local_def_id_to_hir_id(did), +// ), +// Some(self.cx.tcx.features()), +// ); +// } +// } +// } +// } -impl DocVisitor<'_> for DocCfgChecker<'_, '_> { - fn visit_item(&mut self, item: &'_ Item) { - if let Some(Some(local_did)) = item.def_id().map(|did| did.as_local()) { - self.check_attrs(&item.attrs, local_did); - } +// impl DocVisitor<'_> for DocCfgChecker<'_, '_> { +// fn visit_item(&mut self, item: &'_ Item) { +// if let Some(Some(local_did)) = item.def_id().map(|did| did.as_local()) { +// self.check_attrs(&item.attrs, local_did); +// } - self.visit_item_recur(item); - } -} +// self.visit_item_recur(item); +// } +// } diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs index 2339a6b69cd8..d71c3eaa2dcb 100644 --- a/src/librustdoc/passes/collect_trait_impls.rs +++ b/src/librustdoc/passes/collect_trait_impls.rs @@ -3,9 +3,10 @@ //! struct implements that trait. use rustc_data_structures::fx::FxHashSet; +use rustc_hir::Attribute; +use rustc_hir::attrs::{AttributeKind, DocAttribute}; use rustc_hir::def_id::{DefId, DefIdMap, DefIdSet, LOCAL_CRATE}; use rustc_middle::ty; -use rustc_span::symbol::sym; use tracing::debug; use super::Pass; @@ -65,17 +66,14 @@ pub(crate) fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) -> for &impl_def_id in tcx.trait_impls_in_crate(LOCAL_CRATE) { let mut parent = Some(tcx.parent(impl_def_id)); while let Some(did) = parent { - attr_buf.extend( - tcx.get_attrs(did, sym::doc) - .filter(|attr| { - if let Some([attr]) = attr.meta_item_list().as_deref() { - attr.has_name(sym::cfg) - } else { - false - } - }) - .cloned(), - ); + attr_buf.extend(tcx.get_all_attrs(did).iter().filter_map(|attr| match attr { + Attribute::Parsed(AttributeKind::Doc(d)) if d.cfg.is_some() => { + let mut new_attr = DocAttribute::default(); + new_attr.cfg = d.cfg.clone(); + Some(Attribute::Parsed(AttributeKind::Doc(Box::new(new_attr)))) + } + _ => None, + })); parent = tcx.opt_parent(did); } cx.with_param_env(impl_def_id, |cx| { diff --git a/src/librustdoc/passes/propagate_doc_cfg.rs b/src/librustdoc/passes/propagate_doc_cfg.rs index c0b48ab51c7e..422393592c76 100644 --- a/src/librustdoc/passes/propagate_doc_cfg.rs +++ b/src/librustdoc/passes/propagate_doc_cfg.rs @@ -1,8 +1,7 @@ //! Propagates [`#[doc(cfg(...))]`](https://github.com/rust-lang/rust/issues/43781) to child items. -use rustc_ast::token::{Token, TokenKind}; -use rustc_ast::tokenstream::{TokenStream, TokenTree}; -use rustc_hir::{AttrArgs, Attribute}; +use rustc_hir::Attribute; +use rustc_hir::attrs::{AttributeKind, DocAttribute}; use rustc_span::symbol::sym; use crate::clean::inline::{load_attrs, merge_attrs}; @@ -30,59 +29,22 @@ struct CfgPropagator<'a, 'tcx> { cfg_info: CfgInfo, } -/// Returns true if the provided `token` is a `cfg` ident. -fn is_cfg_token(token: &TokenTree) -> bool { - // We only keep `doc(cfg)` items. - matches!(token, TokenTree::Token(Token { kind: TokenKind::Ident(sym::cfg, _,), .. }, _,),) -} - -/// We only want to keep `#[cfg()]` and `#[doc(cfg())]` attributes so we rebuild a vec of -/// `TokenTree` with only the tokens we're interested into. -fn filter_non_cfg_tokens_from_list(args_tokens: &TokenStream) -> Vec { - let mut tokens = Vec::with_capacity(args_tokens.len()); - let mut skip_next_delimited = false; - for token in args_tokens.iter() { - match token { - TokenTree::Delimited(..) => { - if !skip_next_delimited { - tokens.push(token.clone()); - } - skip_next_delimited = false; - } - token if is_cfg_token(token) => { - skip_next_delimited = false; - tokens.push(token.clone()); - } - _ => { - skip_next_delimited = true; - } - } - } - tokens -} - /// This function goes through the attributes list (`new_attrs`) and extract the `cfg` tokens from /// it and put them into `attrs`. fn add_only_cfg_attributes(attrs: &mut Vec, new_attrs: &[Attribute]) { for attr in new_attrs { - if attr.is_doc_comment().is_some() { - continue; - } - let mut attr = attr.clone(); - if let Attribute::Unparsed(ref mut normal) = attr - && let [ident] = &*normal.path.segments + if let Attribute::Parsed(AttributeKind::Doc(d)) = attr + && d.cfg.is_some() { - let ident = ident.name; - if ident == sym::doc - && let AttrArgs::Delimited(args) = &mut normal.args - { - let tokens = filter_non_cfg_tokens_from_list(&args.tokens); - args.tokens = TokenStream::new(tokens); - attrs.push(attr); - } else if ident == sym::cfg_trace { - // If it's a `cfg()` attribute, we keep it. - attrs.push(attr); - } + let mut new_attr = DocAttribute::default(); + new_attr.cfg = d.cfg.clone(); + attrs.push(Attribute::Parsed(AttributeKind::Doc(Box::new(new_attr)))); + } else if let Attribute::Unparsed(normal) = attr + && let [ident] = &*normal.path.segments + && ident.name == sym::cfg_trace + { + // If it's a `cfg()` attribute, we keep it. + attrs.push(attr.clone()); } } } From 04bcd83eb5b987afd5b7d43f82c0b5eb2df62767 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 27 Nov 2025 20:51:12 +0100 Subject: [PATCH 10/64] Move `doc = ""` parsing out of `DocParser` to keep doc attributes order --- .../rustc_attr_parsing/src/attributes/doc.rs | 28 +++----------- compiler/rustc_attr_parsing/src/interface.rs | 37 ++++++++++++++++++- 2 files changed, 41 insertions(+), 24 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/doc.rs b/compiler/rustc_attr_parsing/src/attributes/doc.rs index 65651e617179..fbe1ac63ab9c 100644 --- a/compiler/rustc_attr_parsing/src/attributes/doc.rs +++ b/compiler/rustc_attr_parsing/src/attributes/doc.rs @@ -2,7 +2,6 @@ #![allow(unused_imports)] use rustc_ast::ast::{AttrStyle, LitKind, MetaItemLit}; -use rustc_ast::token::CommentKind; use rustc_errors::MultiSpan; use rustc_feature::template; use rustc_hir::attrs::{ @@ -81,19 +80,10 @@ fn parse_keyword_and_attribute<'c, S, F>( *attr_value = Some((value, path.span())); } -#[derive(Debug)] -struct DocComment { - style: AttrStyle, - kind: CommentKind, - span: Span, - comment: Symbol, -} - #[derive(Default, Debug)] pub(crate) struct DocParser { attribute: DocAttribute, nb_doc_attrs: usize, - doc_comment: Option, } impl DocParser { @@ -481,17 +471,11 @@ impl DocParser { } } ArgParser::NameValue(nv) => { - let Some(comment) = nv.value_as_str() else { + if nv.value_as_str().is_none() { cx.expected_string_literal(nv.value_span, Some(nv.value_as_lit())); - return; - }; - - self.doc_comment = Some(DocComment { - style: cx.attr_style, - kind: CommentKind::Block, - span: nv.value_span, - comment, - }); + } else { + unreachable!("Should have been handled at the same time as sugar-syntaxed doc comments"); + } } } } @@ -537,9 +521,7 @@ impl AttributeParser for DocParser { ]); fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option { - if let Some(DocComment { style, kind, span, comment }) = self.doc_comment { - Some(AttributeKind::DocComment { style, kind, span, comment }) - } else if self.nb_doc_attrs != 0 { + if self.nb_doc_attrs != 0 { Some(AttributeKind::Doc(Box::new(self.attribute))) } else { None diff --git a/compiler/rustc_attr_parsing/src/interface.rs b/compiler/rustc_attr_parsing/src/interface.rs index 363e1fcac507..feb7bbcb6234 100644 --- a/compiler/rustc_attr_parsing/src/interface.rs +++ b/compiler/rustc_attr_parsing/src/interface.rs @@ -2,6 +2,7 @@ use std::borrow::Cow; use rustc_ast as ast; use rustc_ast::{AttrStyle, NodeId, Safety}; +use rustc_ast::token::CommentKind; use rustc_errors::DiagCtxtHandle; use rustc_feature::{AttributeTemplate, Features}; use rustc_hir::attrs::AttributeKind; @@ -281,7 +282,8 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { // that's expanded right? But no, sometimes, when parsing attributes on macros, // we already use the lowering logic and these are still there. So, when `omit_doc` // is set we *also* want to ignore these. - if omit_doc == OmitDoc::Skip && attr.has_name(sym::doc) { + let is_doc_attribute = attr.has_name(sym::doc); + if omit_doc == OmitDoc::Skip && is_doc_attribute { continue; } @@ -323,6 +325,39 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { continue; }; let args = parser.args(); + + // Special-case handling for `#[doc = "..."]`: if we go through with + // `DocParser`, the order of doc comments will be messed up because `///` + // doc comments are added into `attributes` whereas attributes parsed with + // `DocParser` are added into `parsed_attributes` which are then appended + // to `attributes`. So if you have: + // + // /// bla + // #[doc = "a"] + // /// blob + // + // You would get: + // + // bla + // blob + // a + if is_doc_attribute + && let ArgParser::NameValue(nv) = args + // If not a string key/value, it should emit an error, but to make + // things simpler, it's handled in `DocParser` because it's simpler to + // emit an error with `AcceptContext`. + && let Some(comment) = nv.value_as_str() + { + attributes.push(Attribute::Parsed(AttributeKind::DocComment { + style: attr.style, + kind: CommentKind::Block, + span: nv.value_span, + comment, + })); + continue; + } + + let path = parser.path(); for accept in accepts { let mut cx: AcceptContext<'_, 'sess, S> = AcceptContext { shared: SharedContext { From 148e522112d65d23c8615e22da65a64e319674bb Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 28 Nov 2025 16:08:24 +0100 Subject: [PATCH 11/64] Correctly differentiate between sugared and raw doc comments --- compiler/rustc_ast/src/attr/mod.rs | 47 +++++++++++++++---- compiler/rustc_ast/src/token.rs | 26 +++++++++- compiler/rustc_ast_pretty/src/pprust/state.rs | 32 +++++++++---- .../rustc_attr_parsing/src/attributes/doc.rs | 4 +- compiler/rustc_attr_parsing/src/interface.rs | 8 ++-- .../rustc_hir/src/attrs/data_structures.rs | 4 +- .../rustc_hir/src/attrs/pretty_printing.rs | 3 +- compiler/rustc_hir/src/hir.rs | 8 ++-- compiler/rustc_resolve/src/rustdoc.rs | 42 +++++++---------- src/librustdoc/clean/types.rs | 2 +- 10 files changed, 117 insertions(+), 59 deletions(-) diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index d54d900128bd..94e7462d26df 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -13,7 +13,9 @@ use crate::ast::{ Expr, ExprKind, LitKind, MetaItem, MetaItemInner, MetaItemKind, MetaItemLit, NormalAttr, Path, PathSegment, Safety, }; -use crate::token::{self, CommentKind, Delimiter, InvisibleOrigin, MetaVarKind, Token}; +use crate::token::{ + self, CommentKind, Delimiter, DocFragmentKind, InvisibleOrigin, MetaVarKind, Token, +}; use crate::tokenstream::{ DelimSpan, LazyAttrTokenStream, Spacing, TokenStream, TokenStreamIter, TokenTree, }; @@ -179,15 +181,21 @@ impl AttributeExt for Attribute { } /// Returns the documentation and its kind if this is a doc comment or a sugared doc comment. - /// * `///doc` returns `Some(("doc", CommentKind::Line))`. - /// * `/** doc */` returns `Some(("doc", CommentKind::Block))`. - /// * `#[doc = "doc"]` returns `Some(("doc", CommentKind::Line))`. + /// * `///doc` returns `Some(("doc", DocFragmentKind::Sugared(CommentKind::Line)))`. + /// * `/** doc */` returns `Some(("doc", DocFragmentKind::Sugared(CommentKind::Block)))`. + /// * `#[doc = "doc"]` returns `Some(("doc", DocFragmentKind::Raw))`. /// * `#[doc(...)]` returns `None`. - fn doc_str_and_comment_kind(&self) -> Option<(Symbol, CommentKind)> { + fn doc_str_and_fragment_kind(&self) -> Option<(Symbol, DocFragmentKind)> { match &self.kind { - AttrKind::DocComment(kind, data) => Some((*data, *kind)), + AttrKind::DocComment(kind, data) => Some((*data, DocFragmentKind::Sugared(*kind))), AttrKind::Normal(normal) if normal.item.path == sym::doc => { - normal.item.value_str().map(|s| (s, CommentKind::Line)) + if let Some(value) = normal.item.value_str() + && let Some(value_span) = normal.item.value_span() + { + Some((value, DocFragmentKind::Raw(value_span))) + } else { + None + } } _ => None, } @@ -305,6 +313,25 @@ impl AttrItem { } } + /// Returns the span in: + /// + /// ```text + /// #[attribute = "value"] + /// ^^^^^^^ + /// ``` + /// + /// It returns `None` in any other cases like: + /// + /// ```text + /// #[attr("value")] + /// ``` + fn value_span(&self) -> Option { + match &self.args { + AttrArgs::Eq { expr, .. } => Some(expr.span), + AttrArgs::Delimited(_) | AttrArgs::Empty => None, + } + } + pub fn meta(&self, span: Span) -> Option { Some(MetaItem { unsafety: Safety::Default, @@ -825,7 +852,7 @@ pub trait AttributeExt: Debug { /// * `/** doc */` returns `Some(("doc", CommentKind::Block))`. /// * `#[doc = "doc"]` returns `Some(("doc", CommentKind::Line))`. /// * `#[doc(...)]` returns `None`. - fn doc_str_and_comment_kind(&self) -> Option<(Symbol, CommentKind)>; + fn doc_str_and_fragment_kind(&self) -> Option<(Symbol, DocFragmentKind)>; /// Returns outer or inner if this is a doc attribute or a sugared doc /// comment, otherwise None. @@ -910,7 +937,7 @@ impl Attribute { AttributeExt::is_proc_macro_attr(self) } - pub fn doc_str_and_comment_kind(&self) -> Option<(Symbol, CommentKind)> { - AttributeExt::doc_str_and_comment_kind(self) + pub fn doc_str_and_fragment_kind(&self) -> Option<(Symbol, DocFragmentKind)> { + AttributeExt::doc_str_and_fragment_kind(self) } } diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index e1231312a2af..accf4d181632 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -16,7 +16,31 @@ use rustc_span::{Ident, Symbol}; use crate::ast; use crate::util::case::Case; -#[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)] +/// Represents the kind of doc comment it is, ie `///` or `#[doc = ""]`. +#[derive(Clone, Copy, PartialEq, Eq, Encodable, Decodable, Debug, HashStable_Generic)] +pub enum DocFragmentKind { + /// A sugared doc comment: `///` or `//!` or `/**` or `/*!`. + Sugared(CommentKind), + /// A "raw" doc comment: `#[doc = ""]`. The `Span` represents the string literal. + Raw(Span), +} + +impl DocFragmentKind { + pub fn is_sugared(self) -> bool { + matches!(self, Self::Sugared(_)) + } + + /// If it is `Sugared`, it will return its associated `CommentKind`, otherwise it will return + /// `CommentKind::Line`. + pub fn comment_kind(self) -> CommentKind { + match self { + Self::Sugared(kind) => kind, + Self::Raw(_) => CommentKind::Line, + } + } +} + +#[derive(Clone, Copy, PartialEq, Eq, Encodable, Decodable, Debug, HashStable_Generic)] pub enum CommentKind { Line, Block, diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 3dce0498efbf..35e47fed9f7a 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -10,7 +10,7 @@ use std::borrow::Cow; use std::sync::Arc; use rustc_ast::attr::AttrIdGenerator; -use rustc_ast::token::{self, CommentKind, Delimiter, Token, TokenKind}; +use rustc_ast::token::{self, CommentKind, Delimiter, DocFragmentKind, Token, TokenKind}; use rustc_ast::tokenstream::{Spacing, TokenStream, TokenTree}; use rustc_ast::util::classify; use rustc_ast::util::comments::{Comment, CommentStyle}; @@ -381,15 +381,24 @@ fn space_between(tt1: &TokenTree, tt2: &TokenTree) -> bool { } pub fn doc_comment_to_string( - comment_kind: CommentKind, + fragment_kind: DocFragmentKind, attr_style: ast::AttrStyle, data: Symbol, ) -> String { - match (comment_kind, attr_style) { - (CommentKind::Line, ast::AttrStyle::Outer) => format!("///{data}"), - (CommentKind::Line, ast::AttrStyle::Inner) => format!("//!{data}"), - (CommentKind::Block, ast::AttrStyle::Outer) => format!("/**{data}*/"), - (CommentKind::Block, ast::AttrStyle::Inner) => format!("/*!{data}*/"), + match fragment_kind { + DocFragmentKind::Sugared(comment_kind) => match (comment_kind, attr_style) { + (CommentKind::Line, ast::AttrStyle::Outer) => format!("///{data}"), + (CommentKind::Line, ast::AttrStyle::Inner) => format!("//!{data}"), + (CommentKind::Block, ast::AttrStyle::Outer) => format!("/**{data}*/"), + (CommentKind::Block, ast::AttrStyle::Inner) => format!("/*!{data}*/"), + }, + DocFragmentKind::Raw(_) => { + format!( + "#{}[doc = {:?}]", + if attr_style == ast::AttrStyle::Inner { "!" } else { "" }, + data.to_string(), + ) + } } } @@ -665,7 +674,11 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere self.word("]"); } ast::AttrKind::DocComment(comment_kind, data) => { - self.word(doc_comment_to_string(*comment_kind, attr.style, *data)); + self.word(doc_comment_to_string( + DocFragmentKind::Sugared(*comment_kind), + attr.style, + *data, + )); self.hardbreak() } } @@ -1029,7 +1042,8 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere /* Other */ token::DocComment(comment_kind, attr_style, data) => { - doc_comment_to_string(comment_kind, attr_style, data).into() + doc_comment_to_string(DocFragmentKind::Sugared(comment_kind), attr_style, data) + .into() } token::Eof => "".into(), } diff --git a/compiler/rustc_attr_parsing/src/attributes/doc.rs b/compiler/rustc_attr_parsing/src/attributes/doc.rs index fbe1ac63ab9c..1a7d8ec93f70 100644 --- a/compiler/rustc_attr_parsing/src/attributes/doc.rs +++ b/compiler/rustc_attr_parsing/src/attributes/doc.rs @@ -474,7 +474,9 @@ impl DocParser { if nv.value_as_str().is_none() { cx.expected_string_literal(nv.value_span, Some(nv.value_as_lit())); } else { - unreachable!("Should have been handled at the same time as sugar-syntaxed doc comments"); + unreachable!( + "Should have been handled at the same time as sugar-syntaxed doc comments" + ); } } } diff --git a/compiler/rustc_attr_parsing/src/interface.rs b/compiler/rustc_attr_parsing/src/interface.rs index feb7bbcb6234..b1538b447da0 100644 --- a/compiler/rustc_attr_parsing/src/interface.rs +++ b/compiler/rustc_attr_parsing/src/interface.rs @@ -2,7 +2,7 @@ use std::borrow::Cow; use rustc_ast as ast; use rustc_ast::{AttrStyle, NodeId, Safety}; -use rustc_ast::token::CommentKind; +use rustc_ast::token::DocFragmentKind; use rustc_errors::DiagCtxtHandle; use rustc_feature::{AttributeTemplate, Features}; use rustc_hir::attrs::AttributeKind; @@ -295,7 +295,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { attributes.push(Attribute::Parsed(AttributeKind::DocComment { style: attr.style, - kind: *comment_kind, + kind: DocFragmentKind::Sugared(*comment_kind), span: lower_span(attr.span), comment: *symbol, })) @@ -350,8 +350,8 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { { attributes.push(Attribute::Parsed(AttributeKind::DocComment { style: attr.style, - kind: CommentKind::Block, - span: nv.value_span, + kind: DocFragmentKind::Raw(nv.value_span), + span: attr.span, comment, })); continue; diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index 39008914f9ef..87a4cf7823f5 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -3,7 +3,7 @@ use std::path::PathBuf; pub use ReprAttr::*; use rustc_abi::Align; -use rustc_ast::token::CommentKind; +use rustc_ast::token::DocFragmentKind; use rustc_ast::{AttrStyle, ast}; use rustc_data_structures::fx::FxIndexMap; use rustc_error_messages::{DiagArgValue, IntoDiagArg}; @@ -648,7 +648,7 @@ pub enum AttributeKind { /// Represents specifically [`#[doc = "..."]`](https://doc.rust-lang.org/stable/rustdoc/write-documentation/the-doc-attribute.html). /// i.e. doc comments. - DocComment { style: AttrStyle, kind: CommentKind, span: Span, comment: Symbol }, + DocComment { style: AttrStyle, kind: DocFragmentKind, span: Span, comment: Symbol }, /// Represents `#[rustc_dummy]`. Dummy, diff --git a/compiler/rustc_hir/src/attrs/pretty_printing.rs b/compiler/rustc_hir/src/attrs/pretty_printing.rs index 75886fb08a2e..29df586ed296 100644 --- a/compiler/rustc_hir/src/attrs/pretty_printing.rs +++ b/compiler/rustc_hir/src/attrs/pretty_printing.rs @@ -1,7 +1,7 @@ use std::num::NonZero; use rustc_abi::Align; -use rustc_ast::token::CommentKind; +use rustc_ast::token::{CommentKind, DocFragmentKind}; use rustc_ast::{AttrStyle, IntTy, UintTy}; use rustc_ast_pretty::pp::Printer; use rustc_data_structures::fx::FxIndexMap; @@ -167,6 +167,7 @@ print_debug!( Align, AttrStyle, CommentKind, + DocFragmentKind, Transparency, SanitizerSet, ); diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index e6a0f430b63a..afa1a33fe769 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -4,7 +4,7 @@ use std::fmt; use rustc_abi::ExternAbi; use rustc_ast::attr::AttributeExt; -use rustc_ast::token::CommentKind; +use rustc_ast::token::DocFragmentKind; use rustc_ast::util::parser::ExprPrecedence; use rustc_ast::{ self as ast, FloatTy, InlineAsmOptions, InlineAsmTemplatePiece, IntTy, Label, LitIntType, @@ -1385,7 +1385,7 @@ impl AttributeExt for Attribute { } #[inline] - fn doc_str_and_comment_kind(&self) -> Option<(Symbol, CommentKind)> { + fn doc_str_and_fragment_kind(&self) -> Option<(Symbol, DocFragmentKind)> { match &self { Attribute::Parsed(AttributeKind::DocComment { kind, comment, .. }) => { Some((*comment, *kind)) @@ -1503,8 +1503,8 @@ impl Attribute { } #[inline] - pub fn doc_str_and_comment_kind(&self) -> Option<(Symbol, CommentKind)> { - AttributeExt::doc_str_and_comment_kind(self) + pub fn doc_str_and_fragment_kind(&self) -> Option<(Symbol, DocFragmentKind)> { + AttributeExt::doc_str_and_fragment_kind(self) } } diff --git a/compiler/rustc_resolve/src/rustdoc.rs b/compiler/rustc_resolve/src/rustdoc.rs index 3c0a89b7c8a7..0ac8e68ad968 100644 --- a/compiler/rustc_resolve/src/rustdoc.rs +++ b/compiler/rustc_resolve/src/rustdoc.rs @@ -10,6 +10,7 @@ use pulldown_cmark::{ use rustc_ast as ast; use rustc_ast::attr::AttributeExt; use rustc_ast::join_path_syms; +use rustc_ast::token::DocFragmentKind; use rustc_ast::util::comments::beautify_doc_string; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::unord::UnordSet; @@ -23,14 +24,6 @@ use tracing::{debug, trace}; #[cfg(test)] mod tests; -#[derive(Clone, Copy, PartialEq, Eq, Debug)] -pub enum DocFragmentKind { - /// A doc fragment created from a `///` or `//!` doc comment. - SugaredDoc, - /// A doc fragment created from a "raw" `#[doc=""]` attribute. - RawDoc, -} - /// A portion of documentation, extracted from a `#[doc]` attribute. /// /// Each variant contains the line number within the complete doc-comment where the fragment @@ -125,7 +118,7 @@ pub fn unindent_doc_fragments(docs: &mut [DocFragment]) { // // In this case, you want "hello! another" and not "hello! another". let add = if docs.windows(2).any(|arr| arr[0].kind != arr[1].kind) - && docs.iter().any(|d| d.kind == DocFragmentKind::SugaredDoc) + && docs.iter().any(|d| d.kind.is_sugared()) { // In case we have a mix of sugared doc comments and "raw" ones, we want the sugared one to // "decide" how much the minimum indent will be. @@ -155,8 +148,7 @@ pub fn unindent_doc_fragments(docs: &mut [DocFragment]) { // Compare against either space or tab, ignoring whether they are // mixed or not. let whitespace = line.chars().take_while(|c| *c == ' ' || *c == '\t').count(); - whitespace - + (if fragment.kind == DocFragmentKind::SugaredDoc { 0 } else { add }) + whitespace + (if fragment.kind.is_sugared() { 0 } else { add }) }) .min() .unwrap_or(usize::MAX) @@ -171,7 +163,7 @@ pub fn unindent_doc_fragments(docs: &mut [DocFragment]) { continue; } - let indent = if fragment.kind != DocFragmentKind::SugaredDoc && min_indent > 0 { + let indent = if !fragment.kind.is_sugared() && min_indent > 0 { min_indent - add } else { min_indent @@ -214,19 +206,17 @@ pub fn attrs_to_doc_fragments<'a, A: AttributeExt + Clone + 'a>( let mut doc_fragments = Vec::with_capacity(size_hint); let mut other_attrs = ThinVec::::with_capacity(if doc_only { 0 } else { size_hint }); for (attr, item_id) in attrs { - if let Some((doc_str, comment_kind)) = attr.doc_str_and_comment_kind() { - let doc = beautify_doc_string(doc_str, comment_kind); - let (span, kind, from_expansion) = if let Some(span) = attr.is_doc_comment() { - (span, DocFragmentKind::SugaredDoc, span.from_expansion()) - } else { - let attr_span = attr.span(); - let (span, from_expansion) = match attr.value_span() { - Some(sp) => (sp.with_ctxt(attr_span.ctxt()), sp.from_expansion()), - None => (attr_span, attr_span.from_expansion()), - }; - (span, DocFragmentKind::RawDoc, from_expansion) + if let Some((doc_str, fragment_kind)) = attr.doc_str_and_fragment_kind() { + let doc = beautify_doc_string(doc_str, fragment_kind.comment_kind()); + let attr_span = attr.span(); + let (span, from_expansion) = match fragment_kind { + DocFragmentKind::Sugared(_) => (attr_span, attr_span.from_expansion()), + DocFragmentKind::Raw(value_span) => { + (value_span.with_ctxt(attr_span.ctxt()), value_span.from_expansion()) + } }; - let fragment = DocFragment { span, doc, kind, item_id, indent: 0, from_expansion }; + let fragment = + DocFragment { span, doc, kind: fragment_kind, item_id, indent: 0, from_expansion }; doc_fragments.push(fragment); } else if !doc_only { other_attrs.push(attr.clone()); @@ -571,7 +561,7 @@ pub fn source_span_for_markdown_range_inner( use rustc_span::BytePos; if let &[fragment] = &fragments - && fragment.kind == DocFragmentKind::RawDoc + && !fragment.kind.is_sugared() && let Ok(snippet) = map.span_to_snippet(fragment.span) && snippet.trim_end() == markdown.trim_end() && let Ok(md_range_lo) = u32::try_from(md_range.start) @@ -589,7 +579,7 @@ pub fn source_span_for_markdown_range_inner( )); } - let is_all_sugared_doc = fragments.iter().all(|frag| frag.kind == DocFragmentKind::SugaredDoc); + let is_all_sugared_doc = fragments.iter().all(|frag| frag.kind.is_sugared()); if !is_all_sugared_doc { // This case ignores the markdown outside of the range so that it can diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 12dcb198bd21..40191d5c98e0 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -2403,7 +2403,7 @@ mod size_asserts { use super::*; // tidy-alphabetical-start static_assert_size!(Crate, 16); // frequently moved by-value - static_assert_size!(DocFragment, 32); + static_assert_size!(DocFragment, 48); static_assert_size!(GenericArg, 32); static_assert_size!(GenericArgs, 24); static_assert_size!(GenericParamDef, 40); From 92edc499a69a24e69e6fcc2641dc9bca1098bd5b Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 28 Nov 2025 16:50:16 +0100 Subject: [PATCH 12/64] Correctly handle doc items inlining --- src/librustdoc/clean/mod.rs | 21 +++++++++++++-------- src/librustdoc/clean/types.rs | 31 ------------------------------- src/librustdoc/visit_ast.rs | 18 +++++++----------- 3 files changed, 20 insertions(+), 50 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 6fd578628388..bea4398ccf86 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -196,9 +196,12 @@ fn generate_item_with_correct_attrs( // For glob re-exports the item may or may not exist to be re-exported (potentially the // cfgs on the path up until the glob can be removed, and only cfgs on the globbed item // itself matter), for non-inlined re-exports see #85043. - let import_is_inline = find_attr!(inline::load_attrs(cx, import_id.to_def_id()), AttributeKind::Doc(d) if d.inline.is_some()) - || (is_glob_import(cx.tcx, import_id) - && (cx.document_hidden() || !cx.tcx.is_doc_hidden(def_id))); + let import_is_inline = find_attr!( + inline::load_attrs(cx, import_id.to_def_id()), + AttributeKind::Doc(d) + if d.inline.is_some_and(|(inline, _)| inline == DocInline::Inline) + ) || (is_glob_import(cx.tcx, import_id) + && (cx.document_hidden() || !cx.tcx.is_doc_hidden(def_id))); attrs.extend(get_all_import_attributes(cx, import_id, def_id, is_inline)); is_inline = is_inline || import_is_inline; } @@ -2666,10 +2669,10 @@ fn add_without_unwanted_attributes<'hir>( let DocAttribute { hidden, inline, cfg, .. } = d; let mut attr = DocAttribute::default(); if is_inline { + attr.cfg = cfg.clone(); + } else { attr.inline = inline.clone(); attr.hidden = hidden.clone(); - } else { - attr.cfg = cfg.clone(); } attrs.push(( Cow::Owned(hir::Attribute::Parsed(AttributeKind::Doc(Box::new(attr)))), @@ -2914,10 +2917,12 @@ fn clean_extern_crate<'tcx>( let attrs = cx.tcx.hir_attrs(krate.hir_id()); let ty_vis = cx.tcx.visibility(krate.owner_id); let please_inline = ty_vis.is_public() - && attrs.iter().any(|a| matches!( + && attrs.iter().any(|a| { + matches!( a, - hir::Attribute::Parsed(AttributeKind::Doc(d)) if d.inline.is_some_and(|(i, _)| i == DocInline::Inline)) - ) + hir::Attribute::Parsed(AttributeKind::Doc(d)) + if d.inline.is_some_and(|(i, _)| i == DocInline::Inline)) + }) && !cx.is_json_output(); let krate_owner_def_id = krate.owner_id.def_id; diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 40191d5c98e0..cefaf1102fb9 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -929,37 +929,6 @@ pub(crate) struct Module { pub(crate) span: Span, } -pub(crate) fn hir_attr_lists<'a, I: IntoIterator>( - attrs: I, - name: Symbol, -) -> impl Iterator + use<'a, I> { - attrs - .into_iter() - .filter(move |attr| attr.has_name(name)) - .filter_map(ast::attr::AttributeExt::meta_item_list) - .flatten() -} - -pub(crate) trait NestedAttributesExt { - /// Returns `true` if the attribute list contains a specific `word` - fn has_word(self, word: Symbol) -> bool - where - Self: Sized, - { - ::get_word_attr(self, word).is_some() - } - - /// Returns `Some(attr)` if the attribute list contains 'attr' - /// corresponding to a specific `word` - fn get_word_attr(self, word: Symbol) -> Option; -} - -impl> NestedAttributesExt for I { - fn get_word_attr(mut self, word: Symbol) -> Option { - self.find(|attr| attr.is_word() && attr.has_name(word)) - } -} - /// A link that has not yet been rendered. /// /// This link will be turned into a rendered link by [`Item::links`]. diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 51b2821eb1e5..d6da8615d57e 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -3,9 +3,10 @@ use std::mem; +use rustc_ast::attr::AttributeExt; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_hir as hir; -use rustc_hir::attrs::AttributeKind; +use rustc_hir::attrs::{AttributeKind, DocInline}; use rustc_hir::def::{DefKind, MacroKinds, Res}; use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId, LocalDefIdSet}; use rustc_hir::intravisit::{Visitor, walk_body, walk_item}; @@ -14,11 +15,11 @@ use rustc_middle::hir::nested_filter; use rustc_middle::ty::TyCtxt; use rustc_span::Span; use rustc_span::def_id::{CRATE_DEF_ID, LOCAL_CRATE}; -use rustc_span::symbol::{Symbol, kw, sym}; +use rustc_span::symbol::{Symbol, kw}; use tracing::debug; +use crate::clean::reexport_chain; use crate::clean::utils::{inherits_doc_hidden, should_ignore_res}; -use crate::clean::{NestedAttributesExt, hir_attr_lists, reexport_chain}; use crate::core; /// This module is used to store stuff from Rust's AST in a more convenient @@ -246,8 +247,8 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { let document_hidden = self.cx.document_hidden(); let use_attrs = tcx.hir_attrs(tcx.local_def_id_to_hir_id(def_id)); // Don't inline `doc(hidden)` imports so they can be stripped at a later stage. - let is_no_inline = hir_attr_lists(use_attrs, sym::doc).has_word(sym::no_inline) - || (document_hidden && hir_attr_lists(use_attrs, sym::doc).has_word(sym::hidden)); + let is_no_inline = find_attr!(use_attrs, AttributeKind::Doc(d) if d.inline.is_some_and(|(inline, _)| inline == DocInline::NoInline)) + || (document_hidden && use_attrs.iter().any(|attr| attr.is_doc_hidden())); if is_no_inline { return false; @@ -464,12 +465,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { // If there was a private module in the current path then don't bother inlining // anything as it will probably be stripped anyway. if is_pub && self.inside_public_path { - let please_inline = attrs.iter().any(|item| match item.meta_item_list() { - Some(ref list) if item.has_name(sym::doc) => { - list.iter().any(|i| i.has_name(sym::inline)) - } - _ => false, - }); + let please_inline = find_attr!(attrs, AttributeKind::Doc(d) if d.inline.is_some_and(|(inline, _)| inline == DocInline::Inline)); let ident = match kind { hir::UseKind::Single(ident) => Some(ident.name), hir::UseKind::Glob => None, From 368a103902b00b4b0b93d30050ce2da7d5c2b0d9 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 28 Nov 2025 18:49:19 +0100 Subject: [PATCH 13/64] Fix `Cfg` add/or operations --- .../rustc_hir/src/attrs/data_structures.rs | 36 +++++++++++++++---- src/librustdoc/clean/cfg.rs | 24 ++++++------- 2 files changed, 42 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index 87a4cf7823f5..e35af0853651 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -197,14 +197,38 @@ pub enum CfgEntry { impl CfgEntry { pub fn span(&self) -> Span { - let (CfgEntry::All(_, span) - | CfgEntry::Any(_, span) - | CfgEntry::Not(_, span) - | CfgEntry::Bool(_, span) - | CfgEntry::NameValue { span, .. } - | CfgEntry::Version(_, span)) = self; + let (Self::All(_, span) + | Self::Any(_, span) + | Self::Not(_, span) + | Self::Bool(_, span) + | Self::NameValue { span, .. } + | Self::Version(_, span)) = self; *span } + + /// Same as `PartialEq` but doesn't check spans and ignore order of cfgs. + pub fn is_equivalent_to(&self, other: &Self) -> bool { + match (self, other) { + (Self::All(a, _), Self::All(b, _)) | (Self::Any(a, _), Self::Any(b, _)) => { + a.len() == b.len() && a.iter().all(|a| b.iter().any(|b| a.is_equivalent_to(b))) + } + (Self::Not(a, _), Self::Not(b, _)) => a.is_equivalent_to(b), + (Self::Bool(a, _), Self::Bool(b, _)) => a == b, + ( + Self::NameValue { name: name1, value: value1, .. }, + Self::NameValue { name: name2, value: value2, .. }, + ) => { + name1 == name2 + && match (value1, value2) { + (Some((a, _)), Some((b, _))) => a == b, + (None, None) => true, + _ => false, + } + } + (Self::Version(a, _), Self::Version(b, _)) => a == b, + _ => false, + } + } } /// Possible values for the `#[linkage]` attribute, allowing to specify the diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs index 38d3a47f8ca0..9b59e7ce6bef 100644 --- a/src/librustdoc/clean/cfg.rs +++ b/src/librustdoc/clean/cfg.rs @@ -280,13 +280,12 @@ impl Cfg { fn should_append_only_to_description(&self) -> bool { match self.0 { - CfgEntry::Bool(..) => false, CfgEntry::Any(..) | CfgEntry::All(..) | CfgEntry::NameValue { .. } - | CfgEntry::Version(..) => true, - CfgEntry::Not(box CfgEntry::NameValue { .. }, _) => true, - CfgEntry::Not(..) => false, + | CfgEntry::Version(..) + | CfgEntry::Not(box CfgEntry::NameValue { .. }, _) => true, + CfgEntry::Not(..) | CfgEntry::Bool(..) => false, } } @@ -347,25 +346,25 @@ impl ops::BitAndAssign for Cfg { (s @ CfgEntry::Bool(true, _), b) => *s = b, (CfgEntry::All(a, _), CfgEntry::All(ref mut b, _)) => { for c in b.drain(..) { - if !a.contains(&c) { + if !a.iter().any(|a| a.is_equivalent_to(&c)) { a.push(c); } } } (CfgEntry::All(a, _), ref mut b) => { - if !a.contains(b) { + if !a.iter().any(|a| a.is_equivalent_to(b)) { a.push(mem::replace(b, CfgEntry::Bool(true, DUMMY_SP))); } } (s, CfgEntry::All(mut a, _)) => { let b = mem::replace(s, CfgEntry::Bool(true, DUMMY_SP)); - if !a.contains(&b) { + if !a.iter().any(|a| a.is_equivalent_to(&b)) { a.push(b); } *s = CfgEntry::All(a, DUMMY_SP); } (s, b) => { - if *s != b { + if !s.is_equivalent_to(&b) { let a = mem::replace(s, CfgEntry::Bool(true, DUMMY_SP)); *s = CfgEntry::All(thin_vec![a, b], DUMMY_SP); } @@ -391,25 +390,25 @@ impl ops::BitOrAssign for Cfg { (s @ CfgEntry::Bool(false, _), b) => *s = b, (CfgEntry::Any(a, _), CfgEntry::Any(ref mut b, _)) => { for c in b.drain(..) { - if !a.contains(&c) { + if !a.iter().any(|a| a.is_equivalent_to(&c)) { a.push(c); } } } (CfgEntry::Any(a, _), ref mut b) => { - if !a.contains(b) { + if !a.iter().any(|a| a.is_equivalent_to(b)) { a.push(mem::replace(b, CfgEntry::Bool(true, DUMMY_SP))); } } (s, CfgEntry::Any(mut a, _)) => { let b = mem::replace(s, CfgEntry::Bool(true, DUMMY_SP)); - if !a.contains(&b) { + if !a.iter().any(|a| a.is_equivalent_to(&b)) { a.push(b); } *s = CfgEntry::Any(a, DUMMY_SP); } (s, b) => { - if *s != b { + if !s.is_equivalent_to(&b) { let a = mem::replace(s, CfgEntry::Bool(true, DUMMY_SP)); *s = CfgEntry::Any(thin_vec![a, b], DUMMY_SP); } @@ -757,6 +756,7 @@ fn handle_auto_cfg_hide_show( { for item in items { // FIXME: Report in case `Cfg::parse` reports an error? + let Ok(cfg) = Cfg::parse(item) else { continue }; if let CfgEntry::NameValue { name, value, .. } = cfg.0 { let value = value.map(|(v, _)| v); From d35ec316c5496b2eda68ba05b9dd28ba94bfa87e Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 1 Dec 2025 15:31:10 +0100 Subject: [PATCH 14/64] Keep a list of `CfgEntry` instead of just one --- compiler/rustc_attr_parsing/src/attributes/doc.rs | 5 ++++- compiler/rustc_hir/src/attrs/data_structures.rs | 4 ++-- src/librustdoc/clean/cfg.rs | 12 ++++++------ src/librustdoc/passes/collect_trait_impls.rs | 2 +- src/librustdoc/passes/propagate_doc_cfg.rs | 2 +- 5 files changed, 14 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/doc.rs b/compiler/rustc_attr_parsing/src/attributes/doc.rs index 1a7d8ec93f70..5e48ade6b7cf 100644 --- a/compiler/rustc_attr_parsing/src/attributes/doc.rs +++ b/compiler/rustc_attr_parsing/src/attributes/doc.rs @@ -225,7 +225,7 @@ impl DocParser { args: &ArgParser<'_>, ) { if let Some(cfg_entry) = super::cfg::parse_cfg(cx, args) { - self.attribute.cfg = Some(cfg_entry); + self.attribute.cfg.push(cfg_entry); } } @@ -524,6 +524,9 @@ impl AttributeParser for DocParser { fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option { if self.nb_doc_attrs != 0 { + if std::env::var("LOL").is_ok() { + eprintln!("+++++> {:#?}", self.attribute); + } Some(AttributeKind::Doc(Box::new(self.attribute))) } else { None diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index e35af0853651..323a1290bb2a 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -479,7 +479,7 @@ pub struct DocAttribute { pub inline: Option<(DocInline, Span)>, // unstable - pub cfg: Option, + pub cfg: ThinVec, pub auto_cfg: ThinVec, /// This is for `#[doc(auto_cfg = false|true)]`. pub auto_cfg_change: Option<(bool, Span)>, @@ -512,7 +512,7 @@ impl Default for DocAttribute { aliases: FxIndexMap::default(), hidden: None, inline: None, - cfg: None, + cfg: ThinVec::new(), auto_cfg: ThinVec::new(), auto_cfg_change: None, fake_variadic: None, diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs index 9b59e7ce6bef..727ad82eeca5 100644 --- a/src/librustdoc/clean/cfg.rs +++ b/src/librustdoc/clean/cfg.rs @@ -24,7 +24,7 @@ use crate::html::escape::Escape; #[cfg(test)] mod tests; -#[derive(Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Debug, Hash)] pub(crate) struct Cfg(CfgEntry); #[derive(PartialEq, Debug)] @@ -299,13 +299,13 @@ impl Cfg { /// /// See `tests::test_simplify_with` for examples. pub(crate) fn simplify_with(&self, assume: &Self) -> Option { - if self == assume { + if self.0.is_equivalent_to(&assume.0) { None } else if let CfgEntry::All(a, _) = &self.0 { let mut sub_cfgs: ThinVec = if let CfgEntry::All(b, _) = &assume.0 { - a.iter().filter(|a| !b.contains(a)).cloned().collect() + a.iter().filter(|a| !b.iter().any(|b| a.is_equivalent_to(b))).cloned().collect() } else { - a.iter().filter(|&a| *a != assume.0).cloned().collect() + a.iter().filter(|&a| !a.is_equivalent_to(&assume.0)).cloned().collect() }; let len = sub_cfgs.len(); match len { @@ -314,7 +314,7 @@ impl Cfg { _ => Some(Cfg(CfgEntry::All(sub_cfgs, DUMMY_SP))), } } else if let CfgEntry::All(b, _) = &assume.0 - && b.contains(&self.0) + && b.iter().any(|b| b.is_equivalent_to(&self.0)) { None } else { @@ -838,7 +838,7 @@ pub(crate) fn extract_cfg_from_attrs<'a, I: Iterator cfg_info.parent_is_doc_cfg = true; } for attr in doc_cfg { - if let Some(new_cfg) = attr.cfg.clone() { + for new_cfg in attr.cfg.clone() { cfg_info.current_cfg &= Cfg(new_cfg); } } diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs index d71c3eaa2dcb..357d00ef6521 100644 --- a/src/librustdoc/passes/collect_trait_impls.rs +++ b/src/librustdoc/passes/collect_trait_impls.rs @@ -67,7 +67,7 @@ pub(crate) fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) -> let mut parent = Some(tcx.parent(impl_def_id)); while let Some(did) = parent { attr_buf.extend(tcx.get_all_attrs(did).iter().filter_map(|attr| match attr { - Attribute::Parsed(AttributeKind::Doc(d)) if d.cfg.is_some() => { + Attribute::Parsed(AttributeKind::Doc(d)) if !d.cfg.is_empty() => { let mut new_attr = DocAttribute::default(); new_attr.cfg = d.cfg.clone(); Some(Attribute::Parsed(AttributeKind::Doc(Box::new(new_attr)))) diff --git a/src/librustdoc/passes/propagate_doc_cfg.rs b/src/librustdoc/passes/propagate_doc_cfg.rs index 422393592c76..95f5537f394c 100644 --- a/src/librustdoc/passes/propagate_doc_cfg.rs +++ b/src/librustdoc/passes/propagate_doc_cfg.rs @@ -34,7 +34,7 @@ struct CfgPropagator<'a, 'tcx> { fn add_only_cfg_attributes(attrs: &mut Vec, new_attrs: &[Attribute]) { for attr in new_attrs { if let Attribute::Parsed(AttributeKind::Doc(d)) = attr - && d.cfg.is_some() + && !d.cfg.is_empty() { let mut new_attr = DocAttribute::default(); new_attr.cfg = d.cfg.clone(); From 57870b7242e3b3446abad0bc1672b52a46d92e1f Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 1 Dec 2025 17:03:39 +0100 Subject: [PATCH 15/64] Fix `doc(auto_cfg)` attribute parsing --- .../rustc_attr_parsing/src/attributes/doc.rs | 24 ++- .../rustc_hir/src/attrs/data_structures.rs | 8 +- src/librustdoc/clean/cfg.rs | 151 +++++++----------- 3 files changed, 82 insertions(+), 101 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/doc.rs b/compiler/rustc_attr_parsing/src/attributes/doc.rs index 5e48ade6b7cf..fb99f43fced8 100644 --- a/compiler/rustc_attr_parsing/src/attributes/doc.rs +++ b/compiler/rustc_attr_parsing/src/attributes/doc.rs @@ -224,7 +224,21 @@ impl DocParser { cx: &'c mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>, ) { - if let Some(cfg_entry) = super::cfg::parse_cfg(cx, args) { + // This function replaces cases like `cfg(all())` with `true`. + fn simplify_cfg(cfg_entry: &mut CfgEntry) { + match cfg_entry { + CfgEntry::All(cfgs, span) if cfgs.is_empty() => { + *cfg_entry = CfgEntry::Bool(true, *span) + } + CfgEntry::Any(cfgs, span) if cfgs.is_empty() => { + *cfg_entry = CfgEntry::Bool(false, *span) + } + CfgEntry::Not(cfg, _) => simplify_cfg(cfg), + _ => {} + } + } + if let Some(mut cfg_entry) = super::cfg::parse_cfg(cx, args) { + simplify_cfg(&mut cfg_entry); self.attribute.cfg.push(cfg_entry); } } @@ -237,7 +251,7 @@ impl DocParser { ) { match args { ArgParser::NoArgs => { - cx.expected_list(args.span().unwrap_or(path.span())); + self.attribute.auto_cfg_change.push((true, path.span())); } ArgParser::List(list) => { for meta in list.mixed() { @@ -303,6 +317,7 @@ impl DocParser { } } } + self.attribute.auto_cfg.push((cfg_hide_show, path.span())); } } ArgParser::NameValue(nv) => { @@ -311,7 +326,7 @@ impl DocParser { cx.emit_lint(AttributeLintKind::DocAutoCfgWrongLiteral, nv.value_span); return; }; - self.attribute.auto_cfg_change = Some((*bool_value, *span)); + self.attribute.auto_cfg_change.push((*bool_value, *span)); } } } @@ -524,9 +539,6 @@ impl AttributeParser for DocParser { fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option { if self.nb_doc_attrs != 0 { - if std::env::var("LOL").is_ok() { - eprintln!("+++++> {:#?}", self.attribute); - } Some(AttributeKind::Doc(Box::new(self.attribute))) } else { None diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index 323a1290bb2a..4e1de8e5aeae 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -480,9 +480,9 @@ pub struct DocAttribute { // unstable pub cfg: ThinVec, - pub auto_cfg: ThinVec, - /// This is for `#[doc(auto_cfg = false|true)]`. - pub auto_cfg_change: Option<(bool, Span)>, + pub auto_cfg: ThinVec<(CfgHideShow, Span)>, + /// This is for `#[doc(auto_cfg = false|true)]`/`#[doc(auto_cfg)]`. + pub auto_cfg_change: ThinVec<(bool, Span)>, // builtin pub fake_variadic: Option, @@ -514,7 +514,7 @@ impl Default for DocAttribute { inline: None, cfg: ThinVec::new(), auto_cfg: ThinVec::new(), - auto_cfg_change: None, + auto_cfg_change: ThinVec::new(), fake_variadic: None, keyword: None, attribute: None, diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs index 727ad82eeca5..292df1cf9550 100644 --- a/src/librustdoc/clean/cfg.rs +++ b/src/librustdoc/clean/cfg.rs @@ -10,13 +10,13 @@ use itertools::Either; use rustc_ast::{LitKind, MetaItem, MetaItemInner, MetaItemKind, MetaItemLit}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::thin_vec::{ThinVec, thin_vec}; +use rustc_hir as hir; use rustc_hir::Attribute; -use rustc_hir::attrs::{AttributeKind, CfgEntry}; +use rustc_hir::attrs::{self, AttributeKind, CfgEntry, CfgHideShow, HideOrShow}; use rustc_middle::ty::TyCtxt; use rustc_session::parse::ParseSess; use rustc_span::symbol::{Symbol, sym}; use rustc_span::{DUMMY_SP, Span}; -use {rustc_ast as ast, rustc_hir as hir}; use crate::display::{Joined as _, MaybeDisplay, Wrapped}; use crate::html::escape::Escape; @@ -689,6 +689,12 @@ impl<'a> From<&'a CfgEntry> for SimpleCfg { } } +impl<'a> From<&'a attrs::CfgInfo> for SimpleCfg { + fn from(cfg: &'a attrs::CfgInfo) -> Self { + Self { name: cfg.name, value: cfg.value.map(|(value, _)| value) } + } +} + /// This type keeps track of (doc) cfg information as we go down the item tree. #[derive(Clone, Debug)] pub(crate) struct CfgInfo { @@ -746,37 +752,27 @@ fn show_hide_show_conflict_error( fn handle_auto_cfg_hide_show( tcx: TyCtxt<'_>, cfg_info: &mut CfgInfo, - sub_attr: &MetaItemInner, - is_show: bool, + attr: &CfgHideShow, + attr_span: Span, new_show_attrs: &mut FxHashMap<(Symbol, Option), rustc_span::Span>, new_hide_attrs: &mut FxHashMap<(Symbol, Option), rustc_span::Span>, ) { - if let MetaItemInner::MetaItem(item) = sub_attr - && let MetaItemKind::List(items) = &item.kind - { - for item in items { - // FIXME: Report in case `Cfg::parse` reports an error? - - let Ok(cfg) = Cfg::parse(item) else { continue }; - if let CfgEntry::NameValue { name, value, .. } = cfg.0 { - let value = value.map(|(v, _)| v); - let simple = SimpleCfg::from(&cfg.0); - if is_show { - if let Some(span) = new_hide_attrs.get(&(name, value)) { - show_hide_show_conflict_error(tcx, item.span(), *span); - } else { - new_show_attrs.insert((name, value), item.span()); - } - cfg_info.hidden_cfg.remove(&simple); - } else { - if let Some(span) = new_show_attrs.get(&(name, value)) { - show_hide_show_conflict_error(tcx, item.span(), *span); - } else { - new_hide_attrs.insert((name, value), item.span()); - } - cfg_info.hidden_cfg.insert(simple); - } + for value in &attr.values { + let simple = SimpleCfg::from(value); + if attr.kind == HideOrShow::Show { + if let Some(span) = new_hide_attrs.get(&(simple.name, simple.value)) { + show_hide_show_conflict_error(tcx, attr_span, *span); + } else { + new_show_attrs.insert((simple.name, simple.value), attr_span); } + cfg_info.hidden_cfg.remove(&simple); + } else { + if let Some(span) = new_show_attrs.get(&(simple.name, simple.value)) { + show_hide_show_conflict_error(tcx, attr_span, *span); + } else { + new_hide_attrs.insert((simple.name, simple.value), attr_span); + } + cfg_info.hidden_cfg.insert(simple); } } } @@ -797,7 +793,7 @@ pub(crate) fn extract_cfg_from_attrs<'a, I: Iterator fn check_changed_auto_active_status( changed_auto_active_status: &mut Option, - attr: &ast::MetaItem, + attr_span: Span, cfg_info: &mut CfgInfo, tcx: TyCtxt<'_>, new_value: bool, @@ -807,14 +803,14 @@ pub(crate) fn extract_cfg_from_attrs<'a, I: Iterator tcx.sess .dcx() .struct_span_err( - vec![*first_change, attr.span], + vec![*first_change, attr_span], "`auto_cfg` was disabled and enabled more than once on the same item", ) .emit(); return true; } } else { - *changed_auto_active_status = Some(attr.span); + *changed_auto_active_status = Some(attr_span); } cfg_info.auto_cfg_active = new_value; false @@ -826,7 +822,7 @@ pub(crate) fn extract_cfg_from_attrs<'a, I: Iterator let mut doc_cfg = attrs .clone() .filter_map(|attr| match attr { - Attribute::Parsed(AttributeKind::Doc(d)) => Some(d), + Attribute::Parsed(AttributeKind::Doc(d)) if !d.cfg.is_empty() => Some(d), _ => None, }) .peekable(); @@ -850,64 +846,37 @@ pub(crate) fn extract_cfg_from_attrs<'a, I: Iterator // We get all `doc(auto_cfg)`, `cfg` and `target_feature` attributes. for attr in attrs { - if let Some(ident) = attr.ident() - && ident.name == sym::doc - && let Some(attrs) = attr.meta_item_list() - { - for attr in attrs.iter().filter(|attr| attr.has_name(sym::auto_cfg)) { - let MetaItemInner::MetaItem(attr) = attr else { - continue; - }; - match &attr.kind { - MetaItemKind::Word => { - if check_changed_auto_active_status( - &mut changed_auto_active_status, - attr, - cfg_info, - tcx, - true, - ) { - return None; - } - } - MetaItemKind::NameValue(lit) => { - if let LitKind::Bool(value) = lit.kind { - if check_changed_auto_active_status( - &mut changed_auto_active_status, - attr, - cfg_info, - tcx, - value, - ) { - return None; - } - } - } - MetaItemKind::List(sub_attrs) => { - if check_changed_auto_active_status( - &mut changed_auto_active_status, - attr, - cfg_info, - tcx, - true, - ) { - return None; - } - for sub_attr in sub_attrs.iter() { - if let Some(ident) = sub_attr.ident() - && (ident.name == sym::show || ident.name == sym::hide) - { - handle_auto_cfg_hide_show( - tcx, - cfg_info, - &sub_attr, - ident.name == sym::show, - &mut new_show_attrs, - &mut new_hide_attrs, - ); - } - } - } + if let Attribute::Parsed(AttributeKind::Doc(d)) = attr { + for (new_value, span) in &d.auto_cfg_change { + if check_changed_auto_active_status( + &mut changed_auto_active_status, + *span, + cfg_info, + tcx, + *new_value, + ) { + return None; + } + } + if let Some((_, span)) = d.auto_cfg.first() { + if check_changed_auto_active_status( + &mut changed_auto_active_status, + *span, + cfg_info, + tcx, + true, + ) { + return None; + } + for (value, span) in &d.auto_cfg { + handle_auto_cfg_hide_show( + tcx, + cfg_info, + value, + *span, + &mut new_show_attrs, + &mut new_hide_attrs, + ); } } } else if let hir::Attribute::Parsed(AttributeKind::TargetFeature { features, .. }) = attr { From 5c47240ad16fc19d093176c606a7529b54401b9e Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 2 Dec 2025 16:01:20 +0100 Subject: [PATCH 16/64] Correctly handle `doc(test(attr(...)))` --- Cargo.lock | 2 +- compiler/rustc_attr_parsing/src/attributes/doc.rs | 6 +++--- src/librustdoc/Cargo.toml | 2 +- src/librustdoc/doctest.rs | 2 +- src/librustdoc/doctest/rust.rs | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 23708adcc499..d818d87e0804 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4868,9 +4868,9 @@ dependencies = [ "indexmap", "itertools", "minifier", + "proc-macro2", "pulldown-cmark-escape", "regex", - "rustc_proc_macro", "rustdoc-json-types", "serde", "serde_json", diff --git a/compiler/rustc_attr_parsing/src/attributes/doc.rs b/compiler/rustc_attr_parsing/src/attributes/doc.rs index fb99f43fced8..26fb53baf2e4 100644 --- a/compiler/rustc_attr_parsing/src/attributes/doc.rs +++ b/compiler/rustc_attr_parsing/src/attributes/doc.rs @@ -115,9 +115,9 @@ impl DocParser { return; }; - // FIXME: convert list into a Vec of `AttributeKind`. - for _ in list.mixed() { - // self.attribute.test_attrs.push(AttributeKind::parse()); + // FIXME: convert list into a Vec of `AttributeKind` because current code is awful. + for attr in list.mixed() { + self.attribute.test_attrs.push(attr.span()); } } Some(name) => { diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml index 371da896b9fc..dcfc1ffc251e 100644 --- a/src/librustdoc/Cargo.toml +++ b/src/librustdoc/Cargo.toml @@ -15,10 +15,10 @@ base64 = "0.21.7" indexmap = { version = "2", features = ["serde"] } itertools = "0.12" minifier = { version = "0.3.5", default-features = false } +proc-macro2 = "1.0.103" pulldown-cmark-escape = { version = "0.11.0", features = ["simd"] } regex = "1" rustdoc-json-types = { path = "../rustdoc-json-types" } -rustc_proc_macro = { path = "../../compiler/rustc_proc_macro" } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" smallvec = "1.8.1" diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 7541311be05d..19e8fe3e3ed2 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -17,6 +17,7 @@ use std::{panic, str}; pub(crate) use make::{BuildDocTestBuilder, DocTestBuilder}; pub(crate) use markdown::test as test_markdown; +use proc_macro2::{TokenStream, TokenTree}; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxHasher, FxIndexMap, FxIndexSet}; use rustc_errors::emitter::HumanReadableErrorType; use rustc_errors::{ColorConfig, DiagCtxtHandle}; @@ -25,7 +26,6 @@ use rustc_hir::def_id::LOCAL_CRATE; use rustc_hir::{Attribute, CRATE_HIR_ID}; use rustc_interface::interface; use rustc_middle::ty::TyCtxt; -use rustc_proc_macro::{TokenStream, TokenTree}; use rustc_session::config::{self, CrateType, ErrorOutputType, Input}; use rustc_session::lint; use rustc_span::edition::Edition; diff --git a/src/librustdoc/doctest/rust.rs b/src/librustdoc/doctest/rust.rs index e119344a806a..6f294ad96267 100644 --- a/src/librustdoc/doctest/rust.rs +++ b/src/librustdoc/doctest/rust.rs @@ -5,12 +5,12 @@ use std::env; use std::str::FromStr; use std::sync::Arc; +use proc_macro2::{TokenStream, TokenTree}; use rustc_hir::attrs::AttributeKind; use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId}; use rustc_hir::{self as hir, Attribute, CRATE_HIR_ID, intravisit}; use rustc_middle::hir::nested_filter; use rustc_middle::ty::TyCtxt; -use rustc_proc_macro::{TokenStream, TokenTree}; use rustc_resolve::rustdoc::span_of_fragments; use rustc_span::source_map::SourceMap; use rustc_span::{BytePos, DUMMY_SP, FileName, Pos, Span}; From 976d45452a90780a3e0b850dfb635232fa2f3058 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 2 Dec 2025 17:25:43 +0100 Subject: [PATCH 17/64] Update rustdoc unit tests --- src/librustdoc/clean/cfg.rs | 3 + src/librustdoc/clean/cfg/tests.rs | 266 +++++++++++++++++----------- src/librustdoc/clean/types/tests.rs | 5 +- 3 files changed, 170 insertions(+), 104 deletions(-) diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs index 292df1cf9550..99409cf838cd 100644 --- a/src/librustdoc/clean/cfg.rs +++ b/src/librustdoc/clean/cfg.rs @@ -25,6 +25,9 @@ use crate::html::escape::Escape; mod tests; #[derive(Clone, Debug, Hash)] +// Because `CfgEntry` includes `Span`, we must NEVER use `==`/`!=` operators on `Cfg` and instead +// use `is_equivalent_to`. +#[cfg_attr(test, derive(PartialEq))] pub(crate) struct Cfg(CfgEntry); #[derive(PartialEq, Debug)] diff --git a/src/librustdoc/clean/cfg/tests.rs b/src/librustdoc/clean/cfg/tests.rs index f0591295da64..4eb6c060cbd2 100644 --- a/src/librustdoc/clean/cfg/tests.rs +++ b/src/librustdoc/clean/cfg/tests.rs @@ -1,23 +1,62 @@ use rustc_ast::ast::LitIntType; use rustc_ast::{MetaItemInner, MetaItemLit, Path, Safety, StrStyle}; use rustc_data_structures::thin_vec::thin_vec; +use rustc_hir::attrs::CfgEntry; use rustc_span::symbol::{Ident, kw}; use rustc_span::{DUMMY_SP, create_default_session_globals_then}; use super::*; -fn word_cfg(s: &str) -> Cfg { - Cfg::Cfg(Symbol::intern(s), None) +fn word_cfg(name: &str) -> Cfg { + Cfg(word_cfg_e(name)) +} + +fn word_cfg_e(name: &str) -> CfgEntry { + CfgEntry::NameValue { + name: Symbol::intern(name), + name_span: DUMMY_SP, + value: None, + span: DUMMY_SP, + } } fn name_value_cfg(name: &str, value: &str) -> Cfg { - Cfg::Cfg(Symbol::intern(name), Some(Symbol::intern(value))) + Cfg(name_value_cfg_e(name, value)) +} + +fn name_value_cfg_e(name: &str, value: &str) -> CfgEntry { + CfgEntry::NameValue { + name: Symbol::intern(name), + name_span: DUMMY_SP, + value: Some((Symbol::intern(value), DUMMY_SP)), + span: DUMMY_SP, + } } fn dummy_lit(symbol: Symbol, kind: LitKind) -> MetaItemInner { MetaItemInner::Lit(MetaItemLit { symbol, suffix: None, kind, span: DUMMY_SP }) } +fn cfg_all(v: ThinVec) -> Cfg { + Cfg(cfg_all_e(v)) +} + +fn cfg_all_e(v: ThinVec) -> CfgEntry { + CfgEntry::All(v, DUMMY_SP) +} + +fn cfg_any(v: ThinVec) -> Cfg { + Cfg(cfg_any_e(v)) +} + +fn cfg_any_e(v: ThinVec) -> CfgEntry { + CfgEntry::Any(v, DUMMY_SP) +} + +fn cfg_not(v: CfgEntry) -> Cfg { + Cfg(CfgEntry::Not(Box::new(v), DUMMY_SP)) +} + fn dummy_meta_item_word(name: &str) -> MetaItemInner { MetaItemInner::MetaItem(MetaItem { unsafety: Safety::Default, @@ -63,40 +102,48 @@ macro_rules! dummy_meta_item_list { }; } +fn cfg_true() -> Cfg { + Cfg(CfgEntry::Bool(true, DUMMY_SP)) +} + +fn cfg_false() -> Cfg { + Cfg(CfgEntry::Bool(false, DUMMY_SP)) +} + #[test] fn test_cfg_not() { create_default_session_globals_then(|| { - assert_eq!(!Cfg::False, Cfg::True); - assert_eq!(!Cfg::True, Cfg::False); - assert_eq!(!word_cfg("test"), Cfg::Not(Box::new(word_cfg("test")))); + assert_eq!(!cfg_false(), cfg_true()); + assert_eq!(!cfg_true(), cfg_false()); + assert_eq!(!word_cfg("test"), cfg_not(word_cfg_e("test"))); assert_eq!( - !Cfg::All(vec![word_cfg("a"), word_cfg("b")]), - Cfg::Not(Box::new(Cfg::All(vec![word_cfg("a"), word_cfg("b")]))) + !cfg_all(thin_vec![word_cfg_e("a"), word_cfg_e("b")]), + cfg_not(cfg_all_e(thin_vec![word_cfg_e("a"), word_cfg_e("b")])) ); assert_eq!( - !Cfg::Any(vec![word_cfg("a"), word_cfg("b")]), - Cfg::Not(Box::new(Cfg::Any(vec![word_cfg("a"), word_cfg("b")]))) + !cfg_any(thin_vec![word_cfg_e("a"), word_cfg_e("b")]), + cfg_not(cfg_any_e(thin_vec![word_cfg_e("a"), word_cfg_e("b")])) ); - assert_eq!(!Cfg::Not(Box::new(word_cfg("test"))), word_cfg("test")); + assert_eq!(!cfg_not(word_cfg_e("test")), word_cfg("test")); }) } #[test] fn test_cfg_and() { create_default_session_globals_then(|| { - let mut x = Cfg::False; - x &= Cfg::True; - assert_eq!(x, Cfg::False); + let mut x = cfg_false(); + x &= cfg_true(); + assert_eq!(x, cfg_false()); x = word_cfg("test"); - x &= Cfg::False; - assert_eq!(x, Cfg::False); + x &= cfg_false(); + assert_eq!(x, cfg_false()); x = word_cfg("test2"); - x &= Cfg::True; + x &= cfg_true(); assert_eq!(x, word_cfg("test2")); - x = Cfg::True; + x = cfg_true(); x &= word_cfg("test3"); assert_eq!(x, word_cfg("test3")); @@ -104,63 +151,69 @@ fn test_cfg_and() { assert_eq!(x, word_cfg("test3")); x &= word_cfg("test4"); - assert_eq!(x, Cfg::All(vec![word_cfg("test3"), word_cfg("test4")])); + assert_eq!(x, cfg_all(thin_vec![word_cfg_e("test3"), word_cfg_e("test4")])); x &= word_cfg("test4"); - assert_eq!(x, Cfg::All(vec![word_cfg("test3"), word_cfg("test4")])); + assert_eq!(x, cfg_all(thin_vec![word_cfg_e("test3"), word_cfg_e("test4")])); x &= word_cfg("test5"); - assert_eq!(x, Cfg::All(vec![word_cfg("test3"), word_cfg("test4"), word_cfg("test5")])); - - x &= Cfg::All(vec![word_cfg("test6"), word_cfg("test7")]); assert_eq!( x, - Cfg::All(vec![ - word_cfg("test3"), - word_cfg("test4"), - word_cfg("test5"), - word_cfg("test6"), - word_cfg("test7"), + cfg_all(thin_vec![word_cfg_e("test3"), word_cfg_e("test4"), word_cfg_e("test5")]) + ); + + x &= cfg_all(thin_vec![word_cfg_e("test6"), word_cfg_e("test7")]); + assert_eq!( + x, + cfg_all(thin_vec![ + word_cfg_e("test3"), + word_cfg_e("test4"), + word_cfg_e("test5"), + word_cfg_e("test6"), + word_cfg_e("test7"), ]) ); - x &= Cfg::All(vec![word_cfg("test6"), word_cfg("test7")]); + x &= cfg_all(thin_vec![word_cfg_e("test6"), word_cfg_e("test7")]); assert_eq!( x, - Cfg::All(vec![ - word_cfg("test3"), - word_cfg("test4"), - word_cfg("test5"), - word_cfg("test6"), - word_cfg("test7"), + cfg_all(thin_vec![ + word_cfg_e("test3"), + word_cfg_e("test4"), + word_cfg_e("test5"), + word_cfg_e("test6"), + word_cfg_e("test7"), ]) ); - let mut y = Cfg::Any(vec![word_cfg("a"), word_cfg("b")]); + let mut y = cfg_any(thin_vec![word_cfg_e("a"), word_cfg_e("b")]); y &= x; assert_eq!( y, - Cfg::All(vec![ - word_cfg("test3"), - word_cfg("test4"), - word_cfg("test5"), - word_cfg("test6"), - word_cfg("test7"), - Cfg::Any(vec![word_cfg("a"), word_cfg("b")]), + cfg_all(thin_vec![ + word_cfg_e("test3"), + word_cfg_e("test4"), + word_cfg_e("test5"), + word_cfg_e("test6"), + word_cfg_e("test7"), + cfg_any_e(thin_vec![word_cfg_e("a"), word_cfg_e("b")]), ]) ); let mut z = word_cfg("test8"); - z &= Cfg::All(vec![word_cfg("test9"), word_cfg("test10")]); - assert_eq!(z, Cfg::All(vec![word_cfg("test9"), word_cfg("test10"), word_cfg("test8")])); + z &= cfg_all(thin_vec![word_cfg_e("test9"), word_cfg_e("test10")]); + assert_eq!( + z, + cfg_all(thin_vec![word_cfg_e("test9"), word_cfg_e("test10"), word_cfg_e("test8"),]), + ); let mut z = word_cfg("test11"); - z &= Cfg::All(vec![word_cfg("test11"), word_cfg("test12")]); - assert_eq!(z, Cfg::All(vec![word_cfg("test11"), word_cfg("test12")])); + z &= cfg_all(thin_vec![word_cfg_e("test11"), word_cfg_e("test12")]); + assert_eq!(z, cfg_all(thin_vec![word_cfg_e("test11"), word_cfg_e("test12")])); assert_eq!( word_cfg("a") & word_cfg("b") & word_cfg("c"), - Cfg::All(vec![word_cfg("a"), word_cfg("b"), word_cfg("c")]) + cfg_all(thin_vec![word_cfg_e("a"), word_cfg_e("b"), word_cfg_e("c")]) ); }) } @@ -168,19 +221,19 @@ fn test_cfg_and() { #[test] fn test_cfg_or() { create_default_session_globals_then(|| { - let mut x = Cfg::True; - x |= Cfg::False; - assert_eq!(x, Cfg::True); + let mut x = cfg_true(); + x |= cfg_false(); + assert_eq!(x, cfg_true()); x = word_cfg("test"); - x |= Cfg::True; + x |= cfg_true(); assert_eq!(x, word_cfg("test")); x = word_cfg("test2"); - x |= Cfg::False; + x |= cfg_false(); assert_eq!(x, word_cfg("test2")); - x = Cfg::False; + x = cfg_false(); x |= word_cfg("test3"); assert_eq!(x, word_cfg("test3")); @@ -188,63 +241,69 @@ fn test_cfg_or() { assert_eq!(x, word_cfg("test3")); x |= word_cfg("test4"); - assert_eq!(x, Cfg::Any(vec![word_cfg("test3"), word_cfg("test4")])); + assert_eq!(x, cfg_any(thin_vec![word_cfg_e("test3"), word_cfg_e("test4")])); x |= word_cfg("test4"); - assert_eq!(x, Cfg::Any(vec![word_cfg("test3"), word_cfg("test4")])); + assert_eq!(x, cfg_any(thin_vec![word_cfg_e("test3"), word_cfg_e("test4")])); x |= word_cfg("test5"); - assert_eq!(x, Cfg::Any(vec![word_cfg("test3"), word_cfg("test4"), word_cfg("test5")])); - - x |= Cfg::Any(vec![word_cfg("test6"), word_cfg("test7")]); assert_eq!( x, - Cfg::Any(vec![ - word_cfg("test3"), - word_cfg("test4"), - word_cfg("test5"), - word_cfg("test6"), - word_cfg("test7"), + cfg_any(thin_vec![word_cfg_e("test3"), word_cfg_e("test4"), word_cfg_e("test5")]) + ); + + x |= cfg_any(thin_vec![word_cfg_e("test6"), word_cfg_e("test7")]); + assert_eq!( + x, + cfg_any(thin_vec![ + word_cfg_e("test3"), + word_cfg_e("test4"), + word_cfg_e("test5"), + word_cfg_e("test6"), + word_cfg_e("test7"), ]) ); - x |= Cfg::Any(vec![word_cfg("test6"), word_cfg("test7")]); + x |= cfg_any(thin_vec![word_cfg_e("test6"), word_cfg_e("test7")]); assert_eq!( x, - Cfg::Any(vec![ - word_cfg("test3"), - word_cfg("test4"), - word_cfg("test5"), - word_cfg("test6"), - word_cfg("test7"), + cfg_any(thin_vec![ + word_cfg_e("test3"), + word_cfg_e("test4"), + word_cfg_e("test5"), + word_cfg_e("test6"), + word_cfg_e("test7"), ]) ); - let mut y = Cfg::All(vec![word_cfg("a"), word_cfg("b")]); + let mut y = cfg_all(thin_vec![word_cfg_e("a"), word_cfg_e("b")]); y |= x; assert_eq!( y, - Cfg::Any(vec![ - word_cfg("test3"), - word_cfg("test4"), - word_cfg("test5"), - word_cfg("test6"), - word_cfg("test7"), - Cfg::All(vec![word_cfg("a"), word_cfg("b")]), + cfg_any(thin_vec![ + word_cfg_e("test3"), + word_cfg_e("test4"), + word_cfg_e("test5"), + word_cfg_e("test6"), + word_cfg_e("test7"), + cfg_all_e(thin_vec![word_cfg_e("a"), word_cfg_e("b")]), ]) ); let mut z = word_cfg("test8"); - z |= Cfg::Any(vec![word_cfg("test9"), word_cfg("test10")]); - assert_eq!(z, Cfg::Any(vec![word_cfg("test9"), word_cfg("test10"), word_cfg("test8")])); + z |= cfg_any(thin_vec![word_cfg_e("test9"), word_cfg_e("test10")]); + assert_eq!( + z, + cfg_any(thin_vec![word_cfg_e("test9"), word_cfg_e("test10"), word_cfg_e("test8")]) + ); let mut z = word_cfg("test11"); - z |= Cfg::Any(vec![word_cfg("test11"), word_cfg("test12")]); - assert_eq!(z, Cfg::Any(vec![word_cfg("test11"), word_cfg("test12")])); + z |= cfg_any(thin_vec![word_cfg_e("test11"), word_cfg_e("test12")]); + assert_eq!(z, cfg_any(thin_vec![word_cfg_e("test11"), word_cfg_e("test12")])); assert_eq!( word_cfg("a") | word_cfg("b") | word_cfg("c"), - Cfg::Any(vec![word_cfg("a"), word_cfg("b"), word_cfg("c")]) + cfg_any(thin_vec![word_cfg_e("a"), word_cfg_e("b"), word_cfg_e("c")]) ); }) } @@ -254,11 +313,11 @@ fn test_parse_ok() { create_default_session_globals_then(|| { let r#true = Symbol::intern("true"); let mi = dummy_lit(r#true, LitKind::Bool(true)); - assert_eq!(Cfg::parse(&mi), Ok(Cfg::True)); + assert_eq!(Cfg::parse(&mi), Ok(cfg_true())); let r#false = Symbol::intern("false"); let mi = dummy_lit(r#false, LitKind::Bool(false)); - assert_eq!(Cfg::parse(&mi), Ok(Cfg::False)); + assert_eq!(Cfg::parse(&mi), Ok(cfg_false())); let mi = dummy_meta_item_word("all"); assert_eq!(Cfg::parse(&mi), Ok(word_cfg("all"))); @@ -464,33 +523,36 @@ fn test_simplify_with() { // This is a tiny subset of things that could be simplified, but it likely covers 90% of // real world usecases well. create_default_session_globals_then(|| { - let foo = word_cfg("foo"); - let bar = word_cfg("bar"); - let baz = word_cfg("baz"); - let quux = word_cfg("quux"); + let foo = word_cfg_e("foo"); + let bar = word_cfg_e("bar"); + let baz = word_cfg_e("baz"); + let quux = word_cfg_e("quux"); - let foobar = Cfg::All(vec![foo.clone(), bar.clone()]); - let barbaz = Cfg::All(vec![bar.clone(), baz.clone()]); - let foobarbaz = Cfg::All(vec![foo.clone(), bar.clone(), baz.clone()]); - let bazquux = Cfg::All(vec![baz.clone(), quux.clone()]); + let foobar = cfg_all(thin_vec![foo.clone(), bar.clone()]); + let barbaz = cfg_all(thin_vec![bar.clone(), baz.clone()]); + let foobarbaz = cfg_all(thin_vec![foo.clone(), bar.clone(), baz.clone()]); + let bazquux = cfg_all(thin_vec![baz.clone(), quux.clone()]); // Unrelated cfgs don't affect each other - assert_eq!(foo.simplify_with(&bar).as_ref(), Some(&foo)); + assert_eq!( + Cfg(foo.clone()).simplify_with(&Cfg(bar.clone())).as_ref(), + Some(&Cfg(foo.clone())) + ); assert_eq!(foobar.simplify_with(&bazquux).as_ref(), Some(&foobar)); // Identical cfgs are eliminated - assert_eq!(foo.simplify_with(&foo), None); + assert_eq!(Cfg(foo.clone()).simplify_with(&Cfg(foo.clone())), None); assert_eq!(foobar.simplify_with(&foobar), None); // Multiple cfgs eliminate a single assumed cfg - assert_eq!(foobar.simplify_with(&foo).as_ref(), Some(&bar)); - assert_eq!(foobar.simplify_with(&bar).as_ref(), Some(&foo)); + assert_eq!(foobar.simplify_with(&Cfg(foo.clone())).as_ref(), Some(&Cfg(bar.clone()))); + assert_eq!(foobar.simplify_with(&Cfg(bar)).as_ref(), Some(&Cfg(foo.clone()))); // A single cfg is eliminated by multiple assumed cfg containing it - assert_eq!(foo.simplify_with(&foobar), None); + assert_eq!(Cfg(foo.clone()).simplify_with(&foobar), None); // Multiple cfgs eliminate the matching subset of multiple assumed cfg - assert_eq!(foobar.simplify_with(&barbaz).as_ref(), Some(&foo)); + assert_eq!(foobar.simplify_with(&barbaz).as_ref(), Some(&Cfg(foo))); assert_eq!(foobar.simplify_with(&foobarbaz), None); }); } diff --git a/src/librustdoc/clean/types/tests.rs b/src/librustdoc/clean/types/tests.rs index 9499507b2c0f..915b7d851a3e 100644 --- a/src/librustdoc/clean/types/tests.rs +++ b/src/librustdoc/clean/types/tests.rs @@ -1,4 +1,5 @@ -use rustc_resolve::rustdoc::{DocFragmentKind, unindent_doc_fragments}; +use rustc_ast::token::{CommentKind, DocFragmentKind}; +use rustc_resolve::rustdoc::unindent_doc_fragments; use rustc_span::create_default_session_globals_then; use super::*; @@ -8,7 +9,7 @@ fn create_doc_fragment(s: &str) -> Vec { span: DUMMY_SP, item_id: None, doc: Symbol::intern(s), - kind: DocFragmentKind::SugaredDoc, + kind: DocFragmentKind::Sugared(CommentKind::Line), indent: 0, from_expansion: false, }] From 9c8c67bfdd864f6ba6eb1bf23b57cd81499c4e2d Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 3 Dec 2025 15:55:57 +0100 Subject: [PATCH 18/64] Fix warning messages --- .../rustc_attr_parsing/src/attributes/doc.rs | 17 +- .../src/session_diagnostics.rs | 9 - .../rustc_hir/src/attrs/data_structures.rs | 6 +- compiler/rustc_metadata/src/rmeta/encoder.rs | 2 +- compiler/rustc_passes/messages.ftl | 12 +- compiler/rustc_passes/src/check_attr.rs | 28 ++- compiler/rustc_passes/src/errors.rs | 8 + src/librustdoc/clean/mod.rs | 14 +- src/librustdoc/lib.rs | 14 ++ src/librustdoc/visit_ast.rs | 14 +- tests/rustdoc-ui/bad-render-options.rs | 36 ++- tests/rustdoc-ui/bad-render-options.stderr | 209 +++++++++++++++--- .../rustdoc-ui/cfg-hide-show-conflict.stderr | 8 +- .../check-doc-alias-attr-location.stderr | 16 +- tests/rustdoc-ui/check-doc-alias-attr.stderr | 61 +++-- tests/rustdoc-ui/doc-alias-assoc-const.stderr | 4 +- tests/rustdoc-ui/doc-alias-same-name.stderr | 6 +- .../rustdoc-ui/doc-include-suggestion.stderr | 2 +- tests/rustdoc-ui/lints/doc_cfg_hide.stderr | 8 +- tests/rustdoc-ui/lints/invalid-doc-attr.rs | 2 - .../rustdoc-ui/lints/invalid-doc-attr.stderr | 36 +-- 21 files changed, 377 insertions(+), 135 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/doc.rs b/compiler/rustc_attr_parsing/src/attributes/doc.rs index 26fb53baf2e4..1fd7b702e92f 100644 --- a/compiler/rustc_attr_parsing/src/attributes/doc.rs +++ b/compiler/rustc_attr_parsing/src/attributes/doc.rs @@ -2,7 +2,6 @@ #![allow(unused_imports)] use rustc_ast::ast::{AttrStyle, LitKind, MetaItemLit}; -use rustc_errors::MultiSpan; use rustc_feature::template; use rustc_hir::attrs::{ AttributeKind, CfgEntry, CfgHideShow, CfgInfo, DocAttribute, DocInline, HideOrShow, @@ -18,7 +17,7 @@ use crate::fluent_generated as fluent; use crate::parser::{ArgParser, MetaItemOrLitParser, MetaItemParser, PathParser}; use crate::session_diagnostics::{ DocAliasBadChar, DocAliasEmpty, DocAliasMalformed, DocAliasStartEnd, DocAttributeNotAttribute, - DocKeywordConflict, DocKeywordNotKeyword, + DocKeywordNotKeyword, }; fn check_keyword(cx: &mut AcceptContext<'_, '_, S>, keyword: Symbol, span: Span) -> bool { @@ -204,19 +203,7 @@ impl DocParser { return; } - let span = path.span(); - - if let Some((prev_inline, prev_span)) = self.attribute.inline { - if prev_inline == inline { - let mut spans = MultiSpan::from_spans(vec![prev_span, span]); - spans.push_span_label(prev_span, fluent::attr_parsing_doc_inline_conflict_first); - spans.push_span_label(span, fluent::attr_parsing_doc_inline_conflict_second); - cx.emit_err(DocKeywordConflict { spans }); - return; - } - } - - self.attribute.inline = Some((inline, span)); + self.attribute.inline.push((inline, path.span())); } fn parse_cfg<'c, S: Stage>( diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index 26b615448e3b..38ae597000d2 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -4,7 +4,6 @@ use rustc_ast::{self as ast}; use rustc_errors::codes::*; use rustc_errors::{ Applicability, Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, - MultiSpan, }; use rustc_feature::AttributeTemplate; use rustc_hir::AttrPath; @@ -589,14 +588,6 @@ pub(crate) struct DocAliasDuplicated { pub first_defn: Span, } -#[derive(Diagnostic)] -#[diag(attr_parsing_doc_inline_conflict)] -#[help] -pub(crate) struct DocKeywordConflict { - #[primary_span] - pub spans: MultiSpan, -} - #[derive(Diagnostic)] #[diag(attr_parsing_link_ordinal_out_of_range)] #[note] diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index 4e1de8e5aeae..0419e219afe4 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -476,7 +476,9 @@ pub struct CfgHideShow { pub struct DocAttribute { pub aliases: FxIndexMap, pub hidden: Option, - pub inline: Option<(DocInline, Span)>, + // Because we need to emit the error if there is more than one `inline` attribute on an item + // at the same time as the other doc attributes, we store a list instead of using `Option`. + pub inline: ThinVec<(DocInline, Span)>, // unstable pub cfg: ThinVec, @@ -511,7 +513,7 @@ impl Default for DocAttribute { Self { aliases: FxIndexMap::default(), hidden: None, - inline: None, + inline: ThinVec::new(), cfg: ThinVec::new(), auto_cfg: ThinVec::new(), auto_cfg_change: ThinVec::new(), diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 9a1cf7f349fd..2069c06c3f77 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -880,7 +880,7 @@ fn analyze_attr(attr: &hir::Attribute, state: &mut AnalyzeAttrState<'_>) -> bool } else if let hir::Attribute::Parsed(AttributeKind::Doc(d)) = attr { // If this is a `doc` attribute that doesn't have anything except maybe `inline` (as in // `#[doc(inline)]`), then we can remove it. It won't be inlinable in downstream crates. - if d.inline.is_none() { + if d.inline.is_empty() { should_encode = true; if d.hidden.is_some() { state.is_doc_hidden = true; diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 007ce22c01e6..4e8973e4928b 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -107,10 +107,10 @@ passes_diagnostic_item_first_defined = the diagnostic item is first defined here passes_doc_alias_bad_location = - doc alias attribute isn't allowed on {$location} + `#[doc(alias = "...")]` isn't allowed on {$location} passes_doc_alias_not_an_alias = - {$attr_str} is the same as the item's name + `#[doc(alias = "{$attr_str}"]` is the same as the item's name passes_doc_attr_not_crate_level = `#![doc({$attr_name} = "...")]` isn't allowed as a crate-level attribute @@ -118,7 +118,15 @@ passes_doc_attr_not_crate_level = passes_doc_fake_variadic_not_valid = `#[doc(fake_variadic)]` must be used on the first of a set of tuple or fn pointer trait impls with varying arity +passes_doc_inline_conflict = + conflicting doc inlining attributes + .help = remove one of the conflicting attributes +passes_doc_inline_conflict_first = + this attribute... + +passes_doc_inline_conflict_second = + {"."}..conflicts with this attribute passes_doc_inline_only_use = this attribute can only be applied to a `use` item diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index bae15de4bf88..3f29d943e7d3 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -13,13 +13,14 @@ use rustc_abi::{Align, ExternAbi, Size}; use rustc_ast::{AttrStyle, LitKind, MetaItemKind, ast}; use rustc_attr_parsing::{AttributeParser, Late}; use rustc_data_structures::fx::FxHashMap; -use rustc_errors::{DiagCtxtHandle, IntoDiagArg, StashKey}; +use rustc_errors::{DiagCtxtHandle, IntoDiagArg, MultiSpan, StashKey}; use rustc_feature::{ ACCEPTED_LANG_FEATURES, AttributeDuplicates, AttributeType, BUILTIN_ATTRIBUTE_MAP, BuiltinAttribute, }; use rustc_hir::attrs::{ - AttributeKind, DocAttribute, InlineAttr, MirDialect, MirPhase, ReprAttr, SanitizerSet, + AttributeKind, DocAttribute, DocInline, InlineAttr, MirDialect, MirPhase, ReprAttr, + SanitizerSet, }; use rustc_hir::def::DefKind; use rustc_hir::def_id::LocalModDefId; @@ -881,7 +882,24 @@ impl<'tcx> CheckAttrVisitor<'tcx> { /// already seen an inlining attribute for this item. /// If so, `specified_inline` holds the value and the span of /// the first `inline`/`no_inline` attribute. - fn check_doc_inline(&self, span: Span, hir_id: HirId, target: Target) { + fn check_doc_inline(&self, hir_id: HirId, target: Target, inline: &[(DocInline, Span)]) { + let span = match inline { + [] => return, + [(_, span)] => *span, + [(inline, span), rest @ ..] => { + for (inline2, span2) in rest { + if inline2 != inline { + let mut spans = MultiSpan::from_spans(vec![*span, *span2]); + spans.push_span_label(*span, fluent::passes_doc_inline_conflict_first); + spans.push_span_label(*span2, fluent::passes_doc_inline_conflict_second); + self.dcx().emit_err(errors::DocInlineConflict { spans }); + return; + } + } + *span + } + }; + match target { Target::Use | Target::ExternCrate => {} _ => { @@ -1050,9 +1068,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - if let Some((_, span)) = inline { - self.check_doc_inline(*span, hir_id, target) - } + self.check_doc_inline(hir_id, target, inline); if let Some(span) = rust_logo { if self.check_attr_crate_level(*span, hir_id) diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index b693aaf76923..3a2908d14184 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -176,6 +176,14 @@ pub(crate) struct DocSearchUnboxInvalid { pub span: Span, } +#[derive(Diagnostic)] +#[diag(passes_doc_inline_conflict)] +#[help] +pub(crate) struct DocInlineConflict { + #[primary_span] + pub spans: MultiSpan, +} + #[derive(LintDiagnostic)] #[diag(passes_doc_inline_only_use)] #[note] diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index bea4398ccf86..dd5c50d2ba37 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -199,7 +199,7 @@ fn generate_item_with_correct_attrs( let import_is_inline = find_attr!( inline::load_attrs(cx, import_id.to_def_id()), AttributeKind::Doc(d) - if d.inline.is_some_and(|(inline, _)| inline == DocInline::Inline) + if d.inline.first().is_some_and(|(inline, _)| *inline == DocInline::Inline) ) || (is_glob_import(cx.tcx, import_id) && (cx.document_hidden() || !cx.tcx.is_doc_hidden(def_id))); attrs.extend(get_all_import_attributes(cx, import_id, def_id, is_inline)); @@ -2921,7 +2921,7 @@ fn clean_extern_crate<'tcx>( matches!( a, hir::Attribute::Parsed(AttributeKind::Doc(d)) - if d.inline.is_some_and(|(i, _)| i == DocInline::Inline)) + if d.inline.first().is_some_and(|(i, _)| *i == DocInline::Inline)) }) && !cx.is_json_output(); @@ -2986,9 +2986,9 @@ fn clean_use_statement_inner<'tcx>( let attrs = cx.tcx.hir_attrs(import.hir_id()); let inline_attr = find_attr!( attrs, - AttributeKind::Doc(d) if d.inline.is_some_and(|(i, _)| i == DocInline::Inline) => d + AttributeKind::Doc(d) if d.inline.first().is_some_and(|(i, _)| *i == DocInline::Inline) => d ) - .and_then(|d| d.inline); + .and_then(|d| d.inline.first()); let pub_underscore = visibility.is_public() && name == Some(kw::Underscore); let current_mod = cx.tcx.parent_module_from_def_id(import.owner_id.def_id); let import_def_id = import.owner_id.def_id; @@ -3009,7 +3009,7 @@ fn clean_use_statement_inner<'tcx>( if pub_underscore && let Some((_, inline_span)) = inline_attr { struct_span_code_err!( cx.tcx.dcx(), - inline_span, + *inline_span, E0780, "anonymous imports cannot be inlined" ) @@ -3026,7 +3026,9 @@ fn clean_use_statement_inner<'tcx>( || pub_underscore || attrs.iter().any(|a| matches!( a, - hir::Attribute::Parsed(AttributeKind::Doc(d)) if d.hidden.is_some() || d.inline.is_some_and(|(i, _)| i == DocInline::NoInline))); + hir::Attribute::Parsed(AttributeKind::Doc(d)) + if d.hidden.is_some() || d.inline.first().is_some_and(|(i, _)| *i == DocInline::NoInline) + )); // Also check whether imports were asked to be inlined, in case we're trying to re-export a // crate in Rust 2018+ diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index a0e359032f9b..13be1a04dbc5 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -32,6 +32,7 @@ extern crate rustc_abi; extern crate rustc_ast; extern crate rustc_ast_pretty; +extern crate rustc_attr_parsing; extern crate rustc_data_structures; extern crate rustc_driver; extern crate rustc_errors; @@ -75,6 +76,7 @@ use std::process; use rustc_errors::DiagCtxtHandle; use rustc_hir::def_id::LOCAL_CRATE; +use rustc_hir::lints::DelayedLint; use rustc_interface::interface; use rustc_middle::ty::TyCtxt; use rustc_session::config::{ErrorOutputType, RustcOptGroup, make_crate_type_option}; @@ -900,6 +902,18 @@ fn main_args(early_dcx: &mut EarlyDiagCtxt, at_args: &[String]) { return; } + for owner_id in tcx.hir_crate_items(()).delayed_lint_items() { + if let Some(delayed_lints) = tcx.opt_ast_lowering_delayed_lints(owner_id) { + for lint in &delayed_lints.lints { + match lint { + DelayedLint::AttributeParsing(attribute_lint) => { + rustc_attr_parsing::emit_attribute_lint(attribute_lint, tcx) + } + } + } + } + } + if render_opts.dep_info().is_some() { rustc_interface::passes::write_dep_info(tcx); } diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index d6da8615d57e..0f4460bed35a 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -247,8 +247,12 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { let document_hidden = self.cx.document_hidden(); let use_attrs = tcx.hir_attrs(tcx.local_def_id_to_hir_id(def_id)); // Don't inline `doc(hidden)` imports so they can be stripped at a later stage. - let is_no_inline = find_attr!(use_attrs, AttributeKind::Doc(d) if d.inline.is_some_and(|(inline, _)| inline == DocInline::NoInline)) - || (document_hidden && use_attrs.iter().any(|attr| attr.is_doc_hidden())); + let is_no_inline = find_attr!( + use_attrs, + AttributeKind::Doc(d) + if d.inline.first().is_some_and(|(inline, _)| *inline == DocInline::NoInline) + ) || (document_hidden + && use_attrs.iter().any(|attr| attr.is_doc_hidden())); if is_no_inline { return false; @@ -465,7 +469,11 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { // If there was a private module in the current path then don't bother inlining // anything as it will probably be stripped anyway. if is_pub && self.inside_public_path { - let please_inline = find_attr!(attrs, AttributeKind::Doc(d) if d.inline.is_some_and(|(inline, _)| inline == DocInline::Inline)); + let please_inline = find_attr!( + attrs, + AttributeKind::Doc(d) + if d.inline.first().is_some_and(|(inline, _)| *inline == DocInline::Inline) + ); let ident = match kind { hir::UseKind::Single(ident) => Some(ident.name), hir::UseKind::Glob => None, diff --git a/tests/rustdoc-ui/bad-render-options.rs b/tests/rustdoc-ui/bad-render-options.rs index f2cfd4b76fa8..0522f68cb6c2 100644 --- a/tests/rustdoc-ui/bad-render-options.rs +++ b/tests/rustdoc-ui/bad-render-options.rs @@ -1,11 +1,29 @@ // regression test for https://github.com/rust-lang/rust/issues/149187 -#![doc(html_favicon_url)] //~ ERROR: `doc(html_favicon_url)` expects a string value [invalid_doc_attributes] -#![doc(html_logo_url)] //~ ERROR: `doc(html_logo_url)` expects a string value [invalid_doc_attributes] -#![doc(html_playground_url)] //~ ERROR: `doc(html_playground_url)` expects a string value [invalid_doc_attributes] -#![doc(issue_tracker_base_url)] //~ ERROR expects a string value -#![doc(html_favicon_url = 1)] //~ ERROR expects a string value -#![doc(html_logo_url = 2)] //~ ERROR expects a string value -#![doc(html_playground_url = 3)] //~ ERROR expects a string value -#![doc(issue_tracker_base_url = 4)] //~ ERROR expects a string value -#![doc(html_no_source = "asdf")] //~ ERROR `doc(html_no_source)` does not accept a value [invalid_doc_attributes] +#![doc(html_favicon_url)] +//~^ ERROR: malformed `doc` attribute +//~| NOTE expected this to be of the form `html_favicon_url = "..."` +#![doc(html_logo_url)] +//~^ ERROR: malformed `doc` attribute +//~| NOTE expected this to be of the form `html_logo_url = "..."` +#![doc(html_playground_url)] +//~^ ERROR: malformed `doc` attribute +//~| NOTE expected this to be of the form `html_playground_url = "..."` +#![doc(issue_tracker_base_url)] +//~^ ERROR: malformed `doc` attribute +//~| NOTE expected this to be of the form `issue_tracker_base_url = "..."` +#![doc(html_favicon_url = 1)] +//~^ ERROR malformed `doc` attribute +//~| NOTE expected a string literal +#![doc(html_logo_url = 2)] +//~^ ERROR malformed `doc` attribute +//~| NOTE expected a string literal +#![doc(html_playground_url = 3)] +//~^ ERROR malformed `doc` attribute +//~| NOTE expected a string literal +#![doc(issue_tracker_base_url = 4)] +//~^ ERROR malformed `doc` attribute +//~| NOTE expected a string literal +#![doc(html_no_source = "asdf")] +//~^ ERROR malformed `doc` attribute +//~| NOTE didn't expect any arguments here diff --git a/tests/rustdoc-ui/bad-render-options.stderr b/tests/rustdoc-ui/bad-render-options.stderr index 9d503363c0bd..e7f33f4dff1d 100644 --- a/tests/rustdoc-ui/bad-render-options.stderr +++ b/tests/rustdoc-ui/bad-render-options.stderr @@ -1,58 +1,211 @@ -error: `doc(html_favicon_url)` expects a string value - --> $DIR/bad-render-options.rs:3:8 +error[E0539]: malformed `doc` attribute input + --> $DIR/bad-render-options.rs:3:1 | LL | #![doc(html_favicon_url)] - | ^^^^^^^^^^^^^^^^ + | ^^^^^^^----------------^^ + | | + | expected this to be of the form `html_favicon_url = "..."` + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #![doc(html_favicon_url)] +LL + #![doc = "string"] + | +LL - #![doc(html_favicon_url)] +LL + #![doc(hidden)] + | +LL - #![doc(html_favicon_url)] +LL + #![doc(inline)] + | +LL - #![doc(html_favicon_url)] +LL + #![doc(test)] | - = note: `#[deny(invalid_doc_attributes)]` on by default -error: `doc(html_logo_url)` expects a string value - --> $DIR/bad-render-options.rs:4:8 +error[E0539]: malformed `doc` attribute input + --> $DIR/bad-render-options.rs:6:1 | LL | #![doc(html_logo_url)] - | ^^^^^^^^^^^^^ + | ^^^^^^^-------------^^ + | | + | expected this to be of the form `html_logo_url = "..."` + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #![doc(html_logo_url)] +LL + #![doc = "string"] + | +LL - #![doc(html_logo_url)] +LL + #![doc(hidden)] + | +LL - #![doc(html_logo_url)] +LL + #![doc(inline)] + | +LL - #![doc(html_logo_url)] +LL + #![doc(test)] + | -error: `doc(html_playground_url)` expects a string value - --> $DIR/bad-render-options.rs:5:8 +error[E0539]: malformed `doc` attribute input + --> $DIR/bad-render-options.rs:9:1 | LL | #![doc(html_playground_url)] - | ^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^-------------------^^ + | | + | expected this to be of the form `html_playground_url = "..."` + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #![doc(html_playground_url)] +LL + #![doc = "string"] + | +LL - #![doc(html_playground_url)] +LL + #![doc(hidden)] + | +LL - #![doc(html_playground_url)] +LL + #![doc(inline)] + | +LL - #![doc(html_playground_url)] +LL + #![doc(test)] + | -error: `doc(issue_tracker_base_url)` expects a string value - --> $DIR/bad-render-options.rs:6:8 +error[E0539]: malformed `doc` attribute input + --> $DIR/bad-render-options.rs:12:1 | LL | #![doc(issue_tracker_base_url)] - | ^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^----------------------^^ + | | + | expected this to be of the form `issue_tracker_base_url = "..."` + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #![doc(issue_tracker_base_url)] +LL + #![doc = "string"] + | +LL - #![doc(issue_tracker_base_url)] +LL + #![doc(hidden)] + | +LL - #![doc(issue_tracker_base_url)] +LL + #![doc(inline)] + | +LL - #![doc(issue_tracker_base_url)] +LL + #![doc(test)] + | -error: `doc(html_favicon_url)` expects a string value - --> $DIR/bad-render-options.rs:7:8 +error[E0539]: malformed `doc` attribute input + --> $DIR/bad-render-options.rs:15:1 | LL | #![doc(html_favicon_url = 1)] - | ^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^-^^ + | | + | expected a string literal here + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #![doc(html_favicon_url = 1)] +LL + #![doc = "string"] + | +LL - #![doc(html_favicon_url = 1)] +LL + #![doc(hidden)] + | +LL - #![doc(html_favicon_url = 1)] +LL + #![doc(inline)] + | +LL - #![doc(html_favicon_url = 1)] +LL + #![doc(test)] + | -error: `doc(html_logo_url)` expects a string value - --> $DIR/bad-render-options.rs:8:8 +error[E0539]: malformed `doc` attribute input + --> $DIR/bad-render-options.rs:18:1 | LL | #![doc(html_logo_url = 2)] - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^-^^ + | | + | expected a string literal here + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #![doc(html_logo_url = 2)] +LL + #![doc = "string"] + | +LL - #![doc(html_logo_url = 2)] +LL + #![doc(hidden)] + | +LL - #![doc(html_logo_url = 2)] +LL + #![doc(inline)] + | +LL - #![doc(html_logo_url = 2)] +LL + #![doc(test)] + | -error: `doc(html_playground_url)` expects a string value - --> $DIR/bad-render-options.rs:9:8 +error[E0539]: malformed `doc` attribute input + --> $DIR/bad-render-options.rs:21:1 | LL | #![doc(html_playground_url = 3)] - | ^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-^^ + | | + | expected a string literal here + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #![doc(html_playground_url = 3)] +LL + #![doc = "string"] + | +LL - #![doc(html_playground_url = 3)] +LL + #![doc(hidden)] + | +LL - #![doc(html_playground_url = 3)] +LL + #![doc(inline)] + | +LL - #![doc(html_playground_url = 3)] +LL + #![doc(test)] + | -error: `doc(issue_tracker_base_url)` expects a string value - --> $DIR/bad-render-options.rs:10:8 +error[E0539]: malformed `doc` attribute input + --> $DIR/bad-render-options.rs:24:1 | LL | #![doc(issue_tracker_base_url = 4)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-^^ + | | + | expected a string literal here + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #![doc(issue_tracker_base_url = 4)] +LL + #![doc = "string"] + | +LL - #![doc(issue_tracker_base_url = 4)] +LL + #![doc(hidden)] + | +LL - #![doc(issue_tracker_base_url = 4)] +LL + #![doc(inline)] + | +LL - #![doc(issue_tracker_base_url = 4)] +LL + #![doc(test)] + | -error: `doc(html_no_source)` does not accept a value - --> $DIR/bad-render-options.rs:11:8 +error[E0565]: malformed `doc` attribute input + --> $DIR/bad-render-options.rs:27:1 | LL | #![doc(html_no_source = "asdf")] - | ^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^--------^^ + | | + | didn't expect any arguments here + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #![doc(html_no_source = "asdf")] +LL + #![doc = "string"] + | +LL - #![doc(html_no_source = "asdf")] +LL + #![doc(hidden)] + | +LL - #![doc(html_no_source = "asdf")] +LL + #![doc(inline)] + | +LL - #![doc(html_no_source = "asdf")] +LL + #![doc(test)] + | error: aborting due to 9 previous errors +Some errors have detailed explanations: E0539, E0565. +For more information about an error, try `rustc --explain E0539`. diff --git a/tests/rustdoc-ui/cfg-hide-show-conflict.stderr b/tests/rustdoc-ui/cfg-hide-show-conflict.stderr index 22231e82cd7b..384a9f1a0b1f 100644 --- a/tests/rustdoc-ui/cfg-hide-show-conflict.stderr +++ b/tests/rustdoc-ui/cfg-hide-show-conflict.stderr @@ -1,14 +1,14 @@ error: same `cfg` was in `auto_cfg(hide(...))` and `auto_cfg(show(...))` on the same item - --> $DIR/cfg-hide-show-conflict.rs:3:31 + --> $DIR/cfg-hide-show-conflict.rs:3:8 | LL | #![doc(auto_cfg(show(windows, target_os = "linux")))] - | ^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^ | note: first change was here - --> $DIR/cfg-hide-show-conflict.rs:2:22 + --> $DIR/cfg-hide-show-conflict.rs:2:8 | LL | #![doc(auto_cfg(hide(target_os = "linux")))] - | ^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^ error: aborting due to 1 previous error diff --git a/tests/rustdoc-ui/check-doc-alias-attr-location.stderr b/tests/rustdoc-ui/check-doc-alias-attr-location.stderr index 85c9516236c9..b8e1863ce560 100644 --- a/tests/rustdoc-ui/check-doc-alias-attr-location.stderr +++ b/tests/rustdoc-ui/check-doc-alias-attr-location.stderr @@ -1,26 +1,26 @@ error: `#[doc(alias = "...")]` isn't allowed on foreign module - --> $DIR/check-doc-alias-attr-location.rs:7:7 + --> $DIR/check-doc-alias-attr-location.rs:7:15 | LL | #[doc(alias = "foo")] - | ^^^^^^^^^^^^^ + | ^^^^^ error: `#[doc(alias = "...")]` isn't allowed on implementation block - --> $DIR/check-doc-alias-attr-location.rs:10:7 + --> $DIR/check-doc-alias-attr-location.rs:10:15 | LL | #[doc(alias = "bar")] - | ^^^^^^^^^^^^^ + | ^^^^^ error: `#[doc(alias = "...")]` isn't allowed on implementation block - --> $DIR/check-doc-alias-attr-location.rs:16:7 + --> $DIR/check-doc-alias-attr-location.rs:16:15 | LL | #[doc(alias = "foobar")] - | ^^^^^^^^^^^^^^^^ + | ^^^^^^^^ error: `#[doc(alias = "...")]` isn't allowed on type alias in implementation block - --> $DIR/check-doc-alias-attr-location.rs:18:11 + --> $DIR/check-doc-alias-attr-location.rs:18:19 | LL | #[doc(alias = "assoc")] - | ^^^^^^^^^^^^^^^ + | ^^^^^^^ error: aborting due to 4 previous errors diff --git a/tests/rustdoc-ui/check-doc-alias-attr.stderr b/tests/rustdoc-ui/check-doc-alias-attr.stderr index 250568be3333..06d5c6535191 100644 --- a/tests/rustdoc-ui/check-doc-alias-attr.stderr +++ b/tests/rustdoc-ui/check-doc-alias-attr.stderr @@ -4,11 +4,28 @@ error: doc alias attribute expects a string `#[doc(alias = "a")]` or a list of s LL | #[doc(alias)] | ^^^^^ -error: doc alias attribute expects a string `#[doc(alias = "a")]` or a list of strings `#[doc(alias("a", "b"))]` - --> $DIR/check-doc-alias-attr.rs:8:7 +error[E0539]: malformed `doc` attribute input + --> $DIR/check-doc-alias-attr.rs:8:1 | LL | #[doc(alias = 0)] - | ^^^^^^^^^ + | ^^^^^^^^^^^^^^-^^ + | | + | expected a string literal here + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #[doc(alias = 0)] +LL + #[doc = "string"] + | +LL - #[doc(alias = 0)] +LL + #[doc(hidden)] + | +LL - #[doc(alias = 0)] +LL + #[doc(inline)] + | +LL - #[doc(alias = 0)] +LL + #[doc(test)] + | error: '"' character isn't allowed in `#[doc(alias = "...")]` --> $DIR/check-doc-alias-attr.rs:9:15 @@ -54,25 +71,42 @@ error: `#[doc(alias = "...")]` attribute cannot have empty value LL | #[doc(alias = "")] | ^^ -error: `#[doc(alias("a"))]` expects string literals - --> $DIR/check-doc-alias-attr.rs:19:13 +error[E0539]: malformed `doc` attribute input + --> $DIR/check-doc-alias-attr.rs:19:1 | LL | #[doc(alias(0))] - | ^ + | ^^^^^^^^^^^^-^^^ + | | + | expected a string literal here + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #[doc(alias(0))] +LL + #[doc = "string"] + | +LL - #[doc(alias(0))] +LL + #[doc(hidden)] + | +LL - #[doc(alias(0))] +LL + #[doc(inline)] + | +LL - #[doc(alias(0))] +LL + #[doc(test)] + | -error: '"' character isn't allowed in `#[doc(alias("..."))]` +error: '"' character isn't allowed in `#[doc(alias = "...")]` --> $DIR/check-doc-alias-attr.rs:20:13 | LL | #[doc(alias("\""))] | ^^^^ -error: '\n' character isn't allowed in `#[doc(alias("..."))]` +error: '\n' character isn't allowed in `#[doc(alias = "...")]` --> $DIR/check-doc-alias-attr.rs:21:13 | LL | #[doc(alias("\n"))] | ^^^^ -error: '\n' character isn't allowed in `#[doc(alias("..."))]` +error: '\n' character isn't allowed in `#[doc(alias = "...")]` --> $DIR/check-doc-alias-attr.rs:22:13 | LL | #[doc(alias(" @@ -80,25 +114,25 @@ LL | #[doc(alias(" LL | | "))] | |_^ -error: '\t' character isn't allowed in `#[doc(alias("..."))]` +error: '\t' character isn't allowed in `#[doc(alias = "...")]` --> $DIR/check-doc-alias-attr.rs:24:13 | LL | #[doc(alias("\t"))] | ^^^^ -error: `#[doc(alias("..."))]` cannot start or end with ' ' +error: `#[doc(alias = "...")]` cannot start or end with ' ' --> $DIR/check-doc-alias-attr.rs:25:13 | LL | #[doc(alias(" hello"))] | ^^^^^^^^ -error: `#[doc(alias("..."))]` cannot start or end with ' ' +error: `#[doc(alias = "...")]` cannot start or end with ' ' --> $DIR/check-doc-alias-attr.rs:26:13 | LL | #[doc(alias("hello "))] | ^^^^^^^^ -error: `#[doc(alias("..."))]` attribute cannot have empty value +error: `#[doc(alias = "...")]` attribute cannot have empty value --> $DIR/check-doc-alias-attr.rs:27:13 | LL | #[doc(alias(""))] @@ -106,3 +140,4 @@ LL | #[doc(alias(""))] error: aborting due to 17 previous errors +For more information about this error, try `rustc --explain E0539`. diff --git a/tests/rustdoc-ui/doc-alias-assoc-const.stderr b/tests/rustdoc-ui/doc-alias-assoc-const.stderr index cc628c39400b..7566ec840da7 100644 --- a/tests/rustdoc-ui/doc-alias-assoc-const.stderr +++ b/tests/rustdoc-ui/doc-alias-assoc-const.stderr @@ -1,8 +1,8 @@ error: `#[doc(alias = "...")]` isn't allowed on associated constant in trait implementation block - --> $DIR/doc-alias-assoc-const.rs:8:11 + --> $DIR/doc-alias-assoc-const.rs:8:19 | LL | #[doc(alias = "CONST_BAZ")] - | ^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^ error: aborting due to 1 previous error diff --git a/tests/rustdoc-ui/doc-alias-same-name.stderr b/tests/rustdoc-ui/doc-alias-same-name.stderr index a9da75c0171c..a76ff5ee0b67 100644 --- a/tests/rustdoc-ui/doc-alias-same-name.stderr +++ b/tests/rustdoc-ui/doc-alias-same-name.stderr @@ -1,8 +1,8 @@ -error: `#[doc(alias = "...")]` is the same as the item's name - --> $DIR/doc-alias-same-name.rs:3:7 +error: `#[doc(alias = "Foo"]` is the same as the item's name + --> $DIR/doc-alias-same-name.rs:3:15 | LL | #[doc(alias = "Foo")] - | ^^^^^^^^^^^^^ + | ^^^^^ error: aborting due to 1 previous error diff --git a/tests/rustdoc-ui/doc-include-suggestion.stderr b/tests/rustdoc-ui/doc-include-suggestion.stderr index 1b4b78a8f263..ea5261e5bbd4 100644 --- a/tests/rustdoc-ui/doc-include-suggestion.stderr +++ b/tests/rustdoc-ui/doc-include-suggestion.stderr @@ -2,7 +2,7 @@ error: unknown `doc` attribute `include` --> $DIR/doc-include-suggestion.rs:1:7 | LL | #[doc(include = "external-cross-doc.md")] - | ------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-- help: use `doc = include_str!` instead: `#[doc = include_str!("external-cross-doc.md")]` + | ^^^^^^^ help: use `doc = include_str!` instead: `#[doc = include_str!("external-cross-doc.md")]` | = note: `#[deny(invalid_doc_attributes)]` on by default diff --git a/tests/rustdoc-ui/lints/doc_cfg_hide.stderr b/tests/rustdoc-ui/lints/doc_cfg_hide.stderr index c63c8d607fa0..acbe6ef69dd5 100644 --- a/tests/rustdoc-ui/lints/doc_cfg_hide.stderr +++ b/tests/rustdoc-ui/lints/doc_cfg_hide.stderr @@ -1,16 +1,16 @@ error: `#![doc(auto_cfg(hide(...)))]` expects a list of items - --> $DIR/doc_cfg_hide.rs:2:8 + --> $DIR/doc_cfg_hide.rs:2:17 | LL | #![doc(auto_cfg(hide = "test"))] - | ^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^ | = note: `#[deny(invalid_doc_attributes)]` on by default error: `#![doc(auto_cfg(hide(...)))]` expects a list of items - --> $DIR/doc_cfg_hide.rs:3:8 + --> $DIR/doc_cfg_hide.rs:3:17 | LL | #![doc(auto_cfg(hide))] - | ^^^^^^^^^^^^^^ + | ^^^^ error: `#![doc(auto_cfg(hide(...)))]` only accepts identifiers or key/value items --> $DIR/doc_cfg_hide.rs:4:22 diff --git a/tests/rustdoc-ui/lints/invalid-doc-attr.rs b/tests/rustdoc-ui/lints/invalid-doc-attr.rs index e1cc08ca2427..a8c42b8fd79c 100644 --- a/tests/rustdoc-ui/lints/invalid-doc-attr.rs +++ b/tests/rustdoc-ui/lints/invalid-doc-attr.rs @@ -6,8 +6,6 @@ #[doc(test(no_crate_inject))] //~^ ERROR can only be applied at the crate level -//~| HELP to apply to the crate, use an inner attribute -//~| SUGGESTION ! #[doc(inline)] //~^ ERROR can only be applied to a `use` item pub fn foo() {} diff --git a/tests/rustdoc-ui/lints/invalid-doc-attr.stderr b/tests/rustdoc-ui/lints/invalid-doc-attr.stderr index 7621999a8ca5..82e1b62b57a6 100644 --- a/tests/rustdoc-ui/lints/invalid-doc-attr.stderr +++ b/tests/rustdoc-ui/lints/invalid-doc-attr.stderr @@ -1,18 +1,14 @@ error: this attribute can only be applied at the crate level - --> $DIR/invalid-doc-attr.rs:7:7 + --> $DIR/invalid-doc-attr.rs:7:12 | LL | #[doc(test(no_crate_inject))] - | ^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ | = note: read for more information = note: `#[deny(invalid_doc_attributes)]` on by default -help: to apply to the crate, use an inner attribute - | -LL | #![doc(test(no_crate_inject))] - | + error: this attribute can only be applied to a `use` item - --> $DIR/invalid-doc-attr.rs:11:7 + --> $DIR/invalid-doc-attr.rs:9:7 | LL | #[doc(inline)] | ^^^^^^ only applicable on `use` items @@ -23,15 +19,15 @@ LL | pub fn foo() {} = note: read for more information error: this attribute can only be applied at the crate level - --> $DIR/invalid-doc-attr.rs:16:12 + --> $DIR/invalid-doc-attr.rs:14:17 | LL | #![doc(test(no_crate_inject))] - | ^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ | = note: read for more information error: conflicting doc inlining attributes - --> $DIR/invalid-doc-attr.rs:26:7 + --> $DIR/invalid-doc-attr.rs:24:7 | LL | #[doc(inline)] | ^^^^^^ this attribute... @@ -41,7 +37,7 @@ LL | #[doc(no_inline)] = help: remove one of the conflicting attributes error: this attribute can only be applied to an `extern crate` item - --> $DIR/invalid-doc-attr.rs:32:7 + --> $DIR/invalid-doc-attr.rs:30:7 | LL | #[doc(masked)] | ^^^^^^ only applicable on `extern crate` items @@ -52,7 +48,7 @@ LL | pub struct Masked; = note: read for more information error: this attribute cannot be applied to an `extern crate self` item - --> $DIR/invalid-doc-attr.rs:36:7 + --> $DIR/invalid-doc-attr.rs:34:7 | LL | #[doc(masked)] | ^^^^^^ not applicable on `extern crate self` items @@ -63,21 +59,27 @@ LL | pub extern crate self as reexport; error: this attribute can only be applied to an `extern crate` item --> $DIR/invalid-doc-attr.rs:4:8 | -LL | #![doc(masked)] - | ^^^^^^ only applicable on `extern crate` items +LL | / #![crate_type = "lib"] +LL | | #![feature(doc_masked)] +LL | | +LL | | #![doc(masked)] + | | ^^^^^^ only applicable on `extern crate` items +... | +LL | | pub extern crate self as reexport; + | |__________________________________- not an `extern crate` item | = note: read for more information error: this attribute can only be applied at the crate level - --> $DIR/invalid-doc-attr.rs:19:11 + --> $DIR/invalid-doc-attr.rs:17:16 | LL | #[doc(test(no_crate_inject))] - | ^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ | = note: read for more information error: this attribute can only be applied to a `use` item - --> $DIR/invalid-doc-attr.rs:21:11 + --> $DIR/invalid-doc-attr.rs:19:11 | LL | #[doc(inline)] | ^^^^^^ only applicable on `use` items From d1277ccffaff214fb6127930c70f29744e40a877 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 4 Dec 2025 12:58:31 +0100 Subject: [PATCH 19/64] Update `check_doc_cfg` pass in rustdoc, remove old `rustc_attr_parsing::cfg_matches` API --- .../src/attributes/cfg_old.rs | 40 ------- src/librustdoc/passes/check_doc_cfg.rs | 100 +++++++++--------- 2 files changed, 49 insertions(+), 91 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg_old.rs b/compiler/rustc_attr_parsing/src/attributes/cfg_old.rs index adae3fa635f4..29be000d476d 100644 --- a/compiler/rustc_attr_parsing/src/attributes/cfg_old.rs +++ b/compiler/rustc_attr_parsing/src/attributes/cfg_old.rs @@ -4,8 +4,6 @@ use rustc_feature::{Features, GatedCfg, find_gated_cfg}; use rustc_hir::RustcVersion; use rustc_hir::lints::AttributeLintKind; use rustc_session::Session; -use rustc_session::config::ExpectedValues; -use rustc_session::lint::builtin::UNEXPECTED_CFGS; use rustc_session::lint::{BuiltinLintDiag, Lint}; use rustc_session::parse::feature_err; use rustc_span::{Span, Symbol, sym}; @@ -37,44 +35,6 @@ pub struct Condition { pub span: Span, } -/// Tests if a cfg-pattern matches the cfg set -pub fn cfg_matches( - cfg: &MetaItemInner, - sess: &Session, - lint_emitter: impl CfgMatchesLintEmitter, - features: Option<&Features>, -) -> bool { - eval_condition(cfg, sess, features, &mut |cfg| { - try_gate_cfg(cfg.name, cfg.span, sess, features); - match sess.psess.check_config.expecteds.get(&cfg.name) { - Some(ExpectedValues::Some(values)) if !values.contains(&cfg.value) => { - lint_emitter.emit_span_lint( - sess, - UNEXPECTED_CFGS, - cfg.span, - BuiltinLintDiag::AttributeLint(AttributeLintKind::UnexpectedCfgValue( - (cfg.name, cfg.name_span), - cfg.value.map(|v| (v, cfg.value_span.unwrap())), - )), - ); - } - None if sess.psess.check_config.exhaustive_names => { - lint_emitter.emit_span_lint( - sess, - UNEXPECTED_CFGS, - cfg.span, - BuiltinLintDiag::AttributeLint(AttributeLintKind::UnexpectedCfgName( - (cfg.name, cfg.name_span), - cfg.value.map(|v| (v, cfg.value_span.unwrap())), - )), - ); - } - _ => { /* not unexpected */ } - } - sess.psess.config.contains(&(cfg.name, cfg.value)) - }) -} - pub fn try_gate_cfg(name: Symbol, span: Span, sess: &Session, features: Option<&Features>) { let gate = find_gated_cfg(|sym| sym == name); if let (Some(feats), Some(gated_cfg)) = (features, gate) { diff --git a/src/librustdoc/passes/check_doc_cfg.rs b/src/librustdoc/passes/check_doc_cfg.rs index 63dc375a13c6..9e7fae5e14e4 100644 --- a/src/librustdoc/passes/check_doc_cfg.rs +++ b/src/librustdoc/passes/check_doc_cfg.rs @@ -1,9 +1,8 @@ -#![allow(dead_code, unused_imports)] - -use rustc_hir::HirId; +use rustc_attr_parsing::{ShouldEmit, eval_config_entry}; +use rustc_hir::attrs::AttributeKind; use rustc_hir::def_id::LocalDefId; +use rustc_hir::{Attribute, HirId}; use rustc_middle::ty::TyCtxt; -use rustc_span::sym; use super::Pass; use crate::clean::{Attributes, Crate, Item}; @@ -16,59 +15,58 @@ pub(crate) const CHECK_DOC_CFG: Pass = Pass { description: "checks `#[doc(cfg(...))]` for stability feature and unexpected cfgs", }; -pub(crate) fn check_doc_cfg(krate: Crate, _cx: &mut DocContext<'_>) -> Crate { - // let mut checker = DocCfgChecker { cx }; - // checker.visit_crate(&krate); +pub(crate) fn check_doc_cfg(krate: Crate, cx: &mut DocContext<'_>) -> Crate { + let mut checker = DocCfgChecker { cx }; + checker.visit_crate(&krate); krate } -// struct RustdocCfgMatchesLintEmitter<'a>(TyCtxt<'a>, HirId); +struct RustdocCfgMatchesLintEmitter<'a>(TyCtxt<'a>, HirId); -// impl<'a> rustc_attr_parsing::CfgMatchesLintEmitter for RustdocCfgMatchesLintEmitter<'a> { -// fn emit_span_lint( -// &self, -// sess: &rustc_session::Session, -// lint: &'static rustc_lint::Lint, -// sp: rustc_span::Span, -// builtin_diag: rustc_lint_defs::BuiltinLintDiag, -// ) { -// self.0.node_span_lint(lint, self.1, sp, |diag| { -// rustc_lint::decorate_builtin_lint(sess, Some(self.0), builtin_diag, diag) -// }); -// } -// } +impl<'a> rustc_attr_parsing::CfgMatchesLintEmitter for RustdocCfgMatchesLintEmitter<'a> { + fn emit_span_lint( + &self, + sess: &rustc_session::Session, + lint: &'static rustc_lint::Lint, + sp: rustc_span::Span, + builtin_diag: rustc_lint_defs::BuiltinLintDiag, + ) { + self.0.node_span_lint(lint, self.1, sp, |diag| { + rustc_lint::decorate_builtin_lint(sess, Some(self.0), builtin_diag, diag) + }); + } +} -// struct DocCfgChecker<'a, 'tcx> { -// cx: &'a mut DocContext<'tcx>, -// } +struct DocCfgChecker<'a, 'tcx> { + cx: &'a mut DocContext<'tcx>, +} -// impl DocCfgChecker<'_, '_> { -// fn check_attrs(&mut self, attrs: &Attributes, did: LocalDefId) { -// for attr in &attrs.other_attrs { -// let Attribute::Parsed(AttributeKind::Doc(d)) = attr else { continue }; -// let Some(doc_cfg) = d.cfg else { continue }; +impl DocCfgChecker<'_, '_> { + fn check_attrs(&mut self, attrs: &Attributes, did: LocalDefId) { + for attr in &attrs.other_attrs { + let Attribute::Parsed(AttributeKind::Doc(d)) = attr else { continue }; -// if let Some([cfg_mi]) = doc_cfg.meta_item_list() { -// let _ = rustc_attr_parsing::cfg_matches( -// cfg_mi, -// &self.cx.tcx.sess, -// RustdocCfgMatchesLintEmitter( -// self.cx.tcx, -// self.cx.tcx.local_def_id_to_hir_id(did), -// ), -// Some(self.cx.tcx.features()), -// ); -// } -// } -// } -// } + for doc_cfg in &d.cfg { + let _ = eval_config_entry( + &self.cx.tcx.sess, + doc_cfg, + &RustdocCfgMatchesLintEmitter( + self.cx.tcx, + self.cx.tcx.local_def_id_to_hir_id(did), + ), + ShouldEmit::ErrorsAndLints, + ); + } + } + } +} -// impl DocVisitor<'_> for DocCfgChecker<'_, '_> { -// fn visit_item(&mut self, item: &'_ Item) { -// if let Some(Some(local_did)) = item.def_id().map(|did| did.as_local()) { -// self.check_attrs(&item.attrs, local_did); -// } +impl DocVisitor<'_> for DocCfgChecker<'_, '_> { + fn visit_item(&mut self, item: &'_ Item) { + if let Some(Some(local_did)) = item.def_id().map(|did| did.as_local()) { + self.check_attrs(&item.attrs, local_did); + } -// self.visit_item_recur(item); -// } -// } + self.visit_item_recur(item); + } +} From e4f57dd4b3f3f4dc0bd6c4b2484526375ef3c5cf Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 4 Dec 2025 15:48:56 +0100 Subject: [PATCH 20/64] Finish fixing ui tests --- .../rustc_attr_parsing/src/attributes/doc.rs | 7 +- compiler/rustc_attr_parsing/src/lib.rs | 1 + tests/rustdoc-ui/deprecated-attrs.stderr | 4 +- tests/rustdoc-ui/doc-alias-crate-level.rs | 3 - tests/rustdoc-ui/doc-alias-crate-level.stderr | 12 +- tests/rustdoc-ui/doc-alias.rs | 2 + tests/rustdoc-ui/doc-alias.stderr | 8 + tests/rustdoc-ui/doc-cfg-2.rs | 16 ++ tests/rustdoc-ui/doc-cfg-2.stderr | 60 ++++++ tests/rustdoc-ui/doc-cfg.rs | 17 +- tests/rustdoc-ui/doc-cfg.stderr | 183 ++++++++++-------- tests/rustdoc-ui/doctest/doc-test-attr.stderr | 4 +- tests/rustdoc-ui/invalid-cfg.rs | 16 +- tests/rustdoc-ui/invalid-cfg.stderr | 178 ++++++++++++++--- tests/rustdoc-ui/lints/doc-attr-2.rs | 11 ++ tests/rustdoc-ui/lints/doc-attr-2.stderr | 28 +++ tests/rustdoc-ui/lints/doc-attr.rs | 15 +- tests/rustdoc-ui/lints/doc-attr.stderr | 92 +++++---- 18 files changed, 471 insertions(+), 186 deletions(-) create mode 100644 tests/rustdoc-ui/doc-alias.rs create mode 100644 tests/rustdoc-ui/doc-alias.stderr create mode 100644 tests/rustdoc-ui/doc-cfg-2.rs create mode 100644 tests/rustdoc-ui/doc-cfg-2.stderr create mode 100644 tests/rustdoc-ui/lints/doc-attr-2.rs create mode 100644 tests/rustdoc-ui/lints/doc-attr-2.stderr diff --git a/compiler/rustc_attr_parsing/src/attributes/doc.rs b/compiler/rustc_attr_parsing/src/attributes/doc.rs index 1fd7b702e92f..2e8249fb35be 100644 --- a/compiler/rustc_attr_parsing/src/attributes/doc.rs +++ b/compiler/rustc_attr_parsing/src/attributes/doc.rs @@ -442,7 +442,12 @@ impl DocParser { cx.emit_lint(AttributeLintKind::DocUnknownAny { name }, path.span()); } None => { - // FIXME: is there anything to do in this case? + let full_name = + path.segments().map(|s| s.as_str()).intersperse("::").collect::(); + cx.emit_lint( + AttributeLintKind::DocUnknownAny { name: Symbol::intern(&full_name) }, + path.span(), + ); } } } diff --git a/compiler/rustc_attr_parsing/src/lib.rs b/compiler/rustc_attr_parsing/src/lib.rs index 37a3189f892e..3e9d8087a192 100644 --- a/compiler/rustc_attr_parsing/src/lib.rs +++ b/compiler/rustc_attr_parsing/src/lib.rs @@ -81,6 +81,7 @@ #![recursion_limit = "256"] // tidy-alphabetical-end #![feature(if_let_guard)] +#![feature(iter_intersperse)] #[macro_use] /// All the individual attribute parsers for each of rustc's built-in attributes. diff --git a/tests/rustdoc-ui/deprecated-attrs.stderr b/tests/rustdoc-ui/deprecated-attrs.stderr index 323257f944ce..6135b1496925 100644 --- a/tests/rustdoc-ui/deprecated-attrs.stderr +++ b/tests/rustdoc-ui/deprecated-attrs.stderr @@ -17,7 +17,7 @@ error: unknown `doc` attribute `passes` --> $DIR/deprecated-attrs.rs:9:8 | LL | #![doc(passes = "collapse-docs unindent-comments")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no longer functions + | ^^^^^^ no longer functions | = note: `doc` attribute `passes` no longer functions; see issue #44136 = note: `doc(passes)` is now a no-op @@ -26,7 +26,7 @@ error: unknown `doc` attribute `plugins` --> $DIR/deprecated-attrs.rs:14:8 | LL | #![doc(plugins = "xxx")] - | ^^^^^^^^^^^^^^^ no longer functions + | ^^^^^^^ no longer functions | = note: `doc` attribute `plugins` no longer functions; see issue #44136 and CVE-2018-1000622 = note: `doc(plugins)` is now a no-op diff --git a/tests/rustdoc-ui/doc-alias-crate-level.rs b/tests/rustdoc-ui/doc-alias-crate-level.rs index 70618ac01dfb..9ba7a63d7f10 100644 --- a/tests/rustdoc-ui/doc-alias-crate-level.rs +++ b/tests/rustdoc-ui/doc-alias-crate-level.rs @@ -1,4 +1 @@ #![doc(alias = "crate-level-not-working")] //~ ERROR - -#[doc(alias = "shouldn't work!")] //~ ERROR -pub fn foo() {} diff --git a/tests/rustdoc-ui/doc-alias-crate-level.stderr b/tests/rustdoc-ui/doc-alias-crate-level.stderr index fc8095e03ca9..1742118a67c1 100644 --- a/tests/rustdoc-ui/doc-alias-crate-level.stderr +++ b/tests/rustdoc-ui/doc-alias-crate-level.stderr @@ -1,14 +1,8 @@ -error: '\'' character isn't allowed in `#[doc(alias = "...")]` - --> $DIR/doc-alias-crate-level.rs:3:15 - | -LL | #[doc(alias = "shouldn't work!")] - | ^^^^^^^^^^^^^^^^^ - error: `#![doc(alias = "...")]` isn't allowed as a crate-level attribute - --> $DIR/doc-alias-crate-level.rs:1:8 + --> $DIR/doc-alias-crate-level.rs:1:16 | LL | #![doc(alias = "crate-level-not-working")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 2 previous errors +error: aborting due to 1 previous error diff --git a/tests/rustdoc-ui/doc-alias.rs b/tests/rustdoc-ui/doc-alias.rs new file mode 100644 index 000000000000..ae2a5b387191 --- /dev/null +++ b/tests/rustdoc-ui/doc-alias.rs @@ -0,0 +1,2 @@ +#[doc(alias = "shouldn't work!")] //~ ERROR +pub fn foo() {} diff --git a/tests/rustdoc-ui/doc-alias.stderr b/tests/rustdoc-ui/doc-alias.stderr new file mode 100644 index 000000000000..1b3cc9426947 --- /dev/null +++ b/tests/rustdoc-ui/doc-alias.stderr @@ -0,0 +1,8 @@ +error: '\'' character isn't allowed in `#[doc(alias = "...")]` + --> $DIR/doc-alias.rs:1:15 + | +LL | #[doc(alias = "shouldn't work!")] + | ^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/rustdoc-ui/doc-cfg-2.rs b/tests/rustdoc-ui/doc-cfg-2.rs new file mode 100644 index 000000000000..bd6a2dc18be9 --- /dev/null +++ b/tests/rustdoc-ui/doc-cfg-2.rs @@ -0,0 +1,16 @@ +#![feature(doc_cfg)] + +#[doc(cfg(foo), cfg(bar))] +//~^ WARN unexpected `cfg` condition name: `foo` +//~| WARN unexpected `cfg` condition name: `bar` +#[doc(auto_cfg(42))] //~ ERROR +#[doc(auto_cfg(hide(true)))] //~ ERROR +#[doc(auto_cfg(hide(42)))] //~ ERROR +#[doc(auto_cfg(hide("a")))] //~ ERROR +#[doc(auto_cfg = 42)] //~ ERROR +#[doc(auto_cfg = "a")] //~ ERROR +// Shouldn't lint +#[doc(auto_cfg(hide(windows)))] +#[doc(auto_cfg(hide(feature = "windows")))] +#[doc(auto_cfg(hide(foo)))] +pub fn foo() {} diff --git a/tests/rustdoc-ui/doc-cfg-2.stderr b/tests/rustdoc-ui/doc-cfg-2.stderr new file mode 100644 index 000000000000..f3d67abfb8dd --- /dev/null +++ b/tests/rustdoc-ui/doc-cfg-2.stderr @@ -0,0 +1,60 @@ +warning: unexpected `cfg` condition name: `foo` + --> $DIR/doc-cfg-2.rs:3:11 + | +LL | #[doc(cfg(foo), cfg(bar))] + | ^^^ + | + = help: expected names are: `FALSE` and `test` and 31 more + = help: to expect this configuration use `--check-cfg=cfg(foo)` + = note: see for more information about checking conditional configuration + = note: `#[warn(unexpected_cfgs)]` on by default + +warning: unexpected `cfg` condition name: `bar` + --> $DIR/doc-cfg-2.rs:3:21 + | +LL | #[doc(cfg(foo), cfg(bar))] + | ^^^ + | + = help: to expect this configuration use `--check-cfg=cfg(bar)` + = note: see for more information about checking conditional configuration + +error: only `hide` or `show` are allowed in `#[doc(auto_cfg(...))]` + --> $DIR/doc-cfg-2.rs:6:16 + | +LL | #[doc(auto_cfg(42))] + | ^^ + | + = note: `#[deny(invalid_doc_attributes)]` on by default + +error: `#![doc(auto_cfg(hide(...)))]` only accepts identifiers or key/value items + --> $DIR/doc-cfg-2.rs:7:21 + | +LL | #[doc(auto_cfg(hide(true)))] + | ^^^^ + +error: `#![doc(auto_cfg(hide(...)))]` only accepts identifiers or key/value items + --> $DIR/doc-cfg-2.rs:8:21 + | +LL | #[doc(auto_cfg(hide(42)))] + | ^^ + +error: `#![doc(auto_cfg(hide(...)))]` only accepts identifiers or key/value items + --> $DIR/doc-cfg-2.rs:9:21 + | +LL | #[doc(auto_cfg(hide("a")))] + | ^^^ + +error: expected boolean for `#[doc(auto_cfg = ...)]` + --> $DIR/doc-cfg-2.rs:10:18 + | +LL | #[doc(auto_cfg = 42)] + | ^^ + +error: expected boolean for `#[doc(auto_cfg = ...)]` + --> $DIR/doc-cfg-2.rs:11:18 + | +LL | #[doc(auto_cfg = "a")] + | ^^^ + +error: aborting due to 6 previous errors; 2 warnings emitted + diff --git a/tests/rustdoc-ui/doc-cfg.rs b/tests/rustdoc-ui/doc-cfg.rs index d72643e23556..f30d80aa9cda 100644 --- a/tests/rustdoc-ui/doc-cfg.rs +++ b/tests/rustdoc-ui/doc-cfg.rs @@ -1,22 +1,9 @@ #![feature(doc_cfg)] #[doc(cfg(), cfg(foo, bar))] -//~^ ERROR -//~^^ ERROR -#[doc(cfg(foo), cfg(bar))] -//~^ WARN unexpected `cfg` condition name: `foo` -//~^^ WARN unexpected `cfg` condition name: `bar` +//~^ ERROR malformed `doc` attribute input +//~| ERROR malformed `doc` attribute input #[doc(cfg())] //~ ERROR #[doc(cfg(foo, bar))] //~ ERROR -#[doc(auto_cfg(42))] //~ ERROR -#[doc(auto_cfg(hide(true)))] //~ ERROR -#[doc(auto_cfg(hide(42)))] //~ ERROR -#[doc(auto_cfg(hide("a")))] //~ ERROR #[doc(auto_cfg(hide(foo::bar)))] //~ ERROR -#[doc(auto_cfg = 42)] //~ ERROR -#[doc(auto_cfg = "a")] //~ ERROR -// Shouldn't lint -#[doc(auto_cfg(hide(windows)))] -#[doc(auto_cfg(hide(feature = "windows")))] -#[doc(auto_cfg(hide(foo)))] pub fn foo() {} diff --git a/tests/rustdoc-ui/doc-cfg.stderr b/tests/rustdoc-ui/doc-cfg.stderr index 49e8c324facf..a4c6584d3294 100644 --- a/tests/rustdoc-ui/doc-cfg.stderr +++ b/tests/rustdoc-ui/doc-cfg.stderr @@ -1,90 +1,119 @@ -error: only `hide` or `show` are allowed in `#[doc(auto_cfg(...))]` - --> $DIR/doc-cfg.rs:11:7 - | -LL | #[doc(auto_cfg(42))] - | ^^^^^^^^^^^^ - | - = note: `#[deny(invalid_doc_attributes)]` on by default - -error: `#![doc(auto_cfg(hide(...)))]` only accepts identifiers or key/value items - --> $DIR/doc-cfg.rs:12:21 - | -LL | #[doc(auto_cfg(hide(true)))] - | ^^^^ - -error: `#![doc(auto_cfg(hide(...)))]` only accepts identifiers or key/value items - --> $DIR/doc-cfg.rs:13:21 - | -LL | #[doc(auto_cfg(hide(42)))] - | ^^ - -error: `#![doc(auto_cfg(hide(...)))]` only accepts identifiers or key/value items - --> $DIR/doc-cfg.rs:14:21 - | -LL | #[doc(auto_cfg(hide("a")))] - | ^^^ - -error: `#![doc(auto_cfg(hide(...)))]` only accepts identifiers or key/value items - --> $DIR/doc-cfg.rs:15:21 - | -LL | #[doc(auto_cfg(hide(foo::bar)))] - | ^^^^^^^^ - -error: expected boolean for `#[doc(auto_cfg = ...)]` - --> $DIR/doc-cfg.rs:16:7 - | -LL | #[doc(auto_cfg = 42)] - | ^^^^^^^^^^^^^ - -error: expected boolean for `#[doc(auto_cfg = ...)]` - --> $DIR/doc-cfg.rs:17:7 - | -LL | #[doc(auto_cfg = "a")] - | ^^^^^^^^^^^^^^ - -warning: unexpected `cfg` condition name: `foo` - --> $DIR/doc-cfg.rs:6:11 - | -LL | #[doc(cfg(foo), cfg(bar))] - | ^^^ - | - = help: expected names are: `FALSE` and `test` and 31 more - = help: to expect this configuration use `--check-cfg=cfg(foo)` - = note: see for more information about checking conditional configuration - = note: `#[warn(unexpected_cfgs)]` on by default - -warning: unexpected `cfg` condition name: `bar` - --> $DIR/doc-cfg.rs:6:21 - | -LL | #[doc(cfg(foo), cfg(bar))] - | ^^^ - | - = help: to expect this configuration use `--check-cfg=cfg(bar)` - = note: see for more information about checking conditional configuration - -error: `cfg` predicate is not specified - --> $DIR/doc-cfg.rs:3:7 +error[E0805]: malformed `doc` attribute input + --> $DIR/doc-cfg.rs:3:1 | LL | #[doc(cfg(), cfg(foo, bar))] - | ^^^^^ help: expected syntax is: `cfg(/* predicate */)` + | ^^^^^^^^^--^^^^^^^^^^^^^^^^^ + | | + | expected a single argument here + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #[doc(cfg(), cfg(foo, bar))] +LL + #[doc = "string"] + | +LL - #[doc(cfg(), cfg(foo, bar))] +LL + #[doc(hidden)] + | +LL - #[doc(cfg(), cfg(foo, bar))] +LL + #[doc(inline)] + | +LL - #[doc(cfg(), cfg(foo, bar))] +LL + #[doc(test)] + | -error: multiple `cfg` predicates are specified - --> $DIR/doc-cfg.rs:3:23 +error[E0805]: malformed `doc` attribute input + --> $DIR/doc-cfg.rs:3:1 | LL | #[doc(cfg(), cfg(foo, bar))] - | ^^^ + | ^^^^^^^^^^^^^^^^----------^^ + | | + | expected a single argument here + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #[doc(cfg(), cfg(foo, bar))] +LL + #[doc = "string"] + | +LL - #[doc(cfg(), cfg(foo, bar))] +LL + #[doc(hidden)] + | +LL - #[doc(cfg(), cfg(foo, bar))] +LL + #[doc(inline)] + | +LL - #[doc(cfg(), cfg(foo, bar))] +LL + #[doc(test)] + | -error: `cfg` predicate is not specified - --> $DIR/doc-cfg.rs:9:7 +error[E0805]: malformed `doc` attribute input + --> $DIR/doc-cfg.rs:6:1 | LL | #[doc(cfg())] - | ^^^^^ help: expected syntax is: `cfg(/* predicate */)` + | ^^^^^^^^^--^^ + | | + | expected a single argument here + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #[doc(cfg())] +LL + #[doc = "string"] + | +LL - #[doc(cfg())] +LL + #[doc(hidden)] + | +LL - #[doc(cfg())] +LL + #[doc(inline)] + | +LL - #[doc(cfg())] +LL + #[doc(test)] + | -error: multiple `cfg` predicates are specified - --> $DIR/doc-cfg.rs:10:16 +error[E0805]: malformed `doc` attribute input + --> $DIR/doc-cfg.rs:7:1 | LL | #[doc(cfg(foo, bar))] - | ^^^ + | ^^^^^^^^^----------^^ + | | + | expected a single argument here + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #[doc(cfg(foo, bar))] +LL + #[doc = "string"] + | +LL - #[doc(cfg(foo, bar))] +LL + #[doc(hidden)] + | +LL - #[doc(cfg(foo, bar))] +LL + #[doc(inline)] + | +LL - #[doc(cfg(foo, bar))] +LL + #[doc(test)] + | -error: aborting due to 11 previous errors; 2 warnings emitted +error[E0539]: malformed `doc` attribute input + --> $DIR/doc-cfg.rs:8:1 + | +LL | #[doc(auto_cfg(hide(foo::bar)))] + | ^^^^^^^^^^^^^^^^^^^^--------^^^^ + | | + | expected a valid identifier here + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #[doc(auto_cfg(hide(foo::bar)))] +LL + #[doc = "string"] + | +LL - #[doc(auto_cfg(hide(foo::bar)))] +LL + #[doc(hidden)] + | +LL - #[doc(auto_cfg(hide(foo::bar)))] +LL + #[doc(inline)] + | +LL - #[doc(auto_cfg(hide(foo::bar)))] +LL + #[doc(test)] + | +error: aborting due to 5 previous errors + +Some errors have detailed explanations: E0539, E0805. +For more information about an error, try `rustc --explain E0539`. diff --git a/tests/rustdoc-ui/doctest/doc-test-attr.stderr b/tests/rustdoc-ui/doctest/doc-test-attr.stderr index 415251cc5e9d..cf7bce66ef40 100644 --- a/tests/rustdoc-ui/doctest/doc-test-attr.stderr +++ b/tests/rustdoc-ui/doctest/doc-test-attr.stderr @@ -7,10 +7,10 @@ LL | #![doc(test)] = note: `#[deny(invalid_doc_attributes)]` on by default error: `#[doc(test(...)]` takes a list of attributes - --> $DIR/doc-test-attr.rs:5:8 + --> $DIR/doc-test-attr.rs:5:13 | LL | #![doc(test = "hello")] - | ^^^^^^^^^^^^^^ + | ^^^^^^^^^ error: unknown `doc(test)` attribute `a` --> $DIR/doc-test-attr.rs:7:13 diff --git a/tests/rustdoc-ui/invalid-cfg.rs b/tests/rustdoc-ui/invalid-cfg.rs index 7e54aeea1def..4d00edc0c7c2 100644 --- a/tests/rustdoc-ui/invalid-cfg.rs +++ b/tests/rustdoc-ui/invalid-cfg.rs @@ -1,21 +1,21 @@ #![feature(doc_cfg)] -#[doc(cfg = "x")] //~ ERROR not followed by parentheses -#[doc(cfg(x, y))] //~ ERROR multiple `cfg` predicates +#[doc(cfg = "x")] //~ ERROR malformed `doc` attribute input +#[doc(cfg(x, y))] //~ ERROR malformed `doc` attribute input pub struct S {} // We check it also fails on private items. -#[doc(cfg = "x")] //~ ERROR not followed by parentheses -#[doc(cfg(x, y))] //~ ERROR multiple `cfg` predicates +#[doc(cfg = "x")] //~ ERROR malformed `doc` attribute input +#[doc(cfg(x, y))] //~ ERROR malformed `doc` attribute input struct X {} // We check it also fails on hidden items. -#[doc(cfg = "x")] //~ ERROR not followed by parentheses -#[doc(cfg(x, y))] //~ ERROR multiple `cfg` predicates +#[doc(cfg = "x")] //~ ERROR malformed `doc` attribute input +#[doc(cfg(x, y))] //~ ERROR malformed `doc` attribute input #[doc(hidden)] pub struct Y {} // We check it also fails on hidden AND private items. -#[doc(cfg = "x")] //~ ERROR not followed by parentheses -#[doc(cfg(x, y))] //~ ERROR multiple `cfg` predicates +#[doc(cfg = "x")] //~ ERROR malformed `doc` attribute input +#[doc(cfg(x, y))] //~ ERROR malformed `doc` attribute input #[doc(hidden)] struct Z {} diff --git a/tests/rustdoc-ui/invalid-cfg.stderr b/tests/rustdoc-ui/invalid-cfg.stderr index 455626e07bd5..a23784509c8b 100644 --- a/tests/rustdoc-ui/invalid-cfg.stderr +++ b/tests/rustdoc-ui/invalid-cfg.stderr @@ -1,50 +1,180 @@ -error: `cfg` is not followed by parentheses - --> $DIR/invalid-cfg.rs:2:7 +error[E0539]: malformed `doc` attribute input + --> $DIR/invalid-cfg.rs:2:1 | LL | #[doc(cfg = "x")] - | ^^^^^^^^^ help: expected syntax is: `cfg(/* predicate */)` + | ^^^^^^^^^^^^^^^^^ expected this to be a list + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #[doc(cfg = "x")] +LL + #[doc = "string"] + | +LL - #[doc(cfg = "x")] +LL + #[doc(hidden)] + | +LL - #[doc(cfg = "x")] +LL + #[doc(inline)] + | +LL - #[doc(cfg = "x")] +LL + #[doc(test)] + | -error: multiple `cfg` predicates are specified - --> $DIR/invalid-cfg.rs:3:14 +error[E0805]: malformed `doc` attribute input + --> $DIR/invalid-cfg.rs:3:1 | LL | #[doc(cfg(x, y))] - | ^ + | ^^^^^^^^^------^^ + | | + | expected a single argument here + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #[doc(cfg(x, y))] +LL + #[doc = "string"] + | +LL - #[doc(cfg(x, y))] +LL + #[doc(hidden)] + | +LL - #[doc(cfg(x, y))] +LL + #[doc(inline)] + | +LL - #[doc(cfg(x, y))] +LL + #[doc(test)] + | -error: `cfg` is not followed by parentheses - --> $DIR/invalid-cfg.rs:7:7 +error[E0539]: malformed `doc` attribute input + --> $DIR/invalid-cfg.rs:7:1 | LL | #[doc(cfg = "x")] - | ^^^^^^^^^ help: expected syntax is: `cfg(/* predicate */)` + | ^^^^^^^^^^^^^^^^^ expected this to be a list + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #[doc(cfg = "x")] +LL + #[doc = "string"] + | +LL - #[doc(cfg = "x")] +LL + #[doc(hidden)] + | +LL - #[doc(cfg = "x")] +LL + #[doc(inline)] + | +LL - #[doc(cfg = "x")] +LL + #[doc(test)] + | -error: multiple `cfg` predicates are specified - --> $DIR/invalid-cfg.rs:8:14 +error[E0805]: malformed `doc` attribute input + --> $DIR/invalid-cfg.rs:8:1 | LL | #[doc(cfg(x, y))] - | ^ + | ^^^^^^^^^------^^ + | | + | expected a single argument here + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #[doc(cfg(x, y))] +LL + #[doc = "string"] + | +LL - #[doc(cfg(x, y))] +LL + #[doc(hidden)] + | +LL - #[doc(cfg(x, y))] +LL + #[doc(inline)] + | +LL - #[doc(cfg(x, y))] +LL + #[doc(test)] + | -error: `cfg` is not followed by parentheses - --> $DIR/invalid-cfg.rs:12:7 +error[E0539]: malformed `doc` attribute input + --> $DIR/invalid-cfg.rs:12:1 | LL | #[doc(cfg = "x")] - | ^^^^^^^^^ help: expected syntax is: `cfg(/* predicate */)` + | ^^^^^^^^^^^^^^^^^ expected this to be a list + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #[doc(cfg = "x")] +LL + #[doc = "string"] + | +LL - #[doc(cfg = "x")] +LL + #[doc(hidden)] + | +LL - #[doc(cfg = "x")] +LL + #[doc(inline)] + | +LL - #[doc(cfg = "x")] +LL + #[doc(test)] + | -error: multiple `cfg` predicates are specified - --> $DIR/invalid-cfg.rs:13:14 +error[E0805]: malformed `doc` attribute input + --> $DIR/invalid-cfg.rs:13:1 | LL | #[doc(cfg(x, y))] - | ^ + | ^^^^^^^^^------^^ + | | + | expected a single argument here + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #[doc(cfg(x, y))] +LL + #[doc = "string"] + | +LL - #[doc(cfg(x, y))] +LL + #[doc(hidden)] + | +LL - #[doc(cfg(x, y))] +LL + #[doc(inline)] + | +LL - #[doc(cfg(x, y))] +LL + #[doc(test)] + | -error: `cfg` is not followed by parentheses - --> $DIR/invalid-cfg.rs:18:7 +error[E0539]: malformed `doc` attribute input + --> $DIR/invalid-cfg.rs:18:1 | LL | #[doc(cfg = "x")] - | ^^^^^^^^^ help: expected syntax is: `cfg(/* predicate */)` + | ^^^^^^^^^^^^^^^^^ expected this to be a list + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #[doc(cfg = "x")] +LL + #[doc = "string"] + | +LL - #[doc(cfg = "x")] +LL + #[doc(hidden)] + | +LL - #[doc(cfg = "x")] +LL + #[doc(inline)] + | +LL - #[doc(cfg = "x")] +LL + #[doc(test)] + | -error: multiple `cfg` predicates are specified - --> $DIR/invalid-cfg.rs:19:14 +error[E0805]: malformed `doc` attribute input + --> $DIR/invalid-cfg.rs:19:1 | LL | #[doc(cfg(x, y))] - | ^ + | ^^^^^^^^^------^^ + | | + | expected a single argument here + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #[doc(cfg(x, y))] +LL + #[doc = "string"] + | +LL - #[doc(cfg(x, y))] +LL + #[doc(hidden)] + | +LL - #[doc(cfg(x, y))] +LL + #[doc(inline)] + | +LL - #[doc(cfg(x, y))] +LL + #[doc(test)] + | error: aborting due to 8 previous errors +Some errors have detailed explanations: E0539, E0805. +For more information about an error, try `rustc --explain E0539`. diff --git a/tests/rustdoc-ui/lints/doc-attr-2.rs b/tests/rustdoc-ui/lints/doc-attr-2.rs new file mode 100644 index 000000000000..e5198e347523 --- /dev/null +++ b/tests/rustdoc-ui/lints/doc-attr-2.rs @@ -0,0 +1,11 @@ +#![doc(as_ptr)] +//~^ ERROR unknown `doc` attribute `as_ptr` + +#[doc(as_ptr)] +//~^ ERROR unknown `doc` attribute `as_ptr` +pub fn foo() {} + +#[doc(foo::bar, crate::bar::baz = "bye")] +//~^ ERROR unknown `doc` attribute `foo::bar` +//~| ERROR unknown `doc` attribute `crate::bar::baz` +fn bar() {} diff --git a/tests/rustdoc-ui/lints/doc-attr-2.stderr b/tests/rustdoc-ui/lints/doc-attr-2.stderr new file mode 100644 index 000000000000..c2bb45c5785e --- /dev/null +++ b/tests/rustdoc-ui/lints/doc-attr-2.stderr @@ -0,0 +1,28 @@ +error: unknown `doc` attribute `as_ptr` + --> $DIR/doc-attr-2.rs:4:7 + | +LL | #[doc(as_ptr)] + | ^^^^^^ + | + = note: `#[deny(invalid_doc_attributes)]` on by default + +error: unknown `doc` attribute `foo::bar` + --> $DIR/doc-attr-2.rs:8:7 + | +LL | #[doc(foo::bar, crate::bar::baz = "bye")] + | ^^^^^^^^ + +error: unknown `doc` attribute `crate::bar::baz` + --> $DIR/doc-attr-2.rs:8:17 + | +LL | #[doc(foo::bar, crate::bar::baz = "bye")] + | ^^^^^^^^^^^^^^^ + +error: unknown `doc` attribute `as_ptr` + --> $DIR/doc-attr-2.rs:1:8 + | +LL | #![doc(as_ptr)] + | ^^^^^^ + +error: aborting due to 4 previous errors + diff --git a/tests/rustdoc-ui/lints/doc-attr.rs b/tests/rustdoc-ui/lints/doc-attr.rs index 666aeb55cbec..b27faa81cb92 100644 --- a/tests/rustdoc-ui/lints/doc-attr.rs +++ b/tests/rustdoc-ui/lints/doc-attr.rs @@ -1,17 +1,8 @@ #![crate_type = "lib"] -#![doc(as_ptr)] -//~^ ERROR unknown `doc` attribute - -#[doc(as_ptr)] -//~^ ERROR unknown `doc` attribute -pub fn foo() {} #[doc(123)] -//~^ ERROR invalid `doc` attribute +//~^ ERROR malformed `doc` attribute #[doc("hello", "bar")] -//~^ ERROR invalid `doc` attribute -//~| ERROR invalid `doc` attribute -#[doc(foo::bar, crate::bar::baz = "bye")] -//~^ ERROR unknown `doc` attribute -//~| ERROR unknown `doc` attribute +//~^ ERROR malformed `doc` attribute +//~| ERROR malformed `doc` attribute fn bar() {} diff --git a/tests/rustdoc-ui/lints/doc-attr.stderr b/tests/rustdoc-ui/lints/doc-attr.stderr index 091ffc20d465..794b585a9de7 100644 --- a/tests/rustdoc-ui/lints/doc-attr.stderr +++ b/tests/rustdoc-ui/lints/doc-attr.stderr @@ -1,46 +1,72 @@ -error: unknown `doc` attribute `as_ptr` - --> $DIR/doc-attr.rs:5:7 - | -LL | #[doc(as_ptr)] - | ^^^^^^ - | - = note: `#[deny(invalid_doc_attributes)]` on by default - -error: invalid `doc` attribute - --> $DIR/doc-attr.rs:9:7 +error[E0539]: malformed `doc` attribute input + --> $DIR/doc-attr.rs:3:1 | LL | #[doc(123)] - | ^^^ + | ^^^^^^---^^ + | | + | expected this to be of the form `... = "..."` + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #[doc(123)] +LL + #[doc = "string"] + | +LL - #[doc(123)] +LL + #[doc(hidden)] + | +LL - #[doc(123)] +LL + #[doc(inline)] + | +LL - #[doc(123)] +LL + #[doc(test)] + | -error: invalid `doc` attribute - --> $DIR/doc-attr.rs:11:7 +error[E0539]: malformed `doc` attribute input + --> $DIR/doc-attr.rs:5:1 | LL | #[doc("hello", "bar")] - | ^^^^^^^ + | ^^^^^^-------^^^^^^^^^ + | | + | expected this to be of the form `... = "..."` + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #[doc("hello", "bar")] +LL + #[doc = "string"] + | +LL - #[doc("hello", "bar")] +LL + #[doc(hidden)] + | +LL - #[doc("hello", "bar")] +LL + #[doc(inline)] + | +LL - #[doc("hello", "bar")] +LL + #[doc(test)] + | -error: invalid `doc` attribute - --> $DIR/doc-attr.rs:11:16 +error[E0539]: malformed `doc` attribute input + --> $DIR/doc-attr.rs:5:1 | LL | #[doc("hello", "bar")] - | ^^^^^ - -error: unknown `doc` attribute `foo::bar` - --> $DIR/doc-attr.rs:14:7 + | ^^^^^^^^^^^^^^^-----^^ + | | + | expected this to be of the form `... = "..."` | -LL | #[doc(foo::bar, crate::bar::baz = "bye")] - | ^^^^^^^^ - -error: unknown `doc` attribute `crate::bar::baz` - --> $DIR/doc-attr.rs:14:17 +help: try changing it to one of the following valid forms of the attribute | -LL | #[doc(foo::bar, crate::bar::baz = "bye")] - | ^^^^^^^^^^^^^^^^^^^^^^^ - -error: unknown `doc` attribute `as_ptr` - --> $DIR/doc-attr.rs:2:8 +LL - #[doc("hello", "bar")] +LL + #[doc = "string"] + | +LL - #[doc("hello", "bar")] +LL + #[doc(hidden)] + | +LL - #[doc("hello", "bar")] +LL + #[doc(inline)] + | +LL - #[doc("hello", "bar")] +LL + #[doc(test)] | -LL | #![doc(as_ptr)] - | ^^^^^^ -error: aborting due to 7 previous errors +error: aborting due to 3 previous errors +For more information about this error, try `rustc --explain E0539`. From 3fa499bab0313ad3893b7b765c71c1654924af32 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 4 Dec 2025 16:50:14 +0100 Subject: [PATCH 21/64] Sort fluent messages --- compiler/rustc_attr_parsing/messages.ftl | 164 ++++++++++++----------- 1 file changed, 83 insertions(+), 81 deletions(-) diff --git a/compiler/rustc_attr_parsing/messages.ftl b/compiler/rustc_attr_parsing/messages.ftl index 4d7716560fb2..2a98b87e7a7e 100644 --- a/compiler/rustc_attr_parsing/messages.ftl +++ b/compiler/rustc_attr_parsing/messages.ftl @@ -14,8 +14,91 @@ attr_parsing_deprecated_item_suggestion = .help = add `#![feature(deprecated_suggestion)]` to the crate root .note = see #94785 for more details +attr_parsing_doc_alias_bad_char = + {$char_} character isn't allowed in {$attr_str} + +attr_parsing_doc_alias_duplicated = doc alias is duplicated + .label = first defined here + +attr_parsing_doc_alias_empty = + {$attr_str} attribute cannot have empty value + +attr_parsing_doc_alias_malformed = + doc alias attribute expects a string `#[doc(alias = "a")]` or a list of strings `#[doc(alias("a", "b"))]` + +attr_parsing_doc_alias_start_end = + {$attr_str} cannot start or end with ' ' + +attr_parsing_doc_attribute_not_attribute = + nonexistent builtin attribute `{$attribute}` used in `#[doc(attribute = "...")]` + .help = only existing builtin attributes are allowed in core/std + +attr_parsing_doc_auto_cfg_expects_hide_or_show = + only `hide` or `show` are allowed in `#[doc(auto_cfg(...))]` + +attr_parsing_doc_auto_cfg_hide_show_expects_list = + `#![doc(auto_cfg({$attr_name}(...)))]` expects a list of items + +attr_parsing_doc_auto_cfg_hide_show_unexpected_item = + `#![doc(auto_cfg({$attr_name}(...)))]` only accepts identifiers or key/value items + +attr_parsing_doc_auto_cfg_wrong_literal = + expected boolean for `#[doc(auto_cfg = ...)]` + +attr_parsing_doc_invalid = + invalid `doc` attribute + +attr_parsing_doc_keyword_not_keyword = + nonexistent keyword `{$keyword}` used in `#[doc(keyword = "...")]` + .help = only existing keywords are allowed in core/std + +attr_parsing_doc_test_literal = `#![doc(test(...)]` does not take a literal + +attr_parsing_doc_test_takes_list = + `#[doc(test(...)]` takes a list of attributes + +attr_parsing_doc_test_unknown = + unknown `doc(test)` attribute `{$name}` + +attr_parsing_doc_unknown_any = + unknown `doc` attribute `{$name}` + +attr_parsing_doc_unknown_include = + unknown `doc` attribute `include` + .suggestion = use `doc = include_str!` instead + +attr_parsing_doc_unknown_passes = + unknown `doc` attribute `{$name}` + .note = `doc` attribute `{$name}` no longer functions; see issue #44136 + .label = no longer functions + .no_op_note = `doc({$name})` is now a no-op + +attr_parsing_doc_unknown_plugins = + unknown `doc` attribute `plugins` + .note = `doc` attribute `plugins` no longer functions; see issue #44136 and CVE-2018-1000622 + .label = no longer functions + .no_op_note = `doc(plugins)` is now a no-op + +attr_parsing_doc_unknown_spotlight = + unknown `doc` attribute `spotlight` + .note = `doc(spotlight)` was renamed to `doc(notable_trait)` + .suggestion = use `notable_trait` instead + .no_op_note = `doc(spotlight)` is now a no-op + +attr_parsing_empty_attribute = + unused attribute + .suggestion = {$valid_without_list -> + [true] remove these parentheses + *[other] remove this attribute + } + .note = {$valid_without_list -> + [true] using `{$attr_path}` with an empty list is equivalent to not using a list at all + *[other] using `{$attr_path}` with an empty list has no effect + } + attr_parsing_empty_confusables = expected at least one confusable name + attr_parsing_empty_link_name = link name must not be empty .label = empty link name @@ -239,84 +322,3 @@ attr_parsing_doc_alias_duplicated = doc alias is duplicated attr_parsing_whole_archive_needs_static = linking modifier `whole-archive` is only compatible with `static` linking kind - -attr_parsing_unused_no_lints_note = - attribute `{$name}` without any lints has no effect - -attr_parsing_doc_alias_empty = - {$attr_str} attribute cannot have empty value - -attr_parsing_doc_alias_bad_char = - {$char_} character isn't allowed in {$attr_str} - -attr_parsing_doc_alias_start_end = - {$attr_str} cannot start or end with ' ' - -attr_parsing_doc_keyword_not_keyword = - nonexistent keyword `{$keyword}` used in `#[doc(keyword = "...")]` - .help = only existing keywords are allowed in core/std - -attr_parsing_doc_attribute_not_attribute = - nonexistent builtin attribute `{$attribute}` used in `#[doc(attribute = "...")]` - .help = only existing builtin attributes are allowed in core/std - -attr_parsing_doc_inline_conflict = - conflicting doc inlining attributes - .help = remove one of the conflicting attributes - -attr_parsing_doc_inline_conflict_first = - this attribute... - -attr_parsing_doc_inline_conflict_second = - {"."}..conflicts with this attribute - -attr_parsing_doc_auto_cfg_expects_hide_or_show = - only `hide` or `show` are allowed in `#[doc(auto_cfg(...))]` - -attr_parsing_doc_auto_cfg_hide_show_unexpected_item = - `#![doc(auto_cfg({$attr_name}(...)))]` only accepts identifiers or key/value items - -attr_parsing_doc_auto_cfg_hide_show_expects_list = - `#![doc(auto_cfg({$attr_name}(...)))]` expects a list of items - -attr_parsing_doc_invalid = - invalid `doc` attribute - -attr_parsing_doc_unknown_include = - unknown `doc` attribute `include` - .suggestion = use `doc = include_str!` instead - -attr_parsing_doc_unknown_spotlight = - unknown `doc` attribute `spotlight` - .note = `doc(spotlight)` was renamed to `doc(notable_trait)` - .suggestion = use `notable_trait` instead - .no_op_note = `doc(spotlight)` is now a no-op - -attr_parsing_doc_unknown_passes = - unknown `doc` attribute `{$name}` - .note = `doc` attribute `{$name}` no longer functions; see issue #44136 - .label = no longer functions - .no_op_note = `doc({$name})` is now a no-op - -attr_parsing_doc_unknown_plugins = - unknown `doc` attribute `plugins` - .note = `doc` attribute `plugins` no longer functions; see issue #44136 and CVE-2018-1000622 - .label = no longer functions - .no_op_note = `doc(plugins)` is now a no-op - -attr_parsing_doc_unknown_any = - unknown `doc` attribute `{$name}` - -attr_parsing_doc_auto_cfg_wrong_literal = - expected boolean for `#[doc(auto_cfg = ...)]` - -attr_parsing_doc_test_takes_list = - `#[doc(test(...)]` takes a list of attributes - -attr_parsing_doc_test_unknown = - unknown `doc(test)` attribute `{$name}` - -attr_parsing_doc_test_literal = `#![doc(test(...)]` does not take a literal - -attr_parsing_doc_alias_malformed = - doc alias attribute expects a string `#[doc(alias = "a")]` or a list of strings `#[doc(alias("a", "b"))]` From a36c462fb86cce3ca7abcdc9c577f68d76f0a4bf Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 4 Dec 2025 17:43:19 +0100 Subject: [PATCH 22/64] Update clippy code to new doc attribute API --- .../src/doc/doc_suspicious_footnotes.rs | 14 +++++++++----- src/tools/clippy/clippy_lints/src/doc/mod.rs | 2 +- .../src/doc/suspicious_doc_comments.rs | 6 +++--- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/src/tools/clippy/clippy_lints/src/doc/doc_suspicious_footnotes.rs b/src/tools/clippy/clippy_lints/src/doc/doc_suspicious_footnotes.rs index 3330cc5defd3..1944cd7c91d3 100644 --- a/src/tools/clippy/clippy_lints/src/doc/doc_suspicious_footnotes.rs +++ b/src/tools/clippy/clippy_lints/src/doc/doc_suspicious_footnotes.rs @@ -1,10 +1,9 @@ use clippy_utils::diagnostics::span_lint_and_then; use rustc_ast::attr::AttributeExt as _; -use rustc_ast::token::CommentKind; +use rustc_ast::token::{CommentKind, DocFragmentKind}; use rustc_errors::Applicability; use rustc_hir::{AttrStyle, Attribute}; use rustc_lint::{LateContext, LintContext}; -use rustc_resolve::rustdoc::DocFragmentKind; use std::ops::Range; @@ -43,13 +42,18 @@ pub fn check(cx: &LateContext<'_>, doc: &str, range: Range, fragments: &F span, "looks like a footnote ref, but has no matching footnote", |diag| { - if this_fragment.kind == DocFragmentKind::SugaredDoc { - let (doc_attr, (_, doc_attr_comment_kind), attr_style) = attrs + if let DocFragmentKind::Sugared(_) = this_fragment.kind { + let (doc_attr, doc_attr_comment_kind, attr_style) = attrs .iter() .filter(|attr| attr.span().overlaps(this_fragment.span)) .rev() .find_map(|attr| { - Some((attr, attr.doc_str_and_comment_kind()?, attr.doc_resolution_scope()?)) + let (_, fragment) = attr.doc_str_and_fragment_kind()?; + let fragment = match fragment { + DocFragmentKind::Sugared(kind) => kind, + DocFragmentKind::Raw(_) => CommentKind::Line, + }; + Some((attr, fragment, attr.doc_resolution_scope()?)) }) .unwrap(); let (to_add, terminator) = match (doc_attr_comment_kind, attr_style) { diff --git a/src/tools/clippy/clippy_lints/src/doc/mod.rs b/src/tools/clippy/clippy_lints/src/doc/mod.rs index 120da92da944..b11b2f8392c1 100644 --- a/src/tools/clippy/clippy_lints/src/doc/mod.rs +++ b/src/tools/clippy/clippy_lints/src/doc/mod.rs @@ -861,7 +861,7 @@ fn check_attrs(cx: &LateContext<'_>, valid_idents: &FxHashSet, attrs: &[ let (fragments, _) = attrs_to_doc_fragments( attrs.iter().filter_map(|attr| { - if attr.doc_str_and_comment_kind().is_none() || attr.span().in_external_macro(cx.sess().source_map()) { + if attr.doc_str_and_fragment_kind().is_none() || attr.span().in_external_macro(cx.sess().source_map()) { None } else { Some((attr, None)) diff --git a/src/tools/clippy/clippy_lints/src/doc/suspicious_doc_comments.rs b/src/tools/clippy/clippy_lints/src/doc/suspicious_doc_comments.rs index 47d91b80e7ee..e751600f00a6 100644 --- a/src/tools/clippy/clippy_lints/src/doc/suspicious_doc_comments.rs +++ b/src/tools/clippy/clippy_lints/src/doc/suspicious_doc_comments.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use rustc_ast::AttrStyle; -use rustc_ast::token::CommentKind; +use rustc_ast::token::{CommentKind, DocFragmentKind}; use rustc_errors::Applicability; use rustc_hir::Attribute; use rustc_hir::attrs::AttributeKind; @@ -46,8 +46,8 @@ fn collect_doc_replacements(attrs: &[Attribute]) -> Vec<(Span, String)> { && let Some(com) = comment.as_str().strip_prefix('!') { let sugg = match kind { - CommentKind::Line => format!("//!{com}"), - CommentKind::Block => format!("/*!{com}*/"), + DocFragmentKind::Sugared(CommentKind::Block) => format!("/*!{com}*/"), + DocFragmentKind::Sugared(CommentKind::Line) | DocFragmentKind::Raw(_) => format!("//!{com}"), }; Some((attr.span(), sugg)) } else { From aa3bf6fde949990eb75ae4f8d083109cfacba029 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 4 Dec 2025 18:44:59 +0100 Subject: [PATCH 23/64] Update rustc_resolve unit tests --- compiler/rustc_resolve/src/rustdoc/tests.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_resolve/src/rustdoc/tests.rs b/compiler/rustc_resolve/src/rustdoc/tests.rs index 6a98ae066304..9fea6f6807e4 100644 --- a/compiler/rustc_resolve/src/rustdoc/tests.rs +++ b/compiler/rustc_resolve/src/rustdoc/tests.rs @@ -2,7 +2,7 @@ use std::path::PathBuf; use rustc_span::source_map::{FilePathMapping, SourceMap}; use rustc_span::symbol::sym; -use rustc_span::{BytePos, Span}; +use rustc_span::{BytePos, DUMMY_SP, Span}; use super::{DocFragment, DocFragmentKind, source_span_for_markdown_range_inner}; @@ -17,7 +17,7 @@ fn single_backtick() { &[DocFragment { span: Span::with_root_ctxt(BytePos(8), BytePos(11)), item_id: None, - kind: DocFragmentKind::RawDoc, + kind: DocFragmentKind::Raw(DUMMY_SP), doc: sym::empty, // unused placeholder indent: 0, from_expansion: false, @@ -40,7 +40,7 @@ fn utf8() { &[DocFragment { span: Span::with_root_ctxt(BytePos(8), BytePos(14)), item_id: None, - kind: DocFragmentKind::RawDoc, + kind: DocFragmentKind::Raw(DUMMY_SP), doc: sym::empty, // unused placeholder indent: 0, from_expansion: false, From 4936973d49d653d01a114a00a14d427e37296775 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 5 Dec 2025 01:23:38 +0100 Subject: [PATCH 24/64] Fix ui tests --- .../rustc_attr_parsing/src/attributes/doc.rs | 40 ++++- compiler/rustc_attr_parsing/src/interface.rs | 3 +- compiler/rustc_expand/src/expand.rs | 2 +- compiler/rustc_lint/src/builtin.rs | 10 +- compiler/rustc_passes/src/check_attr.rs | 58 ++++--- tests/rustdoc-ui/bad-render-options.stderr | 63 ++++---- tests/rustdoc-ui/check-doc-alias-attr.stderr | 14 +- tests/rustdoc-ui/doc-cfg.stderr | 35 +++-- tests/rustdoc-ui/invalid-cfg.stderr | 56 ++++--- tests/rustdoc-ui/lints/doc-attr.stderr | 21 +-- tests/ui/attributes/doc-attr.rs | 6 +- tests/ui/attributes/doc-attr.stderr | 93 ++++++++--- tests/ui/attributes/doc-test-literal.rs | 2 +- tests/ui/attributes/doc-test-literal.stderr | 25 ++- .../extented-attribute-macro-error.rs | 1 + .../extented-attribute-macro-error.stderr | 8 +- .../ui/attributes/issue-115264-expr-field.rs | 2 + .../attributes/issue-115264-expr-field.stderr | 12 ++ tests/ui/attributes/issue-115264-pat-field.rs | 2 + .../attributes/issue-115264-pat-field.stderr | 12 ++ .../attributes/key-value-expansion-scope.rs | 16 ++ .../key-value-expansion-scope.stderr | 148 +++++++++++++++--- .../ui/attributes/key-value-expansion.stderr | 12 +- tests/ui/attributes/malformed-attrs.stderr | 66 ++++---- ...es-note-version-and-pr-issue-141619.stderr | 2 +- .../invalid-utf8-binary-file.rs | 4 +- .../invalid-utf8-binary-file.stderr | 8 +- tests/ui/lint/unused/useless-comment.rs | 16 +- tests/ui/lint/unused/useless-comment.stderr | 70 +++++++-- .../ui/malformed/malformed-regressions.stderr | 24 ++- .../attribute/attr-unquoted-ident.stderr | 13 -- .../rustdoc/check-doc-alias-attr-location.rs | 17 +- .../check-doc-alias-attr-location.stderr | 67 ++++++-- tests/ui/rustdoc/check-doc-alias-attr.stderr | 63 ++++++-- tests/ui/rustdoc/doc-alias-crate-level.stderr | 4 +- tests/ui/rustdoc/doc-alias-same-name.stderr | 6 +- tests/ui/rustdoc/doc-primitive.stderr | 2 +- tests/ui/rustdoc/doc-test-attr.stderr | 4 +- tests/ui/rustdoc/doc_keyword.rs | 6 +- tests/ui/rustdoc/doc_keyword.stderr | 30 ++-- tests/ui/rustdoc/duplicate_doc_alias.stderr | 8 +- 41 files changed, 730 insertions(+), 321 deletions(-) create mode 100644 tests/ui/attributes/issue-115264-expr-field.stderr create mode 100644 tests/ui/attributes/issue-115264-pat-field.stderr diff --git a/compiler/rustc_attr_parsing/src/attributes/doc.rs b/compiler/rustc_attr_parsing/src/attributes/doc.rs index 2e8249fb35be..83a6c4fc44d9 100644 --- a/compiler/rustc_attr_parsing/src/attributes/doc.rs +++ b/compiler/rustc_attr_parsing/src/attributes/doc.rs @@ -10,7 +10,7 @@ use rustc_hir::lints::AttributeLintKind; use rustc_span::{Span, Symbol, edition, sym}; use thin_vec::ThinVec; -use super::prelude::{Allow, AllowedTargets, MethodKind, Target}; +use super::prelude::{Allow, AllowedTargets, Error, MethodKind, Target}; use super::{AcceptMapping, AttributeParser}; use crate::context::{AcceptContext, FinalizeContext, Stage}; use crate::fluent_generated as fluent; @@ -459,7 +459,9 @@ impl DocParser { ) { match args { ArgParser::NoArgs => { - todo!() + let suggestions = cx.suggestions(); + let span = cx.attr_span; + cx.emit_lint(AttributeLintKind::IllFormedAttributeInput { suggestions }, span); } ArgParser::List(items) => { for i in items.mixed() { @@ -493,12 +495,41 @@ impl DocParser { impl AttributeParser for DocParser { const ATTRIBUTES: AcceptMapping = &[( &[sym::doc], - template!(List: &["hidden", "inline", "test"], NameValueStr: "string"), + template!( + List: &[ + "alias", + "attribute", + "hidden", + "html_favicon_url", + "html_logo_url", + "html_no_source", + "html_playground_url", + "html_root_url", + "issue_tracker_base_url", + "inline", + "no_inline", + "masked", + "cfg", + "notable_trait", + "keyword", + "fake_variadic", + "search_unbox", + "rust_logo", + "auto_cfg", + "test", + "spotlight", + "include", + "no_default_passes", + "passes", + "plugins", + ], + NameValueStr: "string" + ), |this, cx, args| { this.accept_single_doc_attr(cx, args); }, )]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[ Allow(Target::ExternCrate), Allow(Target::Use), Allow(Target::Static), @@ -527,6 +558,7 @@ impl AttributeParser for DocParser { Allow(Target::ForeignTy), Allow(Target::MacroDef), Allow(Target::Crate), + Error(Target::WherePredicate), ]); fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option { diff --git a/compiler/rustc_attr_parsing/src/interface.rs b/compiler/rustc_attr_parsing/src/interface.rs index b1538b447da0..5eefce75ace2 100644 --- a/compiler/rustc_attr_parsing/src/interface.rs +++ b/compiler/rustc_attr_parsing/src/interface.rs @@ -1,8 +1,8 @@ use std::borrow::Cow; use rustc_ast as ast; -use rustc_ast::{AttrStyle, NodeId, Safety}; use rustc_ast::token::DocFragmentKind; +use rustc_ast::{AttrStyle, NodeId, Safety}; use rustc_errors::DiagCtxtHandle; use rustc_feature::{AttributeTemplate, Features}; use rustc_hir::attrs::AttributeKind; @@ -357,7 +357,6 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { continue; } - let path = parser.path(); for accept in accepts { let mut cx: AcceptContext<'_, 'sess, S> = AcceptContext { shared: SharedContext { diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 90563b21d2e8..33431556c76c 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -2177,7 +2177,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { continue; } - if attr.is_doc_comment() { + if attr.doc_str_and_fragment_kind().is_some() { self.cx.sess.psess.buffer_lint( UNUSED_DOC_COMMENTS, current_span, diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index ae973a3c49c2..bf66c7f85508 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -813,19 +813,23 @@ fn warn_if_doc(cx: &EarlyContext<'_>, node_span: Span, node_kind: &str, attrs: & let mut sugared_span: Option = None; while let Some(attr) = attrs.next() { - let is_doc_comment = attr.is_doc_comment(); + let (is_doc_comment, is_doc_attribute) = match &attr.kind { + AttrKind::DocComment(..) => (true, false), + AttrKind::Normal(normal) if normal.item.path == sym::doc => (true, true), + _ => (false, false), + }; if is_doc_comment { sugared_span = Some(sugared_span.map_or(attr.span, |span| span.with_hi(attr.span.hi()))); } - if attrs.peek().is_some_and(|next_attr| next_attr.is_doc_comment()) { + if !is_doc_attribute && attrs.peek().is_some_and(|next_attr| next_attr.is_doc_comment()) { continue; } let span = sugared_span.take().unwrap_or(attr.span); - if is_doc_comment { + if is_doc_comment || is_doc_attribute { let sub = match attr.kind { AttrKind::DocComment(CommentKind::Line, _) | AttrKind::Normal(..) => { BuiltinUnusedDocCommentSub::PlainHelp diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 3f29d943e7d3..030839baad9b 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -1029,25 +1029,27 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - if let Some((_, span)) = keyword { - self.check_attr_not_crate_level(*span, hir_id, "keyword"); + if let Some((_, span)) = keyword + && self.check_attr_not_crate_level(*span, hir_id, "keyword") + { self.check_doc_keyword_and_attribute(*span, hir_id, "keyword"); } - if let Some((_, span)) = attribute { - self.check_attr_not_crate_level(*span, hir_id, "attribute"); + if let Some((_, span)) = attribute + && self.check_attr_not_crate_level(*span, hir_id, "attribute") + { self.check_doc_keyword_and_attribute(*span, hir_id, "attribute"); } - if let Some(span) = fake_variadic { - if self.check_attr_not_crate_level(*span, hir_id, "fake_variadic") { - self.check_doc_fake_variadic(*span, hir_id); - } + if let Some(span) = fake_variadic + && self.check_attr_not_crate_level(*span, hir_id, "fake_variadic") + { + self.check_doc_fake_variadic(*span, hir_id); } - if let Some(span) = search_unbox { - if self.check_attr_not_crate_level(*span, hir_id, "search_unbox") { - self.check_doc_search_unbox(*span, hir_id); - } + if let Some(span) = search_unbox + && self.check_attr_not_crate_level(*span, hir_id, "search_unbox") + { + self.check_doc_search_unbox(*span, hir_id); } for i in [ @@ -1070,18 +1072,17 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.check_doc_inline(hir_id, target, inline); - if let Some(span) = rust_logo { - if self.check_attr_crate_level(*span, hir_id) - && !self.tcx.features().rustdoc_internals() - { - feature_err( - &self.tcx.sess, - sym::rustdoc_internals, - *span, - fluent::passes_doc_rust_logo, - ) - .emit(); - } + if let Some(span) = rust_logo + && self.check_attr_crate_level(*span, hir_id) + && !self.tcx.features().rustdoc_internals() + { + feature_err( + &self.tcx.sess, + sym::rustdoc_internals, + *span, + fluent::passes_doc_rust_logo, + ) + .emit(); } if let Some(span) = masked { @@ -1984,7 +1985,14 @@ impl<'tcx> Visitor<'tcx> for CheckAttrVisitor<'tcx> { .hir_attrs(where_predicate.hir_id) .iter() .filter(|attr| !ATTRS_ALLOWED.iter().any(|&sym| attr.has_name(sym))) - .filter(|attr| !attr.is_parsed_attr()) + // FIXME: We shouldn't need to special-case `doc`! + .filter(|attr| { + matches!( + attr, + Attribute::Parsed(AttributeKind::DocComment { .. } | AttributeKind::Doc(_)) + | Attribute::Unparsed(_) + ) + }) .map(|attr| attr.span()) .collect::>(); if !spans.is_empty() { diff --git a/tests/rustdoc-ui/bad-render-options.stderr b/tests/rustdoc-ui/bad-render-options.stderr index e7f33f4dff1d..296a41337f33 100644 --- a/tests/rustdoc-ui/bad-render-options.stderr +++ b/tests/rustdoc-ui/bad-render-options.stderr @@ -12,14 +12,15 @@ LL - #![doc(html_favicon_url)] LL + #![doc = "string"] | LL - #![doc(html_favicon_url)] -LL + #![doc(hidden)] +LL + #![doc(alias)] | LL - #![doc(html_favicon_url)] -LL + #![doc(inline)] +LL + #![doc(attribute)] | LL - #![doc(html_favicon_url)] -LL + #![doc(test)] +LL + #![doc(auto_cfg)] | + = and 21 other candidates error[E0539]: malformed `doc` attribute input --> $DIR/bad-render-options.rs:6:1 @@ -35,14 +36,15 @@ LL - #![doc(html_logo_url)] LL + #![doc = "string"] | LL - #![doc(html_logo_url)] -LL + #![doc(hidden)] +LL + #![doc(alias)] | LL - #![doc(html_logo_url)] -LL + #![doc(inline)] +LL + #![doc(attribute)] | LL - #![doc(html_logo_url)] -LL + #![doc(test)] +LL + #![doc(auto_cfg)] | + = and 21 other candidates error[E0539]: malformed `doc` attribute input --> $DIR/bad-render-options.rs:9:1 @@ -58,14 +60,15 @@ LL - #![doc(html_playground_url)] LL + #![doc = "string"] | LL - #![doc(html_playground_url)] -LL + #![doc(hidden)] +LL + #![doc(alias)] | LL - #![doc(html_playground_url)] -LL + #![doc(inline)] +LL + #![doc(attribute)] | LL - #![doc(html_playground_url)] -LL + #![doc(test)] +LL + #![doc(auto_cfg)] | + = and 21 other candidates error[E0539]: malformed `doc` attribute input --> $DIR/bad-render-options.rs:12:1 @@ -81,14 +84,15 @@ LL - #![doc(issue_tracker_base_url)] LL + #![doc = "string"] | LL - #![doc(issue_tracker_base_url)] -LL + #![doc(hidden)] +LL + #![doc(alias)] | LL - #![doc(issue_tracker_base_url)] -LL + #![doc(inline)] +LL + #![doc(attribute)] | LL - #![doc(issue_tracker_base_url)] -LL + #![doc(test)] +LL + #![doc(auto_cfg)] | + = and 21 other candidates error[E0539]: malformed `doc` attribute input --> $DIR/bad-render-options.rs:15:1 @@ -104,14 +108,15 @@ LL - #![doc(html_favicon_url = 1)] LL + #![doc = "string"] | LL - #![doc(html_favicon_url = 1)] -LL + #![doc(hidden)] +LL + #![doc(alias)] | LL - #![doc(html_favicon_url = 1)] -LL + #![doc(inline)] +LL + #![doc(attribute)] | LL - #![doc(html_favicon_url = 1)] -LL + #![doc(test)] +LL + #![doc(auto_cfg)] | + = and 22 other candidates error[E0539]: malformed `doc` attribute input --> $DIR/bad-render-options.rs:18:1 @@ -127,14 +132,15 @@ LL - #![doc(html_logo_url = 2)] LL + #![doc = "string"] | LL - #![doc(html_logo_url = 2)] -LL + #![doc(hidden)] +LL + #![doc(alias)] | LL - #![doc(html_logo_url = 2)] -LL + #![doc(inline)] +LL + #![doc(attribute)] | LL - #![doc(html_logo_url = 2)] -LL + #![doc(test)] +LL + #![doc(auto_cfg)] | + = and 22 other candidates error[E0539]: malformed `doc` attribute input --> $DIR/bad-render-options.rs:21:1 @@ -150,14 +156,15 @@ LL - #![doc(html_playground_url = 3)] LL + #![doc = "string"] | LL - #![doc(html_playground_url = 3)] -LL + #![doc(hidden)] +LL + #![doc(alias)] | LL - #![doc(html_playground_url = 3)] -LL + #![doc(inline)] +LL + #![doc(attribute)] | LL - #![doc(html_playground_url = 3)] -LL + #![doc(test)] +LL + #![doc(auto_cfg)] | + = and 22 other candidates error[E0539]: malformed `doc` attribute input --> $DIR/bad-render-options.rs:24:1 @@ -173,14 +180,15 @@ LL - #![doc(issue_tracker_base_url = 4)] LL + #![doc = "string"] | LL - #![doc(issue_tracker_base_url = 4)] -LL + #![doc(hidden)] +LL + #![doc(alias)] | LL - #![doc(issue_tracker_base_url = 4)] -LL + #![doc(inline)] +LL + #![doc(attribute)] | LL - #![doc(issue_tracker_base_url = 4)] -LL + #![doc(test)] +LL + #![doc(auto_cfg)] | + = and 22 other candidates error[E0565]: malformed `doc` attribute input --> $DIR/bad-render-options.rs:27:1 @@ -196,14 +204,15 @@ LL - #![doc(html_no_source = "asdf")] LL + #![doc = "string"] | LL - #![doc(html_no_source = "asdf")] -LL + #![doc(hidden)] +LL + #![doc(alias)] | LL - #![doc(html_no_source = "asdf")] -LL + #![doc(inline)] +LL + #![doc(attribute)] | LL - #![doc(html_no_source = "asdf")] -LL + #![doc(test)] +LL + #![doc(auto_cfg)] | + = and 22 other candidates error: aborting due to 9 previous errors diff --git a/tests/rustdoc-ui/check-doc-alias-attr.stderr b/tests/rustdoc-ui/check-doc-alias-attr.stderr index 06d5c6535191..6c33f10e8785 100644 --- a/tests/rustdoc-ui/check-doc-alias-attr.stderr +++ b/tests/rustdoc-ui/check-doc-alias-attr.stderr @@ -18,14 +18,15 @@ LL - #[doc(alias = 0)] LL + #[doc = "string"] | LL - #[doc(alias = 0)] -LL + #[doc(hidden)] +LL + #[doc(alias)] | LL - #[doc(alias = 0)] -LL + #[doc(inline)] +LL + #[doc(attribute)] | LL - #[doc(alias = 0)] -LL + #[doc(test)] +LL + #[doc(auto_cfg)] | + = and 22 other candidates error: '"' character isn't allowed in `#[doc(alias = "...")]` --> $DIR/check-doc-alias-attr.rs:9:15 @@ -85,14 +86,15 @@ LL - #[doc(alias(0))] LL + #[doc = "string"] | LL - #[doc(alias(0))] -LL + #[doc(hidden)] +LL + #[doc(alias)] | LL - #[doc(alias(0))] -LL + #[doc(inline)] +LL + #[doc(attribute)] | LL - #[doc(alias(0))] -LL + #[doc(test)] +LL + #[doc(auto_cfg)] | + = and 22 other candidates error: '"' character isn't allowed in `#[doc(alias = "...")]` --> $DIR/check-doc-alias-attr.rs:20:13 diff --git a/tests/rustdoc-ui/doc-cfg.stderr b/tests/rustdoc-ui/doc-cfg.stderr index a4c6584d3294..0efeac66554c 100644 --- a/tests/rustdoc-ui/doc-cfg.stderr +++ b/tests/rustdoc-ui/doc-cfg.stderr @@ -12,14 +12,15 @@ LL - #[doc(cfg(), cfg(foo, bar))] LL + #[doc = "string"] | LL - #[doc(cfg(), cfg(foo, bar))] -LL + #[doc(hidden)] +LL + #[doc(alias)] | LL - #[doc(cfg(), cfg(foo, bar))] -LL + #[doc(inline)] +LL + #[doc(attribute)] | LL - #[doc(cfg(), cfg(foo, bar))] -LL + #[doc(test)] +LL + #[doc(auto_cfg)] | + = and 22 other candidates error[E0805]: malformed `doc` attribute input --> $DIR/doc-cfg.rs:3:1 @@ -35,14 +36,15 @@ LL - #[doc(cfg(), cfg(foo, bar))] LL + #[doc = "string"] | LL - #[doc(cfg(), cfg(foo, bar))] -LL + #[doc(hidden)] +LL + #[doc(alias)] | LL - #[doc(cfg(), cfg(foo, bar))] -LL + #[doc(inline)] +LL + #[doc(attribute)] | LL - #[doc(cfg(), cfg(foo, bar))] -LL + #[doc(test)] +LL + #[doc(auto_cfg)] | + = and 22 other candidates error[E0805]: malformed `doc` attribute input --> $DIR/doc-cfg.rs:6:1 @@ -58,14 +60,15 @@ LL - #[doc(cfg())] LL + #[doc = "string"] | LL - #[doc(cfg())] -LL + #[doc(hidden)] +LL + #[doc(alias)] | LL - #[doc(cfg())] -LL + #[doc(inline)] +LL + #[doc(attribute)] | LL - #[doc(cfg())] -LL + #[doc(test)] +LL + #[doc(auto_cfg)] | + = and 22 other candidates error[E0805]: malformed `doc` attribute input --> $DIR/doc-cfg.rs:7:1 @@ -81,14 +84,15 @@ LL - #[doc(cfg(foo, bar))] LL + #[doc = "string"] | LL - #[doc(cfg(foo, bar))] -LL + #[doc(hidden)] +LL + #[doc(alias)] | LL - #[doc(cfg(foo, bar))] -LL + #[doc(inline)] +LL + #[doc(attribute)] | LL - #[doc(cfg(foo, bar))] -LL + #[doc(test)] +LL + #[doc(auto_cfg)] | + = and 22 other candidates error[E0539]: malformed `doc` attribute input --> $DIR/doc-cfg.rs:8:1 @@ -104,14 +108,15 @@ LL - #[doc(auto_cfg(hide(foo::bar)))] LL + #[doc = "string"] | LL - #[doc(auto_cfg(hide(foo::bar)))] -LL + #[doc(hidden)] +LL + #[doc(alias)] | LL - #[doc(auto_cfg(hide(foo::bar)))] -LL + #[doc(inline)] +LL + #[doc(attribute)] | LL - #[doc(auto_cfg(hide(foo::bar)))] -LL + #[doc(test)] +LL + #[doc(auto_cfg)] | + = and 22 other candidates error: aborting due to 5 previous errors diff --git a/tests/rustdoc-ui/invalid-cfg.stderr b/tests/rustdoc-ui/invalid-cfg.stderr index a23784509c8b..3363dbb56fb4 100644 --- a/tests/rustdoc-ui/invalid-cfg.stderr +++ b/tests/rustdoc-ui/invalid-cfg.stderr @@ -10,14 +10,15 @@ LL - #[doc(cfg = "x")] LL + #[doc = "string"] | LL - #[doc(cfg = "x")] -LL + #[doc(hidden)] +LL + #[doc(alias)] | LL - #[doc(cfg = "x")] -LL + #[doc(inline)] +LL + #[doc(attribute)] | LL - #[doc(cfg = "x")] -LL + #[doc(test)] +LL + #[doc(auto_cfg)] | + = and 22 other candidates error[E0805]: malformed `doc` attribute input --> $DIR/invalid-cfg.rs:3:1 @@ -33,14 +34,15 @@ LL - #[doc(cfg(x, y))] LL + #[doc = "string"] | LL - #[doc(cfg(x, y))] -LL + #[doc(hidden)] +LL + #[doc(alias)] | LL - #[doc(cfg(x, y))] -LL + #[doc(inline)] +LL + #[doc(attribute)] | LL - #[doc(cfg(x, y))] -LL + #[doc(test)] +LL + #[doc(auto_cfg)] | + = and 22 other candidates error[E0539]: malformed `doc` attribute input --> $DIR/invalid-cfg.rs:7:1 @@ -54,14 +56,15 @@ LL - #[doc(cfg = "x")] LL + #[doc = "string"] | LL - #[doc(cfg = "x")] -LL + #[doc(hidden)] +LL + #[doc(alias)] | LL - #[doc(cfg = "x")] -LL + #[doc(inline)] +LL + #[doc(attribute)] | LL - #[doc(cfg = "x")] -LL + #[doc(test)] +LL + #[doc(auto_cfg)] | + = and 22 other candidates error[E0805]: malformed `doc` attribute input --> $DIR/invalid-cfg.rs:8:1 @@ -77,14 +80,15 @@ LL - #[doc(cfg(x, y))] LL + #[doc = "string"] | LL - #[doc(cfg(x, y))] -LL + #[doc(hidden)] +LL + #[doc(alias)] | LL - #[doc(cfg(x, y))] -LL + #[doc(inline)] +LL + #[doc(attribute)] | LL - #[doc(cfg(x, y))] -LL + #[doc(test)] +LL + #[doc(auto_cfg)] | + = and 22 other candidates error[E0539]: malformed `doc` attribute input --> $DIR/invalid-cfg.rs:12:1 @@ -98,14 +102,15 @@ LL - #[doc(cfg = "x")] LL + #[doc = "string"] | LL - #[doc(cfg = "x")] -LL + #[doc(hidden)] +LL + #[doc(alias)] | LL - #[doc(cfg = "x")] -LL + #[doc(inline)] +LL + #[doc(attribute)] | LL - #[doc(cfg = "x")] -LL + #[doc(test)] +LL + #[doc(auto_cfg)] | + = and 22 other candidates error[E0805]: malformed `doc` attribute input --> $DIR/invalid-cfg.rs:13:1 @@ -121,14 +126,15 @@ LL - #[doc(cfg(x, y))] LL + #[doc = "string"] | LL - #[doc(cfg(x, y))] -LL + #[doc(hidden)] +LL + #[doc(alias)] | LL - #[doc(cfg(x, y))] -LL + #[doc(inline)] +LL + #[doc(attribute)] | LL - #[doc(cfg(x, y))] -LL + #[doc(test)] +LL + #[doc(auto_cfg)] | + = and 22 other candidates error[E0539]: malformed `doc` attribute input --> $DIR/invalid-cfg.rs:18:1 @@ -142,14 +148,15 @@ LL - #[doc(cfg = "x")] LL + #[doc = "string"] | LL - #[doc(cfg = "x")] -LL + #[doc(hidden)] +LL + #[doc(alias)] | LL - #[doc(cfg = "x")] -LL + #[doc(inline)] +LL + #[doc(attribute)] | LL - #[doc(cfg = "x")] -LL + #[doc(test)] +LL + #[doc(auto_cfg)] | + = and 22 other candidates error[E0805]: malformed `doc` attribute input --> $DIR/invalid-cfg.rs:19:1 @@ -165,14 +172,15 @@ LL - #[doc(cfg(x, y))] LL + #[doc = "string"] | LL - #[doc(cfg(x, y))] -LL + #[doc(hidden)] +LL + #[doc(alias)] | LL - #[doc(cfg(x, y))] -LL + #[doc(inline)] +LL + #[doc(attribute)] | LL - #[doc(cfg(x, y))] -LL + #[doc(test)] +LL + #[doc(auto_cfg)] | + = and 22 other candidates error: aborting due to 8 previous errors diff --git a/tests/rustdoc-ui/lints/doc-attr.stderr b/tests/rustdoc-ui/lints/doc-attr.stderr index 794b585a9de7..1201bd5c71f1 100644 --- a/tests/rustdoc-ui/lints/doc-attr.stderr +++ b/tests/rustdoc-ui/lints/doc-attr.stderr @@ -12,14 +12,15 @@ LL - #[doc(123)] LL + #[doc = "string"] | LL - #[doc(123)] -LL + #[doc(hidden)] +LL + #[doc(alias)] | LL - #[doc(123)] -LL + #[doc(inline)] +LL + #[doc(attribute)] | LL - #[doc(123)] -LL + #[doc(test)] +LL + #[doc(auto_cfg)] | + = and 22 other candidates error[E0539]: malformed `doc` attribute input --> $DIR/doc-attr.rs:5:1 @@ -35,14 +36,15 @@ LL - #[doc("hello", "bar")] LL + #[doc = "string"] | LL - #[doc("hello", "bar")] -LL + #[doc(hidden)] +LL + #[doc(alias)] | LL - #[doc("hello", "bar")] -LL + #[doc(inline)] +LL + #[doc(attribute)] | LL - #[doc("hello", "bar")] -LL + #[doc(test)] +LL + #[doc(auto_cfg)] | + = and 22 other candidates error[E0539]: malformed `doc` attribute input --> $DIR/doc-attr.rs:5:1 @@ -58,14 +60,15 @@ LL - #[doc("hello", "bar")] LL + #[doc = "string"] | LL - #[doc("hello", "bar")] -LL + #[doc(hidden)] +LL + #[doc(alias)] | LL - #[doc("hello", "bar")] -LL + #[doc(inline)] +LL + #[doc(attribute)] | LL - #[doc("hello", "bar")] -LL + #[doc(test)] +LL + #[doc(auto_cfg)] | + = and 22 other candidates error: aborting due to 3 previous errors diff --git a/tests/ui/attributes/doc-attr.rs b/tests/ui/attributes/doc-attr.rs index 666aeb55cbec..8d733be93567 100644 --- a/tests/ui/attributes/doc-attr.rs +++ b/tests/ui/attributes/doc-attr.rs @@ -7,10 +7,10 @@ pub fn foo() {} #[doc(123)] -//~^ ERROR invalid `doc` attribute +//~^ ERROR malformed `doc` attribute #[doc("hello", "bar")] -//~^ ERROR invalid `doc` attribute -//~| ERROR invalid `doc` attribute +//~^ ERROR malformed `doc` attribute +//~| ERROR malformed `doc` attribute #[doc(foo::bar, crate::bar::baz = "bye")] //~^ ERROR unknown `doc` attribute //~| ERROR unknown `doc` attribute diff --git a/tests/ui/attributes/doc-attr.stderr b/tests/ui/attributes/doc-attr.stderr index 091ffc20d465..9234c1a0719b 100644 --- a/tests/ui/attributes/doc-attr.stderr +++ b/tests/ui/attributes/doc-attr.stderr @@ -1,3 +1,75 @@ +error[E0539]: malformed `doc` attribute input + --> $DIR/doc-attr.rs:9:1 + | +LL | #[doc(123)] + | ^^^^^^---^^ + | | + | expected this to be of the form `... = "..."` + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #[doc(123)] +LL + #[doc = "string"] + | +LL - #[doc(123)] +LL + #[doc(alias)] + | +LL - #[doc(123)] +LL + #[doc(attribute)] + | +LL - #[doc(123)] +LL + #[doc(auto_cfg)] + | + = and 22 other candidates + +error[E0539]: malformed `doc` attribute input + --> $DIR/doc-attr.rs:11:1 + | +LL | #[doc("hello", "bar")] + | ^^^^^^-------^^^^^^^^^ + | | + | expected this to be of the form `... = "..."` + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #[doc("hello", "bar")] +LL + #[doc = "string"] + | +LL - #[doc("hello", "bar")] +LL + #[doc(alias)] + | +LL - #[doc("hello", "bar")] +LL + #[doc(attribute)] + | +LL - #[doc("hello", "bar")] +LL + #[doc(auto_cfg)] + | + = and 22 other candidates + +error[E0539]: malformed `doc` attribute input + --> $DIR/doc-attr.rs:11:1 + | +LL | #[doc("hello", "bar")] + | ^^^^^^^^^^^^^^^-----^^ + | | + | expected this to be of the form `... = "..."` + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #[doc("hello", "bar")] +LL + #[doc = "string"] + | +LL - #[doc("hello", "bar")] +LL + #[doc(alias)] + | +LL - #[doc("hello", "bar")] +LL + #[doc(attribute)] + | +LL - #[doc("hello", "bar")] +LL + #[doc(auto_cfg)] + | + = and 22 other candidates + error: unknown `doc` attribute `as_ptr` --> $DIR/doc-attr.rs:5:7 | @@ -6,24 +78,6 @@ LL | #[doc(as_ptr)] | = note: `#[deny(invalid_doc_attributes)]` on by default -error: invalid `doc` attribute - --> $DIR/doc-attr.rs:9:7 - | -LL | #[doc(123)] - | ^^^ - -error: invalid `doc` attribute - --> $DIR/doc-attr.rs:11:7 - | -LL | #[doc("hello", "bar")] - | ^^^^^^^ - -error: invalid `doc` attribute - --> $DIR/doc-attr.rs:11:16 - | -LL | #[doc("hello", "bar")] - | ^^^^^ - error: unknown `doc` attribute `foo::bar` --> $DIR/doc-attr.rs:14:7 | @@ -34,7 +88,7 @@ error: unknown `doc` attribute `crate::bar::baz` --> $DIR/doc-attr.rs:14:17 | LL | #[doc(foo::bar, crate::bar::baz = "bye")] - | ^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ error: unknown `doc` attribute `as_ptr` --> $DIR/doc-attr.rs:2:8 @@ -44,3 +98,4 @@ LL | #![doc(as_ptr)] error: aborting due to 7 previous errors +For more information about this error, try `rustc --explain E0539`. diff --git a/tests/ui/attributes/doc-test-literal.rs b/tests/ui/attributes/doc-test-literal.rs index 92fe7846f14c..f9776e9924bd 100644 --- a/tests/ui/attributes/doc-test-literal.rs +++ b/tests/ui/attributes/doc-test-literal.rs @@ -1,4 +1,4 @@ #![doc(test(""))] -//~^ ERROR `#![doc(test(...)]` does not take a literal +//~^ ERROR malformed `doc` attribute input fn main() {} diff --git a/tests/ui/attributes/doc-test-literal.stderr b/tests/ui/attributes/doc-test-literal.stderr index 39e109a76ce5..3ffbdcbb9fee 100644 --- a/tests/ui/attributes/doc-test-literal.stderr +++ b/tests/ui/attributes/doc-test-literal.stderr @@ -1,10 +1,27 @@ -error: `#![doc(test(...)]` does not take a literal - --> $DIR/doc-test-literal.rs:1:13 +error[E0565]: malformed `doc` attribute input + --> $DIR/doc-test-literal.rs:1:1 | LL | #![doc(test(""))] - | ^^ + | ^^^^^^^^^^^^--^^^ + | | + | didn't expect a literal here | - = note: `#[deny(invalid_doc_attributes)]` on by default +help: try changing it to one of the following valid forms of the attribute + | +LL - #![doc(test(""))] +LL + #![doc = "string"] + | +LL - #![doc(test(""))] +LL + #![doc(alias)] + | +LL - #![doc(test(""))] +LL + #![doc(attribute)] + | +LL - #![doc(test(""))] +LL + #![doc(auto_cfg)] + | + = and 22 other candidates error: aborting due to 1 previous error +For more information about this error, try `rustc --explain E0565`. diff --git a/tests/ui/attributes/extented-attribute-macro-error.rs b/tests/ui/attributes/extented-attribute-macro-error.rs index 83060024dac9..f85a28ad706e 100644 --- a/tests/ui/attributes/extented-attribute-macro-error.rs +++ b/tests/ui/attributes/extented-attribute-macro-error.rs @@ -3,5 +3,6 @@ #![doc = include_str!("../not_existing_file.md")] struct Documented {} //~^^ ERROR couldn't read +//~| ERROR attribute value must be a literal fn main() {} diff --git a/tests/ui/attributes/extented-attribute-macro-error.stderr b/tests/ui/attributes/extented-attribute-macro-error.stderr index 7b93b98f64cd..ed46cba3d040 100644 --- a/tests/ui/attributes/extented-attribute-macro-error.stderr +++ b/tests/ui/attributes/extented-attribute-macro-error.stderr @@ -4,5 +4,11 @@ error: couldn't read the file LL | #![doc = include_str!("../not_existing_file.md")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 1 previous error +error: attribute value must be a literal + --> $DIR/extented-attribute-macro-error.rs:3:10 + | +LL | #![doc = include_str!("../not_existing_file.md")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors diff --git a/tests/ui/attributes/issue-115264-expr-field.rs b/tests/ui/attributes/issue-115264-expr-field.rs index 8adb68deb5b4..d8189626fb0f 100644 --- a/tests/ui/attributes/issue-115264-expr-field.rs +++ b/tests/ui/attributes/issue-115264-expr-field.rs @@ -12,6 +12,8 @@ struct X { fn main() { let _ = X { #[doc(alias = "StructItem")] + //~^ WARN: attribute cannot be used on struct fields + //~| WARN: this was previously accepted by the compiler but is being phased out foo: 123, }; } diff --git a/tests/ui/attributes/issue-115264-expr-field.stderr b/tests/ui/attributes/issue-115264-expr-field.stderr new file mode 100644 index 000000000000..6bb9dfc90c93 --- /dev/null +++ b/tests/ui/attributes/issue-115264-expr-field.stderr @@ -0,0 +1,12 @@ +warning: `#[doc]` attribute cannot be used on struct fields + --> $DIR/issue-115264-expr-field.rs:14:9 + | +LL | #[doc(alias = "StructItem")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = help: `#[doc]` can be applied to associated consts, associated types, constants, crates, data types, enum variants, extern crates, foreign modules, foreign statics, functions, impl blocks, macro defs, modules, statics, struct fields, trait aliases, traits, type aliases, unions, and use statements + = note: requested on the command line with `-W unused-attributes` + +warning: 1 warning emitted + diff --git a/tests/ui/attributes/issue-115264-pat-field.rs b/tests/ui/attributes/issue-115264-pat-field.rs index 53e3b4524d60..0c8966b5893f 100644 --- a/tests/ui/attributes/issue-115264-pat-field.rs +++ b/tests/ui/attributes/issue-115264-pat-field.rs @@ -12,6 +12,8 @@ struct X { fn main() { let X { #[doc(alias = "StructItem")] + //~^ WARN: attribute cannot be used on pattern fields + //~| WARN: this was previously accepted by the compiler but is being phased out foo } = X { foo: 123 diff --git a/tests/ui/attributes/issue-115264-pat-field.stderr b/tests/ui/attributes/issue-115264-pat-field.stderr new file mode 100644 index 000000000000..a5b221110789 --- /dev/null +++ b/tests/ui/attributes/issue-115264-pat-field.stderr @@ -0,0 +1,12 @@ +warning: `#[doc]` attribute cannot be used on pattern fields + --> $DIR/issue-115264-pat-field.rs:14:9 + | +LL | #[doc(alias = "StructItem")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = help: `#[doc]` can be applied to associated consts, associated types, constants, crates, data types, enum variants, extern crates, foreign modules, foreign statics, functions, impl blocks, macro defs, modules, statics, struct fields, trait aliases, traits, type aliases, unions, and use statements + = note: requested on the command line with `-W unused-attributes` + +warning: 1 warning emitted + diff --git a/tests/ui/attributes/key-value-expansion-scope.rs b/tests/ui/attributes/key-value-expansion-scope.rs index 6688d698f9ea..b30da2eda24a 100644 --- a/tests/ui/attributes/key-value-expansion-scope.rs +++ b/tests/ui/attributes/key-value-expansion-scope.rs @@ -1,19 +1,29 @@ #![doc = in_root!()] //~ ERROR cannot find macro `in_root` //~| WARN this was previously accepted by the compiler #![doc = in_mod!()] //~ ERROR cannot find macro `in_mod` in this scope + //~| ERROR attribute value must be a literal #![doc = in_mod_escape!()] //~ ERROR cannot find macro `in_mod_escape` //~| WARN this was previously accepted by the compiler #![doc = in_block!()] //~ ERROR cannot find macro `in_block` in this scope + //~| ERROR attribute value must be a literal #[doc = in_root!()] //~ ERROR cannot find macro `in_root` in this scope + //~| ERROR attribute value must be a literal #[doc = in_mod!()] //~ ERROR cannot find macro `in_mod` in this scope + //~| ERROR attribute value must be a literal #[doc = in_mod_escape!()] //~ ERROR cannot find macro `in_mod_escape` in this scope + //~| ERROR attribute value must be a literal #[doc = in_block!()] //~ ERROR cannot find macro `in_block` in this scope + //~| ERROR attribute value must be a literal fn before() { #![doc = in_root!()] //~ ERROR cannot find macro `in_root` in this scope + //~| ERROR attribute value must be a literal #![doc = in_mod!()] //~ ERROR cannot find macro `in_mod` in this scope + //~| ERROR attribute value must be a literal #![doc = in_mod_escape!()] //~ ERROR cannot find macro `in_mod_escape` in this scope + //~| ERROR attribute value must be a literal #![doc = in_block!()] //~ ERROR cannot find macro `in_block` in this scope + //~| ERROR attribute value must be a literal } macro_rules! in_root { () => { "" } } @@ -48,8 +58,10 @@ mod macros_escape { } #[doc = in_block!()] //~ ERROR cannot find macro `in_block` in this scope + //~| ERROR attribute value must be a literal fn block() { #![doc = in_block!()] //~ ERROR cannot find macro `in_block` in this scope + //~| ERROR attribute value must be a literal macro_rules! in_block { () => { "" } } @@ -61,13 +73,17 @@ fn block() { #[doc = in_root!()] // OK #[doc = in_mod!()] //~ ERROR cannot find macro `in_mod` in this scope + //~| ERROR attribute value must be a literal #[doc = in_mod_escape!()] // OK #[doc = in_block!()] //~ ERROR cannot find macro `in_block` in this scope + //~| ERROR attribute value must be a literal fn after() { #![doc = in_root!()] // OK #![doc = in_mod!()] //~ ERROR cannot find macro `in_mod` in this scope + //~| ERROR attribute value must be a literal #![doc = in_mod_escape!()] // OK #![doc = in_block!()] //~ ERROR cannot find macro `in_block` in this scope + //~| ERROR attribute value must be a literal } fn main() {} diff --git a/tests/ui/attributes/key-value-expansion-scope.stderr b/tests/ui/attributes/key-value-expansion-scope.stderr index 71a83d80617a..1ebed6b8b6fc 100644 --- a/tests/ui/attributes/key-value-expansion-scope.stderr +++ b/tests/ui/attributes/key-value-expansion-scope.stderr @@ -7,7 +7,7 @@ LL | #![doc = in_mod!()] = help: have you added the `#[macro_use]` on the module/import? error: cannot find macro `in_block` in this scope - --> $DIR/key-value-expansion-scope.rs:6:10 + --> $DIR/key-value-expansion-scope.rs:7:10 | LL | #![doc = in_block!()] | ^^^^^^^^ @@ -15,7 +15,7 @@ LL | #![doc = in_block!()] = help: have you added the `#[macro_use]` on the module/import? error: cannot find macro `in_root` in this scope - --> $DIR/key-value-expansion-scope.rs:8:9 + --> $DIR/key-value-expansion-scope.rs:10:9 | LL | #[doc = in_root!()] | ^^^^^^^ @@ -23,7 +23,7 @@ LL | #[doc = in_root!()] = help: have you added the `#[macro_use]` on the module/import? error: cannot find macro `in_mod` in this scope - --> $DIR/key-value-expansion-scope.rs:9:9 + --> $DIR/key-value-expansion-scope.rs:12:9 | LL | #[doc = in_mod!()] | ^^^^^^ @@ -31,7 +31,7 @@ LL | #[doc = in_mod!()] = help: have you added the `#[macro_use]` on the module/import? error: cannot find macro `in_mod_escape` in this scope - --> $DIR/key-value-expansion-scope.rs:10:9 + --> $DIR/key-value-expansion-scope.rs:14:9 | LL | #[doc = in_mod_escape!()] | ^^^^^^^^^^^^^ @@ -39,7 +39,7 @@ LL | #[doc = in_mod_escape!()] = help: have you added the `#[macro_use]` on the module/import? error: cannot find macro `in_block` in this scope - --> $DIR/key-value-expansion-scope.rs:11:9 + --> $DIR/key-value-expansion-scope.rs:16:9 | LL | #[doc = in_block!()] | ^^^^^^^^ @@ -47,7 +47,7 @@ LL | #[doc = in_block!()] = help: have you added the `#[macro_use]` on the module/import? error: cannot find macro `in_root` in this scope - --> $DIR/key-value-expansion-scope.rs:13:14 + --> $DIR/key-value-expansion-scope.rs:19:14 | LL | #![doc = in_root!()] | ^^^^^^^ @@ -55,7 +55,7 @@ LL | #![doc = in_root!()] = help: have you added the `#[macro_use]` on the module/import? error: cannot find macro `in_mod` in this scope - --> $DIR/key-value-expansion-scope.rs:14:14 + --> $DIR/key-value-expansion-scope.rs:21:14 | LL | #![doc = in_mod!()] | ^^^^^^ @@ -63,7 +63,7 @@ LL | #![doc = in_mod!()] = help: have you added the `#[macro_use]` on the module/import? error: cannot find macro `in_mod_escape` in this scope - --> $DIR/key-value-expansion-scope.rs:15:14 + --> $DIR/key-value-expansion-scope.rs:23:14 | LL | #![doc = in_mod_escape!()] | ^^^^^^^^^^^^^ @@ -71,7 +71,7 @@ LL | #![doc = in_mod_escape!()] = help: have you added the `#[macro_use]` on the module/import? error: cannot find macro `in_block` in this scope - --> $DIR/key-value-expansion-scope.rs:16:14 + --> $DIR/key-value-expansion-scope.rs:25:14 | LL | #![doc = in_block!()] | ^^^^^^^^ @@ -79,7 +79,7 @@ LL | #![doc = in_block!()] = help: have you added the `#[macro_use]` on the module/import? error: cannot find macro `in_block` in this scope - --> $DIR/key-value-expansion-scope.rs:50:9 + --> $DIR/key-value-expansion-scope.rs:60:9 | LL | #[doc = in_block!()] | ^^^^^^^^ @@ -87,7 +87,7 @@ LL | #[doc = in_block!()] = help: have you added the `#[macro_use]` on the module/import? error: cannot find macro `in_block` in this scope - --> $DIR/key-value-expansion-scope.rs:52:14 + --> $DIR/key-value-expansion-scope.rs:63:14 | LL | #![doc = in_block!()] | ^^^^^^^^ @@ -95,7 +95,7 @@ LL | #![doc = in_block!()] = help: have you added the `#[macro_use]` on the module/import? error: cannot find macro `in_mod` in this scope - --> $DIR/key-value-expansion-scope.rs:63:9 + --> $DIR/key-value-expansion-scope.rs:75:9 | LL | #[doc = in_mod!()] | ^^^^^^ @@ -103,7 +103,7 @@ LL | #[doc = in_mod!()] = help: have you added the `#[macro_use]` on the module/import? error: cannot find macro `in_block` in this scope - --> $DIR/key-value-expansion-scope.rs:65:9 + --> $DIR/key-value-expansion-scope.rs:78:9 | LL | #[doc = in_block!()] | ^^^^^^^^ @@ -111,7 +111,7 @@ LL | #[doc = in_block!()] = help: have you added the `#[macro_use]` on the module/import? error: cannot find macro `in_mod` in this scope - --> $DIR/key-value-expansion-scope.rs:68:14 + --> $DIR/key-value-expansion-scope.rs:82:14 | LL | #![doc = in_mod!()] | ^^^^^^ @@ -119,7 +119,7 @@ LL | #![doc = in_mod!()] = help: have you added the `#[macro_use]` on the module/import? error: cannot find macro `in_block` in this scope - --> $DIR/key-value-expansion-scope.rs:70:14 + --> $DIR/key-value-expansion-scope.rs:85:14 | LL | #![doc = in_block!()] | ^^^^^^^^ @@ -138,7 +138,7 @@ LL | #![doc = in_root!()] = note: `#[deny(out_of_scope_macro_calls)]` (part of `#[deny(future_incompatible)]`) on by default error: cannot find macro `in_mod_escape` in the current scope when looking from the crate root - --> $DIR/key-value-expansion-scope.rs:4:10 + --> $DIR/key-value-expansion-scope.rs:5:10 | LL | #![doc = in_mod_escape!()] | ^^^^^^^^^^^^^ not found from the crate root @@ -148,7 +148,7 @@ LL | #![doc = in_mod_escape!()] = help: import `macro_rules` with `use` to make it callable above its definition error: cannot find macro `in_mod` in the current scope when looking from module `macros_stay` - --> $DIR/key-value-expansion-scope.rs:21:9 + --> $DIR/key-value-expansion-scope.rs:31:9 | LL | #[doc = in_mod!()] | ^^^^^^ not found from module `macros_stay` @@ -158,7 +158,7 @@ LL | #[doc = in_mod!()] = help: import `macro_rules` with `use` to make it callable above its definition error: cannot find macro `in_mod` in the current scope when looking from module `macros_stay` - --> $DIR/key-value-expansion-scope.rs:24:14 + --> $DIR/key-value-expansion-scope.rs:34:14 | LL | #![doc = in_mod!()] | ^^^^^^ not found from module `macros_stay` @@ -168,7 +168,7 @@ LL | #![doc = in_mod!()] = help: import `macro_rules` with `use` to make it callable above its definition error: cannot find macro `in_mod_escape` in the current scope when looking from module `macros_escape` - --> $DIR/key-value-expansion-scope.rs:36:9 + --> $DIR/key-value-expansion-scope.rs:46:9 | LL | #[doc = in_mod_escape!()] | ^^^^^^^^^^^^^ not found from module `macros_escape` @@ -178,7 +178,7 @@ LL | #[doc = in_mod_escape!()] = help: import `macro_rules` with `use` to make it callable above its definition error: cannot find macro `in_mod_escape` in the current scope when looking from module `macros_escape` - --> $DIR/key-value-expansion-scope.rs:39:14 + --> $DIR/key-value-expansion-scope.rs:49:14 | LL | #![doc = in_mod_escape!()] | ^^^^^^^^^^^^^ not found from module `macros_escape` @@ -187,7 +187,103 @@ LL | #![doc = in_mod_escape!()] = note: for more information, see issue #124535 = help: import `macro_rules` with `use` to make it callable above its definition -error: aborting due to 22 previous errors +error: attribute value must be a literal + --> $DIR/key-value-expansion-scope.rs:3:10 + | +LL | #![doc = in_mod!()] + | ^^^^^^^^^ + +error: attribute value must be a literal + --> $DIR/key-value-expansion-scope.rs:7:10 + | +LL | #![doc = in_block!()] + | ^^^^^^^^^^^ + +error: attribute value must be a literal + --> $DIR/key-value-expansion-scope.rs:10:9 + | +LL | #[doc = in_root!()] + | ^^^^^^^^^^ + +error: attribute value must be a literal + --> $DIR/key-value-expansion-scope.rs:12:9 + | +LL | #[doc = in_mod!()] + | ^^^^^^^^^ + +error: attribute value must be a literal + --> $DIR/key-value-expansion-scope.rs:14:9 + | +LL | #[doc = in_mod_escape!()] + | ^^^^^^^^^^^^^^^^ + +error: attribute value must be a literal + --> $DIR/key-value-expansion-scope.rs:16:9 + | +LL | #[doc = in_block!()] + | ^^^^^^^^^^^ + +error: attribute value must be a literal + --> $DIR/key-value-expansion-scope.rs:19:14 + | +LL | #![doc = in_root!()] + | ^^^^^^^^^^ + +error: attribute value must be a literal + --> $DIR/key-value-expansion-scope.rs:21:14 + | +LL | #![doc = in_mod!()] + | ^^^^^^^^^ + +error: attribute value must be a literal + --> $DIR/key-value-expansion-scope.rs:23:14 + | +LL | #![doc = in_mod_escape!()] + | ^^^^^^^^^^^^^^^^ + +error: attribute value must be a literal + --> $DIR/key-value-expansion-scope.rs:25:14 + | +LL | #![doc = in_block!()] + | ^^^^^^^^^^^ + +error: attribute value must be a literal + --> $DIR/key-value-expansion-scope.rs:60:9 + | +LL | #[doc = in_block!()] + | ^^^^^^^^^^^ + +error: attribute value must be a literal + --> $DIR/key-value-expansion-scope.rs:63:14 + | +LL | #![doc = in_block!()] + | ^^^^^^^^^^^ + +error: attribute value must be a literal + --> $DIR/key-value-expansion-scope.rs:75:9 + | +LL | #[doc = in_mod!()] + | ^^^^^^^^^ + +error: attribute value must be a literal + --> $DIR/key-value-expansion-scope.rs:78:9 + | +LL | #[doc = in_block!()] + | ^^^^^^^^^^^ + +error: attribute value must be a literal + --> $DIR/key-value-expansion-scope.rs:82:14 + | +LL | #![doc = in_mod!()] + | ^^^^^^^^^ + +error: attribute value must be a literal + --> $DIR/key-value-expansion-scope.rs:85:14 + | +LL | #![doc = in_block!()] + | ^^^^^^^^^^^ + +error: aborting due to 38 previous errors Future incompatibility report: Future breakage diagnostic: error: cannot find macro `in_root` in the current scope when looking from the crate root @@ -203,7 +299,7 @@ LL | #![doc = in_root!()] Future breakage diagnostic: error: cannot find macro `in_mod_escape` in the current scope when looking from the crate root - --> $DIR/key-value-expansion-scope.rs:4:10 + --> $DIR/key-value-expansion-scope.rs:5:10 | LL | #![doc = in_mod_escape!()] | ^^^^^^^^^^^^^ not found from the crate root @@ -215,7 +311,7 @@ LL | #![doc = in_mod_escape!()] Future breakage diagnostic: error: cannot find macro `in_mod` in the current scope when looking from module `macros_stay` - --> $DIR/key-value-expansion-scope.rs:21:9 + --> $DIR/key-value-expansion-scope.rs:31:9 | LL | #[doc = in_mod!()] | ^^^^^^ not found from module `macros_stay` @@ -227,7 +323,7 @@ LL | #[doc = in_mod!()] Future breakage diagnostic: error: cannot find macro `in_mod` in the current scope when looking from module `macros_stay` - --> $DIR/key-value-expansion-scope.rs:24:14 + --> $DIR/key-value-expansion-scope.rs:34:14 | LL | #![doc = in_mod!()] | ^^^^^^ not found from module `macros_stay` @@ -239,7 +335,7 @@ LL | #![doc = in_mod!()] Future breakage diagnostic: error: cannot find macro `in_mod_escape` in the current scope when looking from module `macros_escape` - --> $DIR/key-value-expansion-scope.rs:36:9 + --> $DIR/key-value-expansion-scope.rs:46:9 | LL | #[doc = in_mod_escape!()] | ^^^^^^^^^^^^^ not found from module `macros_escape` @@ -251,7 +347,7 @@ LL | #[doc = in_mod_escape!()] Future breakage diagnostic: error: cannot find macro `in_mod_escape` in the current scope when looking from module `macros_escape` - --> $DIR/key-value-expansion-scope.rs:39:14 + --> $DIR/key-value-expansion-scope.rs:49:14 | LL | #![doc = in_mod_escape!()] | ^^^^^^^^^^^^^ not found from module `macros_escape` diff --git a/tests/ui/attributes/key-value-expansion.stderr b/tests/ui/attributes/key-value-expansion.stderr index d785bf978196..54d79c5bebb7 100644 --- a/tests/ui/attributes/key-value-expansion.stderr +++ b/tests/ui/attributes/key-value-expansion.stderr @@ -1,3 +1,9 @@ +error: attribute value must be a literal + --> $DIR/key-value-expansion.rs:21:6 + | +LL | bug!((column!())); + | ^^^^^^^^^^^ + error: attribute value must be a literal --> $DIR/key-value-expansion.rs:27:14 | @@ -20,11 +26,5 @@ LL | some_macro!(u8); | = note: this error originates in the macro `some_macro` (in Nightly builds, run with -Z macro-backtrace for more info) -error: attribute value must be a literal - --> $DIR/key-value-expansion.rs:21:6 - | -LL | bug!((column!())); - | ^^^^^^^^^^^ - error: aborting due to 3 previous errors diff --git a/tests/ui/attributes/malformed-attrs.stderr b/tests/ui/attributes/malformed-attrs.stderr index 0ef62d70a15c..a6bd62fa1214 100644 --- a/tests/ui/attributes/malformed-attrs.stderr +++ b/tests/ui/attributes/malformed-attrs.stderr @@ -182,27 +182,6 @@ LL | #[allow_internal_unsafe = 1] = help: add `#![feature(allow_internal_unsafe)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error: valid forms for the attribute are `#[doc(hidden)]`, `#[doc(inline)]`, and `#[doc = "string"]` - --> $DIR/malformed-attrs.rs:41:1 - | -LL | #[doc] - | ^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #57571 - = note: for more information, visit - = note: `#[deny(ill_formed_attribute_input)]` (part of `#[deny(future_incompatible)]`) on by default - -error: valid forms for the attribute are `#[doc(hidden)]`, `#[doc(inline)]`, and `#[doc = "string"]` - --> $DIR/malformed-attrs.rs:77:1 - | -LL | #[doc] - | ^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #57571 - = note: for more information, visit - error[E0539]: malformed `windows_subsystem` attribute input --> $DIR/malformed-attrs.rs:26:1 | @@ -790,6 +769,16 @@ LL | #[diagnostic::on_unimplemented = 1] | = help: only `message`, `note` and `label` are allowed as options +error: valid forms for the attribute are `#[doc = "string"]`, `#[doc(alias)]`, `#[doc(attribute)]`, `#[doc(auto_cfg)]`, `#[doc(cfg)]`, `#[doc(fake_variadic)]`, `#[doc(hidden)]`, `#[doc(html_favicon_url)]`, `#[doc(html_logo_url)]`, `#[doc(html_no_source)]`, `#[doc(html_playground_url)]`, `#[doc(html_root_url)]`, `#[doc(include)]`, `#[doc(inline)]`, `#[doc(issue_tracker_base_url)]`, `#[doc(keyword)]`, `#[doc(masked)]`, `#[doc(no_default_passes)]`, `#[doc(no_inline)]`, `#[doc(notable_trait)]`, `#[doc(passes)]`, `#[doc(plugins)]`, `#[doc(rust_logo)]`, `#[doc(search_unbox)]`, `#[doc(spotlight)]`, and `#[doc(test)]` + --> $DIR/malformed-attrs.rs:41:1 + | +LL | #[doc] + | ^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #57571 + = note: `#[deny(ill_formed_attribute_input)]` (part of `#[deny(future_incompatible)]`) on by default + error: valid forms for the attribute are `#[inline(always)]`, `#[inline(never)]`, and `#[inline]` --> $DIR/malformed-attrs.rs:52:1 | @@ -814,6 +803,15 @@ LL | | #[coroutine = 63] || {} LL | | } | |_^ +error: valid forms for the attribute are `#[doc = "string"]`, `#[doc(alias)]`, `#[doc(attribute)]`, `#[doc(auto_cfg)]`, `#[doc(cfg)]`, `#[doc(fake_variadic)]`, `#[doc(hidden)]`, `#[doc(html_favicon_url)]`, `#[doc(html_logo_url)]`, `#[doc(html_no_source)]`, `#[doc(html_playground_url)]`, `#[doc(html_root_url)]`, `#[doc(include)]`, `#[doc(inline)]`, `#[doc(issue_tracker_base_url)]`, `#[doc(keyword)]`, `#[doc(masked)]`, `#[doc(no_default_passes)]`, `#[doc(no_inline)]`, `#[doc(notable_trait)]`, `#[doc(passes)]`, `#[doc(plugins)]`, `#[doc(rust_logo)]`, `#[doc(search_unbox)]`, `#[doc(spotlight)]`, and `#[doc(test)]` + --> $DIR/malformed-attrs.rs:77:1 + | +LL | #[doc] + | ^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #57571 + warning: `#[link_name]` attribute cannot be used on functions --> $DIR/malformed-attrs.rs:88:1 | @@ -875,7 +873,7 @@ error: aborting due to 76 previous errors; 8 warnings emitted Some errors have detailed explanations: E0308, E0463, E0539, E0565, E0658, E0805. For more information about an error, try `rustc --explain E0308`. Future incompatibility report: Future breakage diagnostic: -error: valid forms for the attribute are `#[doc(hidden)]`, `#[doc(inline)]`, and `#[doc = "string"]` +error: valid forms for the attribute are `#[doc = "string"]`, `#[doc(alias)]`, `#[doc(attribute)]`, `#[doc(auto_cfg)]`, `#[doc(cfg)]`, `#[doc(fake_variadic)]`, `#[doc(hidden)]`, `#[doc(html_favicon_url)]`, `#[doc(html_logo_url)]`, `#[doc(html_no_source)]`, `#[doc(html_playground_url)]`, `#[doc(html_root_url)]`, `#[doc(include)]`, `#[doc(inline)]`, `#[doc(issue_tracker_base_url)]`, `#[doc(keyword)]`, `#[doc(masked)]`, `#[doc(no_default_passes)]`, `#[doc(no_inline)]`, `#[doc(notable_trait)]`, `#[doc(passes)]`, `#[doc(plugins)]`, `#[doc(rust_logo)]`, `#[doc(search_unbox)]`, `#[doc(spotlight)]`, and `#[doc(test)]` --> $DIR/malformed-attrs.rs:41:1 | LL | #[doc] @@ -883,19 +881,6 @@ LL | #[doc] | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #57571 - = note: for more information, visit - = note: `#[deny(ill_formed_attribute_input)]` (part of `#[deny(future_incompatible)]`) on by default - -Future breakage diagnostic: -error: valid forms for the attribute are `#[doc(hidden)]`, `#[doc(inline)]`, and `#[doc = "string"]` - --> $DIR/malformed-attrs.rs:77:1 - | -LL | #[doc] - | ^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #57571 - = note: for more information, visit = note: `#[deny(ill_formed_attribute_input)]` (part of `#[deny(future_incompatible)]`) on by default Future breakage diagnostic: @@ -909,6 +894,17 @@ LL | #[inline = 5] = note: for more information, see issue #57571 = note: `#[deny(ill_formed_attribute_input)]` (part of `#[deny(future_incompatible)]`) on by default +Future breakage diagnostic: +error: valid forms for the attribute are `#[doc = "string"]`, `#[doc(alias)]`, `#[doc(attribute)]`, `#[doc(auto_cfg)]`, `#[doc(cfg)]`, `#[doc(fake_variadic)]`, `#[doc(hidden)]`, `#[doc(html_favicon_url)]`, `#[doc(html_logo_url)]`, `#[doc(html_no_source)]`, `#[doc(html_playground_url)]`, `#[doc(html_root_url)]`, `#[doc(include)]`, `#[doc(inline)]`, `#[doc(issue_tracker_base_url)]`, `#[doc(keyword)]`, `#[doc(masked)]`, `#[doc(no_default_passes)]`, `#[doc(no_inline)]`, `#[doc(notable_trait)]`, `#[doc(passes)]`, `#[doc(plugins)]`, `#[doc(rust_logo)]`, `#[doc(search_unbox)]`, `#[doc(spotlight)]`, and `#[doc(test)]` + --> $DIR/malformed-attrs.rs:77:1 + | +LL | #[doc] + | ^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #57571 + = note: `#[deny(ill_formed_attribute_input)]` (part of `#[deny(future_incompatible)]`) on by default + Future breakage diagnostic: error: valid forms for the attribute are `#[ignore = "reason"]` and `#[ignore]` --> $DIR/malformed-attrs.rs:98:1 diff --git a/tests/ui/feature-gates/removed-features-note-version-and-pr-issue-141619.stderr b/tests/ui/feature-gates/removed-features-note-version-and-pr-issue-141619.stderr index bd8c56c61c3c..d9556560b01c 100644 --- a/tests/ui/feature-gates/removed-features-note-version-and-pr-issue-141619.stderr +++ b/tests/ui/feature-gates/removed-features-note-version-and-pr-issue-141619.stderr @@ -11,7 +11,7 @@ error: unknown `doc` attribute `include` --> $DIR/removed-features-note-version-and-pr-issue-141619.rs:2:8 | LL | #![doc(include("README.md"))] - | ^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^ | = note: `#[deny(invalid_doc_attributes)]` on by default diff --git a/tests/ui/include-macros/invalid-utf8-binary-file.rs b/tests/ui/include-macros/invalid-utf8-binary-file.rs index 0bbdbac611fd..c733f07c26f0 100644 --- a/tests/ui/include-macros/invalid-utf8-binary-file.rs +++ b/tests/ui/include-macros/invalid-utf8-binary-file.rs @@ -5,6 +5,8 @@ //! Ensure that ICE does not occur when reading an invalid UTF8 file with an absolute path. //! regression test for issue -#![doc = include_str!(concat!(env!("INVALID_UTF8_BIN")))] //~ ERROR: wasn't a utf-8 file +#![doc = include_str!(concat!(env!("INVALID_UTF8_BIN")))] +//~^ ERROR: wasn't a utf-8 file +//~| ERROR: attribute value must be a literal fn main() {} diff --git a/tests/ui/include-macros/invalid-utf8-binary-file.stderr b/tests/ui/include-macros/invalid-utf8-binary-file.stderr index 4ac4def1b00a..232cb5042b72 100644 --- a/tests/ui/include-macros/invalid-utf8-binary-file.stderr +++ b/tests/ui/include-macros/invalid-utf8-binary-file.stderr @@ -6,5 +6,11 @@ LL | #![doc = include_str!(concat!(env!("INVALID_UTF8_BIN")))] | = note: invalid utf-8 at byte `$BYTE` -error: aborting due to 1 previous error +error: attribute value must be a literal + --> $DIR/invalid-utf8-binary-file.rs:8:10 + | +LL | #![doc = include_str!(concat!(env!("INVALID_UTF8_BIN")))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors diff --git a/tests/ui/lint/unused/useless-comment.rs b/tests/ui/lint/unused/useless-comment.rs index 898665278e39..fee6cff640f6 100644 --- a/tests/ui/lint/unused/useless-comment.rs +++ b/tests/ui/lint/unused/useless-comment.rs @@ -1,6 +1,7 @@ #![feature(stmt_expr_attributes)] #![deny(unused_doc_comments)] +#![deny(unused_attributes)] macro_rules! mac { () => {} @@ -15,7 +16,10 @@ unsafe extern "C" { } fn foo() { /// a //~ ERROR unused doc comment - #[doc(test(attr(allow(dead_code))))] //~ ERROR unused doc comment + #[doc(test(attr(allow(dead_code))))] + //~^ ERROR unused doc comment + //~| ERROR `#[doc]` attribute cannot be used on statements + //~| WARN this was previously accepted by the compiler let x = 12; /// multi-line //~ ERROR unused doc comment @@ -24,7 +28,10 @@ fn foo() { match x { /// c //~ ERROR unused doc comment 1 => {}, - #[doc(test(attr(allow(dead_code))))] //~ ERROR unused doc comment + #[doc(test(attr(allow(dead_code))))] + //~^ ERROR unused doc comment + //~| ERROR `#[doc]` attribute cannot be used on match arms [unused_attributes] + //~| WARN this was previously accepted by the compiler _ => {} } @@ -38,7 +45,10 @@ fn foo() { /// bar //~ ERROR unused doc comment mac!(); - #[doc(test(attr(allow(dead_code))))] //~ ERROR unused doc comment + #[doc(test(attr(allow(dead_code))))] + //~^ ERROR unused doc comment + //~| ERROR `#[doc]` attribute cannot be used on statements + //~| WARN this was previously accepted by the compiler let x = /** comment */ 47; //~ ERROR unused doc comment /// dox //~ ERROR unused doc comment diff --git a/tests/ui/lint/unused/useless-comment.stderr b/tests/ui/lint/unused/useless-comment.stderr index 39873b82b757..3d3937e7a402 100644 --- a/tests/ui/lint/unused/useless-comment.stderr +++ b/tests/ui/lint/unused/useless-comment.stderr @@ -1,5 +1,5 @@ error: unused doc comment - --> $DIR/useless-comment.rs:9:1 + --> $DIR/useless-comment.rs:10:1 | LL | /// foo | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ rustdoc does not generate documentation for macro invocations @@ -12,7 +12,7 @@ LL | #![deny(unused_doc_comments)] | ^^^^^^^^^^^^^^^^^^^ error: unused doc comment - --> $DIR/useless-comment.rs:12:1 + --> $DIR/useless-comment.rs:13:1 | LL | /// a | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -23,7 +23,7 @@ LL | unsafe extern "C" { } = help: use `//` for a plain comment error: unused doc comment - --> $DIR/useless-comment.rs:13:1 + --> $DIR/useless-comment.rs:14:1 | LL | #[doc(test(attr(allow(dead_code))))] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -33,7 +33,7 @@ LL | unsafe extern "C" { } = help: use `//` for a plain comment error: unused doc comment - --> $DIR/useless-comment.rs:38:5 + --> $DIR/useless-comment.rs:45:5 | LL | /// bar | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ rustdoc does not generate documentation for macro invocations @@ -41,28 +41,29 @@ LL | /// bar = help: to document an item produced by a macro, the macro must produce the documentation as part of its expansion error: unused doc comment - --> $DIR/useless-comment.rs:17:5 + --> $DIR/useless-comment.rs:18:5 | LL | /// a | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | #[doc(test(attr(allow(dead_code))))] +... LL | let x = 12; | ----------- rustdoc does not generate documentation for statements | = help: use `//` for a plain comment error: unused doc comment - --> $DIR/useless-comment.rs:18:5 + --> $DIR/useless-comment.rs:19:5 | LL | #[doc(test(attr(allow(dead_code))))] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... LL | let x = 12; | ----------- rustdoc does not generate documentation for statements | = help: use `//` for a plain comment error: unused doc comment - --> $DIR/useless-comment.rs:21:5 + --> $DIR/useless-comment.rs:25:5 | LL | / /// multi-line LL | | /// doc comment @@ -72,6 +73,7 @@ LL | / match x { LL | | /// c LL | | 1 => {}, LL | | #[doc(test(attr(allow(dead_code))))] +... | LL | | _ => {} LL | | } | |_____- rustdoc does not generate documentation for expressions @@ -79,7 +81,7 @@ LL | | } = help: use `//` for a plain comment error: unused doc comment - --> $DIR/useless-comment.rs:25:9 + --> $DIR/useless-comment.rs:29:9 | LL | /// c | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -89,17 +91,18 @@ LL | 1 => {}, = help: use `//` for a plain comment error: unused doc comment - --> $DIR/useless-comment.rs:27:9 + --> $DIR/useless-comment.rs:31:9 | LL | #[doc(test(attr(allow(dead_code))))] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... LL | _ => {} | ------- rustdoc does not generate documentation for match arms | = help: use `//` for a plain comment error: unused doc comment - --> $DIR/useless-comment.rs:31:5 + --> $DIR/useless-comment.rs:38:5 | LL | /// foo | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -109,7 +112,7 @@ LL | unsafe {} = help: use `//` for a plain comment error: unused doc comment - --> $DIR/useless-comment.rs:34:5 + --> $DIR/useless-comment.rs:41:5 | LL | #[doc = "foo"] | ^^^^^^^^^^^^^^ @@ -120,7 +123,7 @@ LL | 3; = help: use `//` for a plain comment error: unused doc comment - --> $DIR/useless-comment.rs:35:5 + --> $DIR/useless-comment.rs:42:5 | LL | #[doc = "bar"] | ^^^^^^^^^^^^^^ @@ -130,17 +133,18 @@ LL | 3; = help: use `//` for a plain comment error: unused doc comment - --> $DIR/useless-comment.rs:41:5 + --> $DIR/useless-comment.rs:48:5 | LL | #[doc(test(attr(allow(dead_code))))] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... LL | let x = /** comment */ 47; | -------------------------- rustdoc does not generate documentation for statements | = help: use `//` for a plain comment error: unused doc comment - --> $DIR/useless-comment.rs:42:13 + --> $DIR/useless-comment.rs:52:13 | LL | let x = /** comment */ 47; | ^^^^^^^^^^^^^^ -- rustdoc does not generate documentation for expressions @@ -148,7 +152,7 @@ LL | let x = /** comment */ 47; = help: use `/* */` for a plain comment error: unused doc comment - --> $DIR/useless-comment.rs:44:5 + --> $DIR/useless-comment.rs:54:5 | LL | /// dox | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -159,5 +163,37 @@ LL | | } | = help: use `//` for a plain comment -error: aborting due to 15 previous errors +error: `#[doc]` attribute cannot be used on statements + --> $DIR/useless-comment.rs:19:5 + | +LL | #[doc(test(attr(allow(dead_code))))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = help: `#[doc]` can be applied to associated consts, associated types, constants, crates, data types, enum variants, extern crates, foreign modules, foreign statics, functions, impl blocks, macro defs, modules, statics, struct fields, trait aliases, traits, type aliases, unions, and use statements +note: the lint level is defined here + --> $DIR/useless-comment.rs:4:9 + | +LL | #![deny(unused_attributes)] + | ^^^^^^^^^^^^^^^^^ + +error: `#[doc]` attribute cannot be used on match arms + --> $DIR/useless-comment.rs:31:9 + | +LL | #[doc(test(attr(allow(dead_code))))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = help: `#[doc]` can be applied to associated consts, associated types, constants, crates, data types, enum variants, extern crates, foreign modules, foreign statics, functions, impl blocks, macro defs, modules, statics, struct fields, trait aliases, traits, type aliases, unions, and use statements + +error: `#[doc]` attribute cannot be used on statements + --> $DIR/useless-comment.rs:48:5 + | +LL | #[doc(test(attr(allow(dead_code))))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = help: `#[doc]` can be applied to associated consts, associated types, constants, crates, data types, enum variants, extern crates, foreign modules, foreign statics, functions, impl blocks, macro defs, modules, statics, struct fields, trait aliases, traits, type aliases, unions, and use statements + +error: aborting due to 18 previous errors diff --git a/tests/ui/malformed/malformed-regressions.stderr b/tests/ui/malformed/malformed-regressions.stderr index 181207984877..29734fd84e6b 100644 --- a/tests/ui/malformed/malformed-regressions.stderr +++ b/tests/ui/malformed/malformed-regressions.stderr @@ -1,14 +1,3 @@ -error: valid forms for the attribute are `#[doc(hidden)]`, `#[doc(inline)]`, and `#[doc = "string"]` - --> $DIR/malformed-regressions.rs:1:1 - | -LL | #[doc] - | ^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #57571 - = note: for more information, visit - = note: `#[deny(ill_formed_attribute_input)]` (part of `#[deny(future_incompatible)]`) on by default - error[E0539]: malformed `link` attribute input --> $DIR/malformed-regressions.rs:7:1 | @@ -63,6 +52,16 @@ LL | fn main() {} = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: requested on the command line with `-W unused-attributes` +error: valid forms for the attribute are `#[doc = "string"]`, `#[doc(alias)]`, `#[doc(attribute)]`, `#[doc(auto_cfg)]`, `#[doc(cfg)]`, `#[doc(fake_variadic)]`, `#[doc(hidden)]`, `#[doc(html_favicon_url)]`, `#[doc(html_logo_url)]`, `#[doc(html_no_source)]`, `#[doc(html_playground_url)]`, `#[doc(html_root_url)]`, `#[doc(include)]`, `#[doc(inline)]`, `#[doc(issue_tracker_base_url)]`, `#[doc(keyword)]`, `#[doc(masked)]`, `#[doc(no_default_passes)]`, `#[doc(no_inline)]`, `#[doc(notable_trait)]`, `#[doc(passes)]`, `#[doc(plugins)]`, `#[doc(rust_logo)]`, `#[doc(search_unbox)]`, `#[doc(spotlight)]`, and `#[doc(test)]` + --> $DIR/malformed-regressions.rs:1:1 + | +LL | #[doc] + | ^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #57571 + = note: `#[deny(ill_formed_attribute_input)]` (part of `#[deny(future_incompatible)]`) on by default + error: valid forms for the attribute are `#[ignore = "reason"]` and `#[ignore]` --> $DIR/malformed-regressions.rs:3:1 | @@ -85,7 +84,7 @@ error: aborting due to 5 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0539`. Future incompatibility report: Future breakage diagnostic: -error: valid forms for the attribute are `#[doc(hidden)]`, `#[doc(inline)]`, and `#[doc = "string"]` +error: valid forms for the attribute are `#[doc = "string"]`, `#[doc(alias)]`, `#[doc(attribute)]`, `#[doc(auto_cfg)]`, `#[doc(cfg)]`, `#[doc(fake_variadic)]`, `#[doc(hidden)]`, `#[doc(html_favicon_url)]`, `#[doc(html_logo_url)]`, `#[doc(html_no_source)]`, `#[doc(html_playground_url)]`, `#[doc(html_root_url)]`, `#[doc(include)]`, `#[doc(inline)]`, `#[doc(issue_tracker_base_url)]`, `#[doc(keyword)]`, `#[doc(masked)]`, `#[doc(no_default_passes)]`, `#[doc(no_inline)]`, `#[doc(notable_trait)]`, `#[doc(passes)]`, `#[doc(plugins)]`, `#[doc(rust_logo)]`, `#[doc(search_unbox)]`, `#[doc(spotlight)]`, and `#[doc(test)]` --> $DIR/malformed-regressions.rs:1:1 | LL | #[doc] @@ -93,7 +92,6 @@ LL | #[doc] | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #57571 - = note: for more information, visit = note: `#[deny(ill_formed_attribute_input)]` (part of `#[deny(future_incompatible)]`) on by default Future breakage diagnostic: diff --git a/tests/ui/parser/attribute/attr-unquoted-ident.stderr b/tests/ui/parser/attribute/attr-unquoted-ident.stderr index f1af60dec9bb..00fb539f8a86 100644 --- a/tests/ui/parser/attribute/attr-unquoted-ident.stderr +++ b/tests/ui/parser/attribute/attr-unquoted-ident.stderr @@ -20,19 +20,6 @@ help: surround the identifier with quotation marks to make it into a string lite LL | #[cfg(key="foo bar baz")] | + + -error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found expression - --> $DIR/attr-unquoted-ident.rs:18:15 - | -LL | #[cfg(key=foo 1 bar 2.0 baz.)] - | ^^^ expressions are not allowed here - | -help: surround the identifier with quotation marks to make it into a string literal - | -LL | #[cfg(key="foo 1 bar 2.0 baz.")] - | + + - -error: expected unsuffixed literal, found identifier `nickname` - --> $DIR/attr-unquoted-ident.rs:28:38 | LL | ($name:ident) => { #[doc(alias = $name)] pub struct S; } | ^^^^^ diff --git a/tests/ui/rustdoc/check-doc-alias-attr-location.rs b/tests/ui/rustdoc/check-doc-alias-attr-location.rs index 10609e5d8f4d..8ba6cfde2d6d 100644 --- a/tests/ui/rustdoc/check-doc-alias-attr-location.rs +++ b/tests/ui/rustdoc/check-doc-alias-attr-location.rs @@ -21,11 +21,22 @@ impl Foo for Bar { type X = i32; fn foo(#[doc(alias = "qux")] _x: u32) -> Self::X { //~^ ERROR - #[doc(alias = "stmt")] //~ ERROR + //~| WARN `#[doc]` attribute cannot be used on function params + //~| WARN: this was previously accepted by the compiler + #[doc(alias = "stmt")] + //~^ ERROR + //~| WARN `#[doc]` attribute cannot be used on statements + //~| WARN: this was previously accepted by the compiler let x = 0; - #[doc(alias = "expr")] //~ ERROR + #[doc(alias = "expr")] + //~^ ERROR + //~| WARN `#[doc]` attribute cannot be used on expressions + //~| WARN: this was previously accepted by the compiler match x { - #[doc(alias = "arm")] //~ ERROR + #[doc(alias = "arm")] + //~^ ERROR + //~| WARN `#[doc]` attribute cannot be used on match arms + //~| WARN: this was previously accepted by the compiler _ => 0 } } diff --git a/tests/ui/rustdoc/check-doc-alias-attr-location.stderr b/tests/ui/rustdoc/check-doc-alias-attr-location.stderr index 23c93a4ed8bd..24be42036f6f 100644 --- a/tests/ui/rustdoc/check-doc-alias-attr-location.stderr +++ b/tests/ui/rustdoc/check-doc-alias-attr-location.stderr @@ -5,46 +5,83 @@ LL | fn foo(#[doc(alias = "qux")] _x: u32) -> Self::X { | ^^^^^^^^^^^^^^^^^^^^^ error: `#[doc(alias = "...")]` isn't allowed on foreign module - --> $DIR/check-doc-alias-attr-location.rs:9:7 + --> $DIR/check-doc-alias-attr-location.rs:9:15 | LL | #[doc(alias = "foo")] - | ^^^^^^^^^^^^^ + | ^^^^^ error: `#[doc(alias = "...")]` isn't allowed on implementation block - --> $DIR/check-doc-alias-attr-location.rs:12:7 + --> $DIR/check-doc-alias-attr-location.rs:12:15 | LL | #[doc(alias = "bar")] - | ^^^^^^^^^^^^^ + | ^^^^^ error: `#[doc(alias = "...")]` isn't allowed on implementation block - --> $DIR/check-doc-alias-attr-location.rs:18:7 + --> $DIR/check-doc-alias-attr-location.rs:18:15 | LL | #[doc(alias = "foobar")] - | ^^^^^^^^^^^^^^^^ + | ^^^^^^^^ error: `#[doc(alias = "...")]` isn't allowed on type alias in implementation block - --> $DIR/check-doc-alias-attr-location.rs:20:11 + --> $DIR/check-doc-alias-attr-location.rs:20:19 | LL | #[doc(alias = "assoc")] - | ^^^^^^^^^^^^^^^ + | ^^^^^^^ error: `#[doc(alias = "...")]` isn't allowed on statement - --> $DIR/check-doc-alias-attr-location.rs:24:15 + --> $DIR/check-doc-alias-attr-location.rs:26:23 | LL | #[doc(alias = "stmt")] - | ^^^^^^^^^^^^^^ + | ^^^^^^ error: `#[doc(alias = "...")]` isn't allowed on expression - --> $DIR/check-doc-alias-attr-location.rs:26:15 + --> $DIR/check-doc-alias-attr-location.rs:31:23 | LL | #[doc(alias = "expr")] - | ^^^^^^^^^^^^^^ + | ^^^^^^ error: `#[doc(alias = "...")]` isn't allowed on match arm - --> $DIR/check-doc-alias-attr-location.rs:28:19 + --> $DIR/check-doc-alias-attr-location.rs:36:27 | LL | #[doc(alias = "arm")] - | ^^^^^^^^^^^^^ + | ^^^^^ -error: aborting due to 8 previous errors +warning: `#[doc]` attribute cannot be used on function params + --> $DIR/check-doc-alias-attr-location.rs:22:12 + | +LL | fn foo(#[doc(alias = "qux")] _x: u32) -> Self::X { + | ^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = help: `#[doc]` can be applied to associated consts, associated types, constants, crates, data types, enum variants, extern crates, foreign modules, foreign statics, functions, impl blocks, macro defs, modules, statics, struct fields, trait aliases, traits, type aliases, unions, and use statements + = note: requested on the command line with `-W unused-attributes` + +warning: `#[doc]` attribute cannot be used on statements + --> $DIR/check-doc-alias-attr-location.rs:26:9 + | +LL | #[doc(alias = "stmt")] + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = help: `#[doc]` can be applied to associated consts, associated types, constants, crates, data types, enum variants, extern crates, foreign modules, foreign statics, functions, impl blocks, macro defs, modules, statics, struct fields, trait aliases, traits, type aliases, unions, and use statements + +warning: `#[doc]` attribute cannot be used on expressions + --> $DIR/check-doc-alias-attr-location.rs:31:9 + | +LL | #[doc(alias = "expr")] + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = help: `#[doc]` can be applied to associated consts, associated types, constants, crates, data types, enum variants, extern crates, foreign modules, foreign statics, functions, impl blocks, macro defs, modules, statics, struct fields, trait aliases, traits, type aliases, unions, and use statements + +warning: `#[doc]` attribute cannot be used on match arms + --> $DIR/check-doc-alias-attr-location.rs:36:13 + | +LL | #[doc(alias = "arm")] + | ^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = help: `#[doc]` can be applied to associated consts, associated types, constants, crates, data types, enum variants, extern crates, foreign modules, foreign statics, functions, impl blocks, macro defs, modules, statics, struct fields, trait aliases, traits, type aliases, unions, and use statements + +error: aborting due to 8 previous errors; 4 warnings emitted diff --git a/tests/ui/rustdoc/check-doc-alias-attr.stderr b/tests/ui/rustdoc/check-doc-alias-attr.stderr index 250568be3333..6c33f10e8785 100644 --- a/tests/ui/rustdoc/check-doc-alias-attr.stderr +++ b/tests/ui/rustdoc/check-doc-alias-attr.stderr @@ -4,11 +4,29 @@ error: doc alias attribute expects a string `#[doc(alias = "a")]` or a list of s LL | #[doc(alias)] | ^^^^^ -error: doc alias attribute expects a string `#[doc(alias = "a")]` or a list of strings `#[doc(alias("a", "b"))]` - --> $DIR/check-doc-alias-attr.rs:8:7 +error[E0539]: malformed `doc` attribute input + --> $DIR/check-doc-alias-attr.rs:8:1 | LL | #[doc(alias = 0)] - | ^^^^^^^^^ + | ^^^^^^^^^^^^^^-^^ + | | + | expected a string literal here + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #[doc(alias = 0)] +LL + #[doc = "string"] + | +LL - #[doc(alias = 0)] +LL + #[doc(alias)] + | +LL - #[doc(alias = 0)] +LL + #[doc(attribute)] + | +LL - #[doc(alias = 0)] +LL + #[doc(auto_cfg)] + | + = and 22 other candidates error: '"' character isn't allowed in `#[doc(alias = "...")]` --> $DIR/check-doc-alias-attr.rs:9:15 @@ -54,25 +72,43 @@ error: `#[doc(alias = "...")]` attribute cannot have empty value LL | #[doc(alias = "")] | ^^ -error: `#[doc(alias("a"))]` expects string literals - --> $DIR/check-doc-alias-attr.rs:19:13 +error[E0539]: malformed `doc` attribute input + --> $DIR/check-doc-alias-attr.rs:19:1 | LL | #[doc(alias(0))] - | ^ + | ^^^^^^^^^^^^-^^^ + | | + | expected a string literal here + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #[doc(alias(0))] +LL + #[doc = "string"] + | +LL - #[doc(alias(0))] +LL + #[doc(alias)] + | +LL - #[doc(alias(0))] +LL + #[doc(attribute)] + | +LL - #[doc(alias(0))] +LL + #[doc(auto_cfg)] + | + = and 22 other candidates -error: '"' character isn't allowed in `#[doc(alias("..."))]` +error: '"' character isn't allowed in `#[doc(alias = "...")]` --> $DIR/check-doc-alias-attr.rs:20:13 | LL | #[doc(alias("\""))] | ^^^^ -error: '\n' character isn't allowed in `#[doc(alias("..."))]` +error: '\n' character isn't allowed in `#[doc(alias = "...")]` --> $DIR/check-doc-alias-attr.rs:21:13 | LL | #[doc(alias("\n"))] | ^^^^ -error: '\n' character isn't allowed in `#[doc(alias("..."))]` +error: '\n' character isn't allowed in `#[doc(alias = "...")]` --> $DIR/check-doc-alias-attr.rs:22:13 | LL | #[doc(alias(" @@ -80,25 +116,25 @@ LL | #[doc(alias(" LL | | "))] | |_^ -error: '\t' character isn't allowed in `#[doc(alias("..."))]` +error: '\t' character isn't allowed in `#[doc(alias = "...")]` --> $DIR/check-doc-alias-attr.rs:24:13 | LL | #[doc(alias("\t"))] | ^^^^ -error: `#[doc(alias("..."))]` cannot start or end with ' ' +error: `#[doc(alias = "...")]` cannot start or end with ' ' --> $DIR/check-doc-alias-attr.rs:25:13 | LL | #[doc(alias(" hello"))] | ^^^^^^^^ -error: `#[doc(alias("..."))]` cannot start or end with ' ' +error: `#[doc(alias = "...")]` cannot start or end with ' ' --> $DIR/check-doc-alias-attr.rs:26:13 | LL | #[doc(alias("hello "))] | ^^^^^^^^ -error: `#[doc(alias("..."))]` attribute cannot have empty value +error: `#[doc(alias = "...")]` attribute cannot have empty value --> $DIR/check-doc-alias-attr.rs:27:13 | LL | #[doc(alias(""))] @@ -106,3 +142,4 @@ LL | #[doc(alias(""))] error: aborting due to 17 previous errors +For more information about this error, try `rustc --explain E0539`. diff --git a/tests/ui/rustdoc/doc-alias-crate-level.stderr b/tests/ui/rustdoc/doc-alias-crate-level.stderr index bd32609ade29..a40e31714f14 100644 --- a/tests/ui/rustdoc/doc-alias-crate-level.stderr +++ b/tests/ui/rustdoc/doc-alias-crate-level.stderr @@ -5,10 +5,10 @@ LL | #[doc(alias = "shouldn't work!")] | ^^^^^^^^^^^^^^^^^ error: `#![doc(alias = "...")]` isn't allowed as a crate-level attribute - --> $DIR/doc-alias-crate-level.rs:5:8 + --> $DIR/doc-alias-crate-level.rs:5:16 | LL | #![doc(alias = "not working!")] - | ^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/tests/ui/rustdoc/doc-alias-same-name.stderr b/tests/ui/rustdoc/doc-alias-same-name.stderr index a9da75c0171c..a76ff5ee0b67 100644 --- a/tests/ui/rustdoc/doc-alias-same-name.stderr +++ b/tests/ui/rustdoc/doc-alias-same-name.stderr @@ -1,8 +1,8 @@ -error: `#[doc(alias = "...")]` is the same as the item's name - --> $DIR/doc-alias-same-name.rs:3:7 +error: `#[doc(alias = "Foo"]` is the same as the item's name + --> $DIR/doc-alias-same-name.rs:3:15 | LL | #[doc(alias = "Foo")] - | ^^^^^^^^^^^^^ + | ^^^^^ error: aborting due to 1 previous error diff --git a/tests/ui/rustdoc/doc-primitive.stderr b/tests/ui/rustdoc/doc-primitive.stderr index 8f6f330b3e5d..4ba310ca2410 100644 --- a/tests/ui/rustdoc/doc-primitive.stderr +++ b/tests/ui/rustdoc/doc-primitive.stderr @@ -2,7 +2,7 @@ error: unknown `doc` attribute `primitive` --> $DIR/doc-primitive.rs:3:7 | LL | #[doc(primitive = "foo")] - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^ | note: the lint level is defined here --> $DIR/doc-primitive.rs:1:9 diff --git a/tests/ui/rustdoc/doc-test-attr.stderr b/tests/ui/rustdoc/doc-test-attr.stderr index 51672314a431..1a4b5e45142a 100644 --- a/tests/ui/rustdoc/doc-test-attr.stderr +++ b/tests/ui/rustdoc/doc-test-attr.stderr @@ -11,10 +11,10 @@ LL | #![deny(invalid_doc_attributes)] | ^^^^^^^^^^^^^^^^^^^^^^ error: `#[doc(test(...)]` takes a list of attributes - --> $DIR/doc-test-attr.rs:6:8 + --> $DIR/doc-test-attr.rs:6:13 | LL | #![doc(test = "hello")] - | ^^^^^^^^^^^^^^ + | ^^^^^^^^^ error: unknown `doc(test)` attribute `a` --> $DIR/doc-test-attr.rs:8:13 diff --git a/tests/ui/rustdoc/doc_keyword.rs b/tests/ui/rustdoc/doc_keyword.rs index e0995f336da3..abf06d7a7866 100644 --- a/tests/ui/rustdoc/doc_keyword.rs +++ b/tests/ui/rustdoc/doc_keyword.rs @@ -1,14 +1,14 @@ #![crate_type = "lib"] #![feature(rustdoc_internals)] -#![doc(keyword = "hello")] +#![doc(keyword = "match")] //~^ ERROR `#![doc(keyword = "...")]` isn't allowed as a crate-level attribute -#[doc(keyword = "hell")] //~ ERROR `#[doc(keyword = "...")]` should be used on empty modules +#[doc(keyword = "match")] //~ ERROR `#[doc(keyword = "...")]` should be used on empty modules mod foo { fn hell() {} } -#[doc(keyword = "hall")] //~ ERROR `#[doc(keyword = "...")]` should be used on modules +#[doc(keyword = "match")] //~ ERROR `#[doc(keyword = "...")]` should be used on modules fn foo() {} diff --git a/tests/ui/rustdoc/doc_keyword.stderr b/tests/ui/rustdoc/doc_keyword.stderr index 584daae2f1aa..56da4b00724a 100644 --- a/tests/ui/rustdoc/doc_keyword.stderr +++ b/tests/ui/rustdoc/doc_keyword.stderr @@ -1,15 +1,3 @@ -error: `#[doc(keyword = "...")]` should be used on empty modules - --> $DIR/doc_keyword.rs:6:7 - | -LL | #[doc(keyword = "hell")] - | ^^^^^^^^^^^^^^^^ - -error: `#[doc(keyword = "...")]` should be used on modules - --> $DIR/doc_keyword.rs:11:7 - | -LL | #[doc(keyword = "hall")] - | ^^^^^^^^^^^^^^^^ - error: nonexistent keyword `tadam` used in `#[doc(keyword = "...")]` --> $DIR/doc_keyword.rs:22:17 | @@ -18,17 +6,29 @@ LL | #[doc(keyword = "tadam")] | = help: only existing keywords are allowed in core/std +error: `#[doc(keyword = "...")]` should be used on empty modules + --> $DIR/doc_keyword.rs:6:7 + | +LL | #[doc(keyword = "match")] + | ^^^^^^^ + +error: `#[doc(keyword = "...")]` should be used on modules + --> $DIR/doc_keyword.rs:11:7 + | +LL | #[doc(keyword = "match")] + | ^^^^^^^ + error: `#[doc(keyword = "...")]` should be used on modules --> $DIR/doc_keyword.rs:17:11 | LL | #[doc(keyword = "match")] - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^ error: `#![doc(keyword = "...")]` isn't allowed as a crate-level attribute --> $DIR/doc_keyword.rs:4:8 | -LL | #![doc(keyword = "hello")] - | ^^^^^^^^^^^^^^^^^ +LL | #![doc(keyword = "match")] + | ^^^^^^^ error: aborting due to 5 previous errors diff --git a/tests/ui/rustdoc/duplicate_doc_alias.stderr b/tests/ui/rustdoc/duplicate_doc_alias.stderr index 4b2dd1f8eb68..eba48ca599b0 100644 --- a/tests/ui/rustdoc/duplicate_doc_alias.stderr +++ b/tests/ui/rustdoc/duplicate_doc_alias.stderr @@ -1,10 +1,10 @@ error: doc alias is duplicated - --> $DIR/duplicate_doc_alias.rs:4:7 + --> $DIR/duplicate_doc_alias.rs:4:15 | LL | #[doc(alias = "A")] - | ----------- first defined here + | --- first defined here LL | #[doc(alias = "A")] - | ^^^^^^^^^^^ + | ^^^ | note: the lint level is defined here --> $DIR/duplicate_doc_alias.rs:1:9 @@ -16,7 +16,7 @@ error: doc alias is duplicated --> $DIR/duplicate_doc_alias.rs:6:13 | LL | #[doc(alias = "B")] - | ----------- first defined here + | --- first defined here LL | #[doc(alias("B"))] | ^^^ From 348d9d98e07753c2adb0a303bc3855e0843efbcb Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 5 Dec 2025 22:54:56 +0100 Subject: [PATCH 25/64] Correctly iterate doc comments in intra-doc resolution in `rustc_resolve` --- compiler/rustc_ast/src/attr/mod.rs | 16 ++++++++++++++++ compiler/rustc_hir/src/hir.rs | 4 ++++ compiler/rustc_resolve/src/rustdoc.rs | 10 +--------- tests/rustdoc/doc-on-keyword.rs | 13 +++++++++++++ 4 files changed, 34 insertions(+), 9 deletions(-) create mode 100644 tests/rustdoc/doc-on-keyword.rs diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index 94e7462d26df..a5e630a09afe 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -233,6 +233,19 @@ impl AttributeExt for Attribute { self.has_name(sym::doc) && self.meta_item_list().is_some_and(|l| list_contains_name(&l, sym::hidden)) } + + fn is_doc_keyword_or_attribute(&self) -> bool { + if self.has_name(sym::doc) + && let Some(items) = self.meta_item_list() + { + for item in items { + if item.has_name(sym::keyword) || item.has_name(sym::attribute) { + return true; + } + } + } + false + } } impl Attribute { @@ -865,6 +878,9 @@ pub trait AttributeExt: Debug { /// Returns `true` if this attribute contains `doc(hidden)`. fn is_doc_hidden(&self) -> bool; + + /// Returns `true` is this attribute contains `doc(keyword)` or `doc(attribute)`. + fn is_doc_keyword_or_attribute(&self) -> bool; } // FIXME(fn_delegation): use function delegation instead of manually forwarding diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index afa1a33fe769..f5470adb87e0 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1418,6 +1418,10 @@ impl AttributeExt for Attribute { fn is_doc_hidden(&self) -> bool { matches!(self, Attribute::Parsed(AttributeKind::Doc(d)) if d.hidden.is_some()) } + + fn is_doc_keyword_or_attribute(&self) -> bool { + matches!(self, Attribute::Parsed(AttributeKind::Doc(d)) if d.attribute.is_some() || d.keyword.is_some()) + } } // FIXME(fn_delegation): use function delegation instead of manually forwarding diff --git a/compiler/rustc_resolve/src/rustdoc.rs b/compiler/rustc_resolve/src/rustdoc.rs index 0ac8e68ad968..7f7c423acb40 100644 --- a/compiler/rustc_resolve/src/rustdoc.rs +++ b/compiler/rustc_resolve/src/rustdoc.rs @@ -367,16 +367,8 @@ pub fn inner_docs(attrs: &[impl AttributeExt]) -> bool { /// Has `#[rustc_doc_primitive]` or `#[doc(keyword)]` or `#[doc(attribute)]`. pub fn has_primitive_or_keyword_or_attribute_docs(attrs: &[impl AttributeExt]) -> bool { for attr in attrs { - if attr.has_name(sym::rustc_doc_primitive) { + if attr.has_name(sym::rustc_doc_primitive) || attr.is_doc_keyword_or_attribute() { return true; - } else if attr.has_name(sym::doc) - && let Some(items) = attr.meta_item_list() - { - for item in items { - if item.has_name(sym::keyword) || item.has_name(sym::attribute) { - return true; - } - } } } false diff --git a/tests/rustdoc/doc-on-keyword.rs b/tests/rustdoc/doc-on-keyword.rs new file mode 100644 index 000000000000..0c62eda60a6b --- /dev/null +++ b/tests/rustdoc/doc-on-keyword.rs @@ -0,0 +1,13 @@ +// While working on , the +// intra doc links on keyword/attribute items were not processed. + +#![feature(rustdoc_internals)] +#![crate_name = "foo"] + +//@ has 'foo/keyword.trait.html' +//@ has - '//a[@href="{{channel}}/core/marker/trait.Send.html"]' 'Send' +//@ has - '//a[@href="{{channel}}/core/marker/trait.Sync.html"]' 'Sync' +#[doc(keyword = "trait")] +// +/// [`Send`] and [Sync] +mod bar {} From 8d4f59bed7af3c8be61f1b96c5bbb25dc4d5b3a8 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 5 Dec 2025 23:13:09 +0100 Subject: [PATCH 26/64] Clean up code --- compiler/rustc_attr_parsing/src/attributes/doc.rs | 6 ++---- compiler/rustc_attr_parsing/src/context.rs | 1 - compiler/rustc_attr_parsing/src/lib.rs | 4 ++-- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/doc.rs b/compiler/rustc_attr_parsing/src/attributes/doc.rs index 83a6c4fc44d9..4c0a7a19e5b8 100644 --- a/compiler/rustc_attr_parsing/src/attributes/doc.rs +++ b/compiler/rustc_attr_parsing/src/attributes/doc.rs @@ -1,6 +1,3 @@ -// FIXME: to be removed -#![allow(unused_imports)] - use rustc_ast::ast::{AttrStyle, LitKind, MetaItemLit}; use rustc_feature::template; use rustc_hir::attrs::{ @@ -13,7 +10,6 @@ use thin_vec::ThinVec; use super::prelude::{Allow, AllowedTargets, Error, MethodKind, Target}; use super::{AcceptMapping, AttributeParser}; use crate::context::{AcceptContext, FinalizeContext, Stage}; -use crate::fluent_generated as fluent; use crate::parser::{ArgParser, MetaItemOrLitParser, MetaItemParser, PathParser}; use crate::session_diagnostics::{ DocAliasBadChar, DocAliasEmpty, DocAliasMalformed, DocAliasStartEnd, DocAttributeNotAttribute, @@ -355,6 +351,8 @@ impl DocParser { // FIXME: It's errorring when the attribute is passed multiple times on the command // line. + // The right fix for this would be to only check this rule if the attribute is + // not set on the command line but directly in the code. // if self.attribute.$ident.is_some() { // cx.duplicate_key(path.span(), path.word_sym().unwrap()); // return; diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 5d15588033fd..f41ea3708788 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -165,7 +165,6 @@ attribute_parsers!( ConstStabilityParser, DocParser, MacroUseParser, - NakedParser, StabilityParser, UsedParser, diff --git a/compiler/rustc_attr_parsing/src/lib.rs b/compiler/rustc_attr_parsing/src/lib.rs index 3e9d8087a192..cb02bb9d501f 100644 --- a/compiler/rustc_attr_parsing/src/lib.rs +++ b/compiler/rustc_attr_parsing/src/lib.rs @@ -78,10 +78,10 @@ // tidy-alphabetical-start #![feature(decl_macro)] -#![recursion_limit = "256"] -// tidy-alphabetical-end #![feature(if_let_guard)] #![feature(iter_intersperse)] +#![recursion_limit = "256"] +// tidy-alphabetical-end #[macro_use] /// All the individual attribute parsers for each of rustc's built-in attributes. From 2340f8054c7a97c44bcee69eb314c56667e337a0 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 6 Dec 2025 21:29:35 +0100 Subject: [PATCH 27/64] Update to new lint API --- compiler/rustc_attr_parsing/messages.ftl | 65 -------------- .../rustc_attr_parsing/src/attributes/doc.rs | 73 ++++++++++++--- .../src/session_diagnostics.rs | 88 ------------------- compiler/rustc_hir/src/lints.rs | 70 +-------------- compiler/rustc_lint/messages.ftl | 52 +++++++++++ compiler/rustc_lint/src/early/diagnostics.rs | 50 +++++++++++ compiler/rustc_lint/src/lints.rs | 88 +++++++++++++++++++ compiler/rustc_lint_defs/src/lib.rs | 35 ++++++++ src/librustdoc/lib.rs | 14 ++- 9 files changed, 301 insertions(+), 234 deletions(-) diff --git a/compiler/rustc_attr_parsing/messages.ftl b/compiler/rustc_attr_parsing/messages.ftl index 2a98b87e7a7e..f2642838b3c8 100644 --- a/compiler/rustc_attr_parsing/messages.ftl +++ b/compiler/rustc_attr_parsing/messages.ftl @@ -17,9 +17,6 @@ attr_parsing_deprecated_item_suggestion = attr_parsing_doc_alias_bad_char = {$char_} character isn't allowed in {$attr_str} -attr_parsing_doc_alias_duplicated = doc alias is duplicated - .label = first defined here - attr_parsing_doc_alias_empty = {$attr_str} attribute cannot have empty value @@ -33,69 +30,10 @@ attr_parsing_doc_attribute_not_attribute = nonexistent builtin attribute `{$attribute}` used in `#[doc(attribute = "...")]` .help = only existing builtin attributes are allowed in core/std -attr_parsing_doc_auto_cfg_expects_hide_or_show = - only `hide` or `show` are allowed in `#[doc(auto_cfg(...))]` - -attr_parsing_doc_auto_cfg_hide_show_expects_list = - `#![doc(auto_cfg({$attr_name}(...)))]` expects a list of items - -attr_parsing_doc_auto_cfg_hide_show_unexpected_item = - `#![doc(auto_cfg({$attr_name}(...)))]` only accepts identifiers or key/value items - -attr_parsing_doc_auto_cfg_wrong_literal = - expected boolean for `#[doc(auto_cfg = ...)]` - -attr_parsing_doc_invalid = - invalid `doc` attribute - attr_parsing_doc_keyword_not_keyword = nonexistent keyword `{$keyword}` used in `#[doc(keyword = "...")]` .help = only existing keywords are allowed in core/std -attr_parsing_doc_test_literal = `#![doc(test(...)]` does not take a literal - -attr_parsing_doc_test_takes_list = - `#[doc(test(...)]` takes a list of attributes - -attr_parsing_doc_test_unknown = - unknown `doc(test)` attribute `{$name}` - -attr_parsing_doc_unknown_any = - unknown `doc` attribute `{$name}` - -attr_parsing_doc_unknown_include = - unknown `doc` attribute `include` - .suggestion = use `doc = include_str!` instead - -attr_parsing_doc_unknown_passes = - unknown `doc` attribute `{$name}` - .note = `doc` attribute `{$name}` no longer functions; see issue #44136 - .label = no longer functions - .no_op_note = `doc({$name})` is now a no-op - -attr_parsing_doc_unknown_plugins = - unknown `doc` attribute `plugins` - .note = `doc` attribute `plugins` no longer functions; see issue #44136 and CVE-2018-1000622 - .label = no longer functions - .no_op_note = `doc(plugins)` is now a no-op - -attr_parsing_doc_unknown_spotlight = - unknown `doc` attribute `spotlight` - .note = `doc(spotlight)` was renamed to `doc(notable_trait)` - .suggestion = use `notable_trait` instead - .no_op_note = `doc(spotlight)` is now a no-op - -attr_parsing_empty_attribute = - unused attribute - .suggestion = {$valid_without_list -> - [true] remove these parentheses - *[other] remove this attribute - } - .note = {$valid_without_list -> - [true] using `{$attr_path}` with an empty list is equivalent to not using a list at all - *[other] using `{$attr_path}` with an empty list has no effect - } - attr_parsing_empty_confusables = expected at least one confusable name @@ -317,8 +255,5 @@ attr_parsing_unused_multiple = .suggestion = remove this attribute .note = attribute also specified here -attr_parsing_doc_alias_duplicated = doc alias is duplicated - .label = first defined here - attr_parsing_whole_archive_needs_static = linking modifier `whole-archive` is only compatible with `static` linking kind diff --git a/compiler/rustc_attr_parsing/src/attributes/doc.rs b/compiler/rustc_attr_parsing/src/attributes/doc.rs index 4c0a7a19e5b8..5714d33e861f 100644 --- a/compiler/rustc_attr_parsing/src/attributes/doc.rs +++ b/compiler/rustc_attr_parsing/src/attributes/doc.rs @@ -116,10 +116,18 @@ impl DocParser { } } Some(name) => { - cx.emit_lint(AttributeLintKind::DocTestUnknown { name }, path.span()); + cx.emit_lint( + rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES, + AttributeLintKind::DocTestUnknown { name }, + path.span(), + ); } None => { - cx.emit_lint(AttributeLintKind::DocTestLiteral, path.span()); + cx.emit_lint( + rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES, + AttributeLintKind::DocTestLiteral, + path.span(), + ); } } } @@ -151,7 +159,11 @@ impl DocParser { } if let Some(first_definition) = self.attribute.aliases.get(&alias).copied() { - cx.emit_lint(AttributeLintKind::DuplicateDocAlias { first_definition }, span); + cx.emit_lint( + rustc_session::lint::builtin::UNUSED_ATTRIBUTES, + AttributeLintKind::DuplicateDocAlias { first_definition }, + span, + ); } self.attribute.aliases.insert(alias, span); @@ -239,7 +251,11 @@ impl DocParser { ArgParser::List(list) => { for meta in list.mixed() { let MetaItemOrLitParser::MetaItemParser(item) = meta else { - cx.emit_lint(AttributeLintKind::DocAutoCfgExpectsHideOrShow, meta.span()); + cx.emit_lint( + rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES, + AttributeLintKind::DocAutoCfgExpectsHideOrShow, + meta.span(), + ); continue; }; let (kind, attr_name) = match item.path().word_sym() { @@ -247,6 +263,7 @@ impl DocParser { Some(sym::show) => (HideOrShow::Show, sym::show), _ => { cx.emit_lint( + rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES, AttributeLintKind::DocAutoCfgExpectsHideOrShow, item.span(), ); @@ -255,6 +272,7 @@ impl DocParser { }; let ArgParser::List(list) = item.args() else { cx.emit_lint( + rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES, AttributeLintKind::DocAutoCfgHideShowExpectsList { attr_name }, item.span(), ); @@ -266,6 +284,7 @@ impl DocParser { for item in list.mixed() { let MetaItemOrLitParser::MetaItemParser(sub_item) = item else { cx.emit_lint( + rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES, AttributeLintKind::DocAutoCfgHideShowUnexpectedItem { attr_name }, item.span(), ); @@ -291,6 +310,7 @@ impl DocParser { } _ => { cx.emit_lint( + rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES, AttributeLintKind::DocAutoCfgHideShowUnexpectedItem { attr_name, }, @@ -306,7 +326,11 @@ impl DocParser { ArgParser::NameValue(nv) => { let MetaItemLit { kind: LitKind::Bool(bool_value), span, .. } = nv.value_as_lit() else { - cx.emit_lint(AttributeLintKind::DocAutoCfgWrongLiteral, nv.value_span); + cx.emit_lint( + rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES, + AttributeLintKind::DocAutoCfgWrongLiteral, + nv.value_span, + ); return; }; self.attribute.auto_cfg_change.push((*bool_value, *span)); @@ -397,6 +421,7 @@ impl DocParser { Some(sym::test) => { let Some(list) = args.list() else { cx.emit_lint( + rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES, AttributeLintKind::DocTestTakesList, args.span().unwrap_or(path.span()), ); @@ -418,7 +443,11 @@ impl DocParser { } } Some(sym::spotlight) => { - cx.emit_lint(AttributeLintKind::DocUnknownSpotlight, path.span()); + cx.emit_lint( + rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES, + AttributeLintKind::DocUnknownSpotlight { span: path.span() }, + path.span(), + ); } Some(sym::include) if let Some(nv) = args.name_value() => { let inner = match cx.attr_style { @@ -426,23 +455,41 @@ impl DocParser { AttrStyle::Inner => "!", }; cx.emit_lint( - AttributeLintKind::DocUnknownInclude { inner, value: nv.value_as_lit().symbol }, + rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES, + AttributeLintKind::DocUnknownInclude { + inner, + value: nv.value_as_lit().symbol, + span: path.span(), + }, path.span(), ); } Some(name @ (sym::passes | sym::no_default_passes)) => { - cx.emit_lint(AttributeLintKind::DocUnknownPasses { name }, path.span()); + cx.emit_lint( + rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES, + AttributeLintKind::DocUnknownPasses { name, span: path.span() }, + path.span(), + ); } Some(sym::plugins) => { - cx.emit_lint(AttributeLintKind::DocUnknownPlugins, path.span()); + cx.emit_lint( + rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES, + AttributeLintKind::DocUnknownPlugins { span: path.span() }, + path.span(), + ); } Some(name) => { - cx.emit_lint(AttributeLintKind::DocUnknownAny { name }, path.span()); + cx.emit_lint( + rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES, + AttributeLintKind::DocUnknownAny { name }, + path.span(), + ); } None => { let full_name = path.segments().map(|s| s.as_str()).intersperse("::").collect::(); cx.emit_lint( + rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES, AttributeLintKind::DocUnknownAny { name: Symbol::intern(&full_name) }, path.span(), ); @@ -459,7 +506,11 @@ impl DocParser { ArgParser::NoArgs => { let suggestions = cx.suggestions(); let span = cx.attr_span; - cx.emit_lint(AttributeLintKind::IllFormedAttributeInput { suggestions }, span); + cx.emit_lint( + rustc_session::lint::builtin::ILL_FORMED_ATTRIBUTE_INPUT, + AttributeLintKind::IllFormedAttributeInput { suggestions, docs: None }, + span, + ); } ArgParser::List(items) => { for i in items.mixed() { diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index 38ae597000d2..092bf67249f2 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -581,13 +581,6 @@ pub(crate) struct NakedFunctionIncompatibleAttribute { pub attr: String, } -#[derive(LintDiagnostic)] -#[diag(attr_parsing_doc_alias_duplicated)] -pub(crate) struct DocAliasDuplicated { - #[label] - pub first_defn: Span, -} - #[derive(Diagnostic)] #[diag(attr_parsing_link_ordinal_out_of_range)] #[note] @@ -995,87 +988,6 @@ pub(crate) struct CfgAttrBadDelim { pub sugg: MetaBadDelimSugg, } -#[derive(LintDiagnostic)] -#[diag(attr_parsing_doc_auto_cfg_expects_hide_or_show)] -pub(crate) struct DocAutoCfgExpectsHideOrShow; - -#[derive(LintDiagnostic)] -#[diag(attr_parsing_doc_auto_cfg_hide_show_unexpected_item)] -pub(crate) struct DocAutoCfgHideShowUnexpectedItem { - pub attr_name: Symbol, -} - -#[derive(LintDiagnostic)] -#[diag(attr_parsing_doc_auto_cfg_hide_show_expects_list)] -pub(crate) struct DocAutoCfgHideShowExpectsList { - pub attr_name: Symbol, -} - -#[derive(LintDiagnostic)] -#[diag(attr_parsing_doc_invalid)] -pub(crate) struct DocInvalid; - -#[derive(LintDiagnostic)] -#[diag(attr_parsing_doc_unknown_include)] -pub(crate) struct DocUnknownInclude { - pub inner: &'static str, - pub value: Symbol, - #[suggestion(code = "#{inner}[doc = include_str!(\"{value}\")]")] - pub sugg: (Span, Applicability), -} - -#[derive(LintDiagnostic)] -#[diag(attr_parsing_doc_unknown_spotlight)] -#[note] -#[note(attr_parsing_no_op_note)] -pub(crate) struct DocUnknownSpotlight { - #[suggestion(style = "short", applicability = "machine-applicable", code = "notable_trait")] - pub sugg_span: Span, -} - -#[derive(LintDiagnostic)] -#[diag(attr_parsing_doc_unknown_passes)] -#[note] -#[note(attr_parsing_no_op_note)] -pub(crate) struct DocUnknownPasses { - pub name: Symbol, - #[label] - pub note_span: Span, -} - -#[derive(LintDiagnostic)] -#[diag(attr_parsing_doc_unknown_plugins)] -#[note] -#[note(attr_parsing_no_op_note)] -pub(crate) struct DocUnknownPlugins { - #[label] - pub label_span: Span, -} - -#[derive(LintDiagnostic)] -#[diag(attr_parsing_doc_unknown_any)] -pub(crate) struct DocUnknownAny { - pub name: Symbol, -} - -#[derive(LintDiagnostic)] -#[diag(attr_parsing_doc_auto_cfg_wrong_literal)] -pub(crate) struct DocAutoCfgWrongLiteral; - -#[derive(LintDiagnostic)] -#[diag(attr_parsing_doc_test_takes_list)] -pub(crate) struct DocTestTakesList; - -#[derive(LintDiagnostic)] -#[diag(attr_parsing_doc_test_unknown)] -pub(crate) struct DocTestUnknown { - pub name: Symbol, -} - -#[derive(LintDiagnostic)] -#[diag(attr_parsing_doc_test_literal)] -pub(crate) struct DocTestLiteral; - #[derive(Diagnostic)] #[diag(attr_parsing_doc_alias_malformed)] pub(crate) struct DocAliasMalformed { diff --git a/compiler/rustc_hir/src/lints.rs b/compiler/rustc_hir/src/lints.rs index 2d13ceabf8ca..eba2d182d2c4 100644 --- a/compiler/rustc_hir/src/lints.rs +++ b/compiler/rustc_hir/src/lints.rs @@ -2,7 +2,7 @@ use rustc_data_structures::fingerprint::Fingerprint; pub use rustc_lint_defs::AttributeLintKind; use rustc_lint_defs::LintId; use rustc_macros::HashStable_Generic; -use rustc_span::{Span, Symbol}; +use rustc_span::Span; use crate::HirId; @@ -31,71 +31,3 @@ pub struct AttributeLint { pub span: Span, pub kind: AttributeLintKind, } - -#[derive(Debug, HashStable_Generic)] -pub enum AttributeLintKind { - /// Copy of `IllFormedAttributeInput` - /// specifically for the `invalid_macro_export_arguments` lint until that is removed, - /// see - InvalidMacroExportArguments { - suggestions: Vec, - }, - UnusedDuplicate { - this: Span, - other: Span, - warning: bool, - }, - IllFormedAttributeInput { - suggestions: Vec, - }, - EmptyAttribute { - first_span: Span, - attr_path: AttrPath, - valid_without_list: bool, - }, - InvalidTarget { - name: AttrPath, - target: Target, - applied: Vec, - only: &'static str, - }, - InvalidStyle { - name: AttrPath, - is_used_as_inner: bool, - target: Target, - target_span: Span, - }, - UnsafeAttrOutsideUnsafe { - attribute_name_span: Span, - sugg_spans: (Span, Span), - }, - DuplicateDocAlias { - first_definition: Span, - }, - DocAutoCfgExpectsHideOrShow, - DocAutoCfgHideShowUnexpectedItem { - attr_name: Symbol, - }, - DocAutoCfgHideShowExpectsList { - attr_name: Symbol, - }, - DocInvalid, - DocUnknownInclude { - inner: &'static str, - value: Symbol, - }, - DocUnknownSpotlight, - DocUnknownPasses { - name: Symbol, - }, - DocUnknownPlugins, - DocUnknownAny { - name: Symbol, - }, - DocAutoCfgWrongLiteral, - DocTestTakesList, - DocTestUnknown { - name: Symbol, - }, - DocTestLiteral, -} diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 0553bc95caa2..94f638b676e8 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -233,6 +233,58 @@ lint_deprecated_where_clause_location = where clause not allowed here lint_diag_out_of_impl = diagnostics should only be created in `Diagnostic`/`Subdiagnostic`/`LintDiagnostic` impls +lint_doc_alias_duplicated = doc alias is duplicated + .label = first defined here + +lint_doc_auto_cfg_expects_hide_or_show = + only `hide` or `show` are allowed in `#[doc(auto_cfg(...))]` + +lint_doc_auto_cfg_hide_show_expects_list = + `#![doc(auto_cfg({$attr_name}(...)))]` expects a list of items + +lint_doc_auto_cfg_hide_show_unexpected_item = + `#![doc(auto_cfg({$attr_name}(...)))]` only accepts identifiers or key/value items + +lint_doc_auto_cfg_wrong_literal = + expected boolean for `#[doc(auto_cfg = ...)]` + +lint_doc_invalid = + invalid `doc` attribute + +lint_doc_test_literal = `#![doc(test(...)]` does not take a literal + +lint_doc_test_takes_list = + `#[doc(test(...)]` takes a list of attributes + +lint_doc_test_unknown = + unknown `doc(test)` attribute `{$name}` + +lint_doc_unknown_any = + unknown `doc` attribute `{$name}` + +lint_doc_unknown_include = + unknown `doc` attribute `include` + .suggestion = use `doc = include_str!` instead + +lint_doc_unknown_passes = + unknown `doc` attribute `{$name}` + .note = `doc` attribute `{$name}` no longer functions; see issue #44136 + .label = no longer functions + .no_op_note = `doc({$name})` is now a no-op + +lint_doc_unknown_plugins = + unknown `doc` attribute `plugins` + .note = `doc` attribute `plugins` no longer functions; see issue #44136 and CVE-2018-1000622 + .label = no longer functions + .no_op_note = `doc(plugins)` is now a no-op + +lint_doc_unknown_spotlight = + unknown `doc` attribute `spotlight` + .note = `doc(spotlight)` was renamed to `doc(notable_trait)` + .suggestion = use `notable_trait` instead + .no_op_note = `doc(spotlight)` is now a no-op + + lint_drop_glue = types that do not implement `Drop` can still have drop glue, consider instead using `{$needs_drop}` to detect whether a type is trivially dropped diff --git a/compiler/rustc_lint/src/early/diagnostics.rs b/compiler/rustc_lint/src/early/diagnostics.rs index 589594a3ec5e..4eb50bda53a1 100644 --- a/compiler/rustc_lint/src/early/diagnostics.rs +++ b/compiler/rustc_lint/src/early/diagnostics.rs @@ -367,5 +367,55 @@ pub fn decorate_attribute_lint( &AttributeLintKind::UnexpectedCfgValue(name, value) => { check_cfg::unexpected_cfg_value(sess, tcx, name, value).decorate_lint(diag) } + &AttributeLintKind::DuplicateDocAlias { first_definition } => { + lints::DocAliasDuplicated { first_defn: first_definition }.decorate_lint(diag) + } + + &AttributeLintKind::DocAutoCfgExpectsHideOrShow => { + lints::DocAutoCfgExpectsHideOrShow.decorate_lint(diag) + } + + &AttributeLintKind::DocAutoCfgHideShowUnexpectedItem { attr_name } => { + lints::DocAutoCfgHideShowUnexpectedItem { attr_name }.decorate_lint(diag) + } + + &AttributeLintKind::DocAutoCfgHideShowExpectsList { attr_name } => { + lints::DocAutoCfgHideShowExpectsList { attr_name }.decorate_lint(diag) + } + + &AttributeLintKind::DocInvalid => { lints::DocInvalid }.decorate_lint(diag), + + &AttributeLintKind::DocUnknownInclude { span, inner, value } => { + lints::DocUnknownInclude { inner, value, sugg: (span, Applicability::MaybeIncorrect) } + } + .decorate_lint(diag), + + &AttributeLintKind::DocUnknownSpotlight { span } => { + lints::DocUnknownSpotlight { sugg_span: span }.decorate_lint(diag) + } + + &AttributeLintKind::DocUnknownPasses { name, span } => { + lints::DocUnknownPasses { name, note_span: span }.decorate_lint(diag) + } + + &AttributeLintKind::DocUnknownPlugins { span } => { + lints::DocUnknownPlugins { label_span: span }.decorate_lint(diag) + } + + &AttributeLintKind::DocUnknownAny { name } => { + lints::DocUnknownAny { name }.decorate_lint(diag) + } + + &AttributeLintKind::DocAutoCfgWrongLiteral => { + lints::DocAutoCfgWrongLiteral.decorate_lint(diag) + } + + &AttributeLintKind::DocTestTakesList => lints::DocTestTakesList.decorate_lint(diag), + + &AttributeLintKind::DocTestUnknown { name } => { + lints::DocTestUnknown { name }.decorate_lint(diag) + } + + &AttributeLintKind::DocTestLiteral => lints::DocTestLiteral.decorate_lint(diag), } } diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 1bec316ce45a..4aeeddcac71d 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -3199,3 +3199,91 @@ pub(crate) struct UnusedVisibility { #[suggestion(style = "short", code = "", applicability = "machine-applicable")] pub span: Span, } + +#[derive(LintDiagnostic)] +#[diag(lint_doc_alias_duplicated)] +pub(crate) struct DocAliasDuplicated { + #[label] + pub first_defn: Span, +} + +#[derive(LintDiagnostic)] +#[diag(lint_doc_auto_cfg_expects_hide_or_show)] +pub(crate) struct DocAutoCfgExpectsHideOrShow; + +#[derive(LintDiagnostic)] +#[diag(lint_doc_auto_cfg_hide_show_unexpected_item)] +pub(crate) struct DocAutoCfgHideShowUnexpectedItem { + pub attr_name: Symbol, +} + +#[derive(LintDiagnostic)] +#[diag(lint_doc_auto_cfg_hide_show_expects_list)] +pub(crate) struct DocAutoCfgHideShowExpectsList { + pub attr_name: Symbol, +} + +#[derive(LintDiagnostic)] +#[diag(lint_doc_invalid)] +pub(crate) struct DocInvalid; + +#[derive(LintDiagnostic)] +#[diag(lint_doc_unknown_include)] +pub(crate) struct DocUnknownInclude { + pub inner: &'static str, + pub value: Symbol, + #[suggestion(code = "#{inner}[doc = include_str!(\"{value}\")]")] + pub sugg: (Span, Applicability), +} + +#[derive(LintDiagnostic)] +#[diag(lint_doc_unknown_spotlight)] +#[note] +#[note(lint_no_op_note)] +pub(crate) struct DocUnknownSpotlight { + #[suggestion(style = "short", applicability = "machine-applicable", code = "notable_trait")] + pub sugg_span: Span, +} + +#[derive(LintDiagnostic)] +#[diag(lint_doc_unknown_passes)] +#[note] +#[note(lint_no_op_note)] +pub(crate) struct DocUnknownPasses { + pub name: Symbol, + #[label] + pub note_span: Span, +} + +#[derive(LintDiagnostic)] +#[diag(lint_doc_unknown_plugins)] +#[note] +#[note(lint_no_op_note)] +pub(crate) struct DocUnknownPlugins { + #[label] + pub label_span: Span, +} + +#[derive(LintDiagnostic)] +#[diag(lint_doc_unknown_any)] +pub(crate) struct DocUnknownAny { + pub name: Symbol, +} + +#[derive(LintDiagnostic)] +#[diag(lint_doc_auto_cfg_wrong_literal)] +pub(crate) struct DocAutoCfgWrongLiteral; + +#[derive(LintDiagnostic)] +#[diag(lint_doc_test_takes_list)] +pub(crate) struct DocTestTakesList; + +#[derive(LintDiagnostic)] +#[diag(lint_doc_test_unknown)] +pub(crate) struct DocTestUnknown { + pub name: Symbol, +} + +#[derive(LintDiagnostic)] +#[diag(lint_doc_test_literal)] +pub(crate) struct DocTestLiteral; diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 376310838cc7..28657c7474b4 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -733,6 +733,41 @@ pub enum AttributeLintKind { }, UnexpectedCfgName((Symbol, Span), Option<(Symbol, Span)>), UnexpectedCfgValue((Symbol, Span), Option<(Symbol, Span)>), + DuplicateDocAlias { + first_definition: Span, + }, + DocAutoCfgExpectsHideOrShow, + DocAutoCfgHideShowUnexpectedItem { + attr_name: Symbol, + }, + DocAutoCfgHideShowExpectsList { + attr_name: Symbol, + }, + DocInvalid, + DocUnknownInclude { + span: Span, + inner: &'static str, + value: Symbol, + }, + DocUnknownSpotlight { + span: Span, + }, + DocUnknownPasses { + name: Symbol, + span: Span, + }, + DocUnknownPlugins { + span: Span, + }, + DocUnknownAny { + name: Symbol, + }, + DocAutoCfgWrongLiteral, + DocTestTakesList, + DocTestUnknown { + name: Symbol, + }, + DocTestLiteral, } pub type RegisteredTools = FxIndexSet; diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 13be1a04dbc5..5e582eb61997 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -907,7 +907,19 @@ fn main_args(early_dcx: &mut EarlyDiagCtxt, at_args: &[String]) { for lint in &delayed_lints.lints { match lint { DelayedLint::AttributeParsing(attribute_lint) => { - rustc_attr_parsing::emit_attribute_lint(attribute_lint, tcx) + tcx.node_span_lint( + attribute_lint.lint_id.lint, + attribute_lint.id, + attribute_lint.span, + |diag| { + rustc_lint::decorate_attribute_lint( + tcx.sess, + Some(tcx), + &attribute_lint.kind, + diag, + ); + }, + ); } } } From 06238bd93e6a871f46b09519cd14676c2642a253 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 6 Dec 2025 22:33:24 +0100 Subject: [PATCH 28/64] Update rustdoc JSON output to new attribute API --- .../rustc_hir/src/attrs/data_structures.rs | 38 ++++++ src/librustdoc/json/conversions.rs | 129 ++++++++++++++++-- 2 files changed, 155 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index 0419e219afe4..696d85631e16 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -1,4 +1,5 @@ use std::borrow::Cow; +use std::fmt; use std::path::PathBuf; pub use ReprAttr::*; @@ -231,6 +232,43 @@ impl CfgEntry { } } +impl fmt::Display for CfgEntry { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fn write_entries( + name: &str, + entries: &[CfgEntry], + f: &mut fmt::Formatter<'_>, + ) -> fmt::Result { + write!(f, "{name}(")?; + for (nb, entry) in entries.iter().enumerate() { + if nb != 0 { + f.write_str(", ")?; + } + entry.fmt(f)?; + } + f.write_str(")") + } + match self { + Self::All(entries, _) => write_entries("all", entries, f), + Self::Any(entries, _) => write_entries("any", entries, f), + Self::Not(entry, _) => write!(f, "not({entry})"), + Self::Bool(value, _) => write!(f, "{value}"), + Self::NameValue { name, value, .. } => { + match value { + // We use `as_str` and debug display to have characters escaped and `"` + // characters surrounding the string. + Some((value, _)) => write!(f, "{name} = {:?}", value.as_str()), + None => write!(f, "{name}"), + } + } + Self::Version(version, _) => match version { + Some(version) => write!(f, "{version}"), + None => Ok(()), + }, + } + } +} + /// Possible values for the `#[linkage]` attribute, allowing to specify the /// linkage type for a `MonoItem`. /// diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index edafc9e7a089..892cc483dbd6 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -7,14 +7,14 @@ use rustc_ast::ast; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::thin_vec::ThinVec; use rustc_hir as hir; -use rustc_hir::attrs::{self, DeprecatedSince}; +use rustc_hir::attrs::{self, DeprecatedSince, DocAttribute, DocInline, HideOrShow}; use rustc_hir::def::CtorKind; use rustc_hir::def_id::DefId; use rustc_hir::{HeaderSafety, Safety}; use rustc_metadata::rendered_const; use rustc_middle::ty::TyCtxt; use rustc_middle::{bug, ty}; -use rustc_span::{Pos, kw, sym}; +use rustc_span::{Pos, Symbol, kw, sym}; use rustdoc_json_types::*; use crate::clean::{self, ItemId}; @@ -46,7 +46,7 @@ impl JsonRenderer<'_> { .attrs .other_attrs .iter() - .filter_map(|a| maybe_from_hir_attr(a, item.item_id, self.tcx)) + .flat_map(|a| maybe_from_hir_attr(a, item.item_id, self.tcx)) .collect(); let span = item.span(self.tcx); let visibility = item.visibility(self.tcx); @@ -902,11 +902,7 @@ impl FromClean for ItemKind { /// Maybe convert a attribute from hir to json. /// /// Returns `None` if the attribute shouldn't be in the output. -fn maybe_from_hir_attr( - attr: &hir::Attribute, - item_id: ItemId, - tcx: TyCtxt<'_>, -) -> Option { +fn maybe_from_hir_attr(attr: &hir::Attribute, item_id: ItemId, tcx: TyCtxt<'_>) -> Vec { use attrs::AttributeKind as AK; let kind = match attr { @@ -914,12 +910,12 @@ fn maybe_from_hir_attr( hir::Attribute::Unparsed(_) => { // FIXME: We should handle `#[doc(hidden)]`. - return Some(other_attr(tcx, attr)); + return vec![other_attr(tcx, attr)]; } }; - Some(match kind { - AK::Deprecation { .. } => return None, // Handled separately into Item::deprecation. + vec![match kind { + AK::Deprecation { .. } => return Vec::new(), // Handled separately into Item::deprecation. AK::DocComment { .. } => unreachable!("doc comments stripped out earlier"), AK::MacroExport { .. } => Attribute::MacroExport, @@ -939,9 +935,118 @@ fn maybe_from_hir_attr( AK::NoMangle(_) => Attribute::NoMangle, AK::NonExhaustive(_) => Attribute::NonExhaustive, AK::AutomaticallyDerived(_) => Attribute::AutomaticallyDerived, + AK::Doc(d) => { + fn toggle_attr(ret: &mut Vec, name: &str, v: &Option) { + if v.is_some() { + ret.push(Attribute::Other(format!("#[doc({name})]"))); + } + } + + fn name_value_attr( + ret: &mut Vec, + name: &str, + v: &Option<(Symbol, rustc_span::Span)>, + ) { + if let Some((v, _)) = v { + // We use `as_str` and debug display to have characters escaped and `"` + // characters surrounding the string. + ret.push(Attribute::Other(format!("#[doc({name} = {:?})]", v.as_str()))); + } + } + + let DocAttribute { + aliases, + hidden, + inline, + cfg, + auto_cfg, + auto_cfg_change, + fake_variadic, + keyword, + attribute, + masked, + notable_trait, + search_unbox, + html_favicon_url, + html_logo_url, + html_playground_url, + html_root_url, + html_no_source, + issue_tracker_base_url, + rust_logo, + test_attrs, + no_crate_inject, + } = &**d; + + let mut ret = Vec::new(); + + for (alias, _) in aliases { + // We use `as_str` and debug display to have characters escaped and `"` characters + // surrounding the string. + ret.push(Attribute::Other(format!("#[doc(alias = {:?})]", alias.as_str()))); + } + toggle_attr(&mut ret, "hidden", hidden); + if let Some(inline) = inline.first() { + ret.push(Attribute::Other(format!( + "#[doc({})]", + match inline.0 { + DocInline::Inline => "inline", + DocInline::NoInline => "no_inline", + } + ))); + } + for sub_cfg in cfg { + ret.push(Attribute::Other(format!("#[doc(cfg({sub_cfg}))]"))); + } + for (auto_cfg, _) in auto_cfg { + let kind = match auto_cfg.kind { + HideOrShow::Hide => "hide", + HideOrShow::Show => "show", + }; + let mut out = format!("#[doc(auto_cfg({kind}("); + for (pos, value) in auto_cfg.values.iter().enumerate() { + if pos > 0 { + out.push_str(", "); + } + out.push_str(value.name.as_str()); + if let Some((value, _)) = value.value { + // We use `as_str` and debug display to have characters escaped and `"` + // characters surrounding the string. + out.push_str(&format!(" = {:?}", value.as_str())); + } + } + out.push_str(")))]"); + ret.push(Attribute::Other(out)); + } + for (change, _) in auto_cfg_change { + ret.push(Attribute::Other(format!("#[doc(auto_cfg = {change})]"))); + } + toggle_attr(&mut ret, "fake_variadic", fake_variadic); + name_value_attr(&mut ret, "keyword", keyword); + name_value_attr(&mut ret, "attribute", attribute); + toggle_attr(&mut ret, "masked", masked); + toggle_attr(&mut ret, "notable_trait", notable_trait); + toggle_attr(&mut ret, "search_unbox", search_unbox); + name_value_attr(&mut ret, "html_favicon_url", html_favicon_url); + name_value_attr(&mut ret, "html_logo_url", html_logo_url); + name_value_attr(&mut ret, "html_playground_url", html_playground_url); + name_value_attr(&mut ret, "html_root_url", html_root_url); + toggle_attr(&mut ret, "html_no_source", html_no_source); + name_value_attr(&mut ret, "issue_tracker_base_url", issue_tracker_base_url); + toggle_attr(&mut ret, "rust_logo", rust_logo); + let source_map = tcx.sess.source_map(); + for attr_span in test_attrs { + // FIXME: This is ugly, remove when `test_attrs` has been ported to new attribute API. + if let Ok(snippet) = source_map.span_to_snippet(*attr_span) { + ret.push(Attribute::Other(format!("#[doc(test(attr({snippet})))"))); + } + } + toggle_attr(&mut ret, "no_crate_inject", no_crate_inject); + return ret; + } _ => other_attr(tcx, attr), - }) + }] } fn other_attr(tcx: TyCtxt<'_>, attr: &hir::Attribute) -> Attribute { From 1da7684c7d0f1ec2bd9aa99a9844cff3296502ea Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 7 Dec 2025 12:18:53 +0100 Subject: [PATCH 29/64] Improve code and add more comments --- .../rustc_hir/src/attrs/data_structures.rs | 30 +--------------- src/librustdoc/clean/cfg.rs | 34 +++++++++---------- src/librustdoc/clean/types.rs | 18 ++++------ src/librustdoc/doctest/rust.rs | 9 +++++ src/librustdoc/passes/collect_trait_impls.rs | 3 ++ 5 files changed, 36 insertions(+), 58 deletions(-) diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index 696d85631e16..09ef6dc18814 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -510,7 +510,7 @@ pub struct CfgHideShow { pub values: ThinVec, } -#[derive(Clone, Debug, HashStable_Generic, Encodable, Decodable, PrintAttribute)] +#[derive(Clone, Debug, Default, HashStable_Generic, Encodable, Decodable, PrintAttribute)] pub struct DocAttribute { pub aliases: FxIndexMap, pub hidden: Option, @@ -546,34 +546,6 @@ pub struct DocAttribute { pub no_crate_inject: Option, } -impl Default for DocAttribute { - fn default() -> Self { - Self { - aliases: FxIndexMap::default(), - hidden: None, - inline: ThinVec::new(), - cfg: ThinVec::new(), - auto_cfg: ThinVec::new(), - auto_cfg_change: ThinVec::new(), - fake_variadic: None, - keyword: None, - attribute: None, - masked: None, - notable_trait: None, - search_unbox: None, - html_favicon_url: None, - html_logo_url: None, - html_playground_url: None, - html_root_url: None, - html_no_source: None, - issue_tracker_base_url: None, - rust_logo: None, - test_attrs: ThinVec::new(), - no_crate_inject: None, - } - } -} - /// Represents parsed *built-in* inert attributes. /// /// ## Overview diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs index 99409cf838cd..6cad4301b313 100644 --- a/src/librustdoc/clean/cfg.rs +++ b/src/librustdoc/clean/cfg.rs @@ -59,11 +59,11 @@ fn is_all_cfg(cfg: &CfgEntry) -> bool { } } -fn strip_hidden(cfg: &CfgEntry, hidden: &FxHashSet) -> Option { +fn strip_hidden(cfg: &CfgEntry, hidden: &FxHashSet) -> Option { match cfg { CfgEntry::Bool(..) => Some(cfg.clone()), CfgEntry::NameValue { .. } => { - if !hidden.contains(&SimpleCfg::from(cfg)) { + if !hidden.contains(&NameValueCfg::from(cfg)) { Some(cfg.clone()) } else { None @@ -109,7 +109,7 @@ impl Cfg { /// Parses a `MetaItemInner` into a `Cfg`. fn parse_nested( nested_cfg: &MetaItemInner, - exclude: &FxHashSet, + exclude: &FxHashSet, ) -> Result, InvalidCfgError> { match nested_cfg { MetaItemInner::MetaItem(cfg) => Cfg::parse_without(cfg, exclude), @@ -124,7 +124,7 @@ impl Cfg { fn parse_without( cfg: &MetaItem, - exclude: &FxHashSet, + exclude: &FxHashSet, ) -> Result, InvalidCfgError> { let name = match cfg.ident() { Some(ident) => ident.name, @@ -137,7 +137,7 @@ impl Cfg { }; match cfg.kind { MetaItemKind::Word => { - if exclude.contains(&SimpleCfg::new(name)) { + if exclude.contains(&NameValueCfg::new(name)) { Ok(None) } else { Ok(Some(Cfg(CfgEntry::NameValue { @@ -150,7 +150,7 @@ impl Cfg { } MetaItemKind::NameValue(ref lit) => match lit.kind { LitKind::Str(value, _) => { - if exclude.contains(&SimpleCfg::new_value(name, value)) { + if exclude.contains(&NameValueCfg::new_value(name, value)) { Ok(None) } else { Ok(Some(Cfg(CfgEntry::NameValue { @@ -666,12 +666,12 @@ impl fmt::Display for Display<'_> { } #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -struct SimpleCfg { +struct NameValueCfg { name: Symbol, value: Option, } -impl SimpleCfg { +impl NameValueCfg { fn new(name: Symbol) -> Self { Self { name, value: None } } @@ -681,18 +681,18 @@ impl SimpleCfg { } } -impl<'a> From<&'a CfgEntry> for SimpleCfg { +impl<'a> From<&'a CfgEntry> for NameValueCfg { fn from(cfg: &'a CfgEntry) -> Self { match cfg { CfgEntry::NameValue { name, value, .. } => { - SimpleCfg { name: *name, value: (*value).map(|(v, _)| v) } + NameValueCfg { name: *name, value: (*value).map(|(v, _)| v) } } - _ => SimpleCfg { name: sym::empty, value: None }, + _ => NameValueCfg { name: sym::empty, value: None }, } } } -impl<'a> From<&'a attrs::CfgInfo> for SimpleCfg { +impl<'a> From<&'a attrs::CfgInfo> for NameValueCfg { fn from(cfg: &'a attrs::CfgInfo) -> Self { Self { name: cfg.name, value: cfg.value.map(|(value, _)| value) } } @@ -703,7 +703,7 @@ impl<'a> From<&'a attrs::CfgInfo> for SimpleCfg { pub(crate) struct CfgInfo { /// List of currently active `doc(auto_cfg(hide(...)))` cfgs, minus currently active /// `doc(auto_cfg(show(...)))` cfgs. - hidden_cfg: FxHashSet, + hidden_cfg: FxHashSet, /// Current computed `cfg`. Each time we enter a new item, this field is updated as well while /// taking into account the `hidden_cfg` information. current_cfg: Cfg, @@ -719,9 +719,9 @@ impl Default for CfgInfo { fn default() -> Self { Self { hidden_cfg: FxHashSet::from_iter([ - SimpleCfg::new(sym::test), - SimpleCfg::new(sym::doc), - SimpleCfg::new(sym::doctest), + NameValueCfg::new(sym::test), + NameValueCfg::new(sym::doc), + NameValueCfg::new(sym::doctest), ]), current_cfg: Cfg(CfgEntry::Bool(true, DUMMY_SP)), auto_cfg_active: true, @@ -761,7 +761,7 @@ fn handle_auto_cfg_hide_show( new_hide_attrs: &mut FxHashMap<(Symbol, Option), rustc_span::Span>, ) { for value in &attr.values { - let simple = SimpleCfg::from(value); + let simple = NameValueCfg::from(value); if attr.kind == HideOrShow::Show { if let Some(span) = new_hide_attrs.get(&(simple.name, simple.value)) { show_hide_show_conflict_error(tcx, attr_span, *span); diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index cefaf1102fb9..7a4650feac1c 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -229,34 +229,28 @@ impl ExternalCrate { } pub(crate) fn keywords(&self, tcx: TyCtxt<'_>) -> impl Iterator { - self.retrieve_keywords_or_documented_attributes(tcx, true) + self.retrieve_keywords_or_documented_attributes(tcx, |d| d.keyword.map(|(v, _)| v)) } pub(crate) fn documented_attributes( &self, tcx: TyCtxt<'_>, ) -> impl Iterator { - self.retrieve_keywords_or_documented_attributes(tcx, false) + self.retrieve_keywords_or_documented_attributes(tcx, |d| d.attribute.map(|(v, _)| v)) } - fn retrieve_keywords_or_documented_attributes( + fn retrieve_keywords_or_documented_attributes Option>( &self, tcx: TyCtxt<'_>, - look_for_keyword: bool, + callback: F, ) -> impl Iterator { let as_target = move |did: DefId, tcx: TyCtxt<'_>| -> Option<(DefId, Symbol)> { tcx.get_all_attrs(did) .iter() .find_map(|attr| match attr { - Attribute::Parsed(AttributeKind::Doc(d)) => { - if look_for_keyword { - d.keyword - } else { - d.attribute - } - } + Attribute::Parsed(AttributeKind::Doc(d)) => callback(d), _ => None, }) - .map(|(value, _)| (did, value)) + .map(|value| (did, value)) }; self.mapped_root_modules(tcx, as_target) } diff --git a/src/librustdoc/doctest/rust.rs b/src/librustdoc/doctest/rust.rs index 6f294ad96267..987e1c2ddbf9 100644 --- a/src/librustdoc/doctest/rust.rs +++ b/src/librustdoc/doctest/rust.rs @@ -143,6 +143,13 @@ impl HirCollector<'_> { if let TokenTree::Ident(i) = token { let i = i.to_string(); let peek = iter.peek(); + // From this ident, we can have things like: + // + // * Group: `allow(...)` + // * Name/value: `crate_name = "..."` + // * Tokens: `html_no_url` + // + // So we peek next element to know what case we are in. match peek { Some(TokenTree::Group(g)) => { let g = g.to_string(); @@ -150,6 +157,8 @@ impl HirCollector<'_> { // Add the additional attributes to the global_crate_attrs vector self.collector.global_crate_attrs.push(format!("{i}{g}")); } + // If next item is `=`, it means it's a name value so we will need + // to get the value as well. Some(TokenTree::Punct(p)) if p.as_char() == '=' => { let p = p.to_string(); iter.next(); diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs index 357d00ef6521..c2a69baf2989 100644 --- a/src/librustdoc/passes/collect_trait_impls.rs +++ b/src/librustdoc/passes/collect_trait_impls.rs @@ -68,6 +68,9 @@ pub(crate) fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) -> while let Some(did) = parent { attr_buf.extend(tcx.get_all_attrs(did).iter().filter_map(|attr| match attr { Attribute::Parsed(AttributeKind::Doc(d)) if !d.cfg.is_empty() => { + // The only doc attributes we're interested into for trait impls are the + // `cfg`s for the `doc_cfg` feature. So we create a new empty `DocAttribute` + // and then only clone the actual `DocAttribute::cfg` field. let mut new_attr = DocAttribute::default(); new_attr.cfg = d.cfg.clone(); Some(Attribute::Parsed(AttributeKind::Doc(Box::new(new_attr)))) From 4191e94715647b2490f0bb8040f589239ab65813 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 8 Dec 2025 18:06:36 +0100 Subject: [PATCH 30/64] Improve spans for `auto_cfg(hide/show)` errors --- compiler/rustc_hir/src/attrs/data_structures.rs | 10 ++++++++++ src/librustdoc/clean/cfg.rs | 14 ++++++-------- tests/rustdoc-ui/cfg-hide-show-conflict.stderr | 8 ++++---- 3 files changed, 20 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index 09ef6dc18814..e4a55bf39333 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -504,6 +504,16 @@ pub struct CfgInfo { pub value: Option<(Symbol, Span)>, } +impl CfgInfo { + pub fn span_for_name_and_value(&self) -> Span { + if let Some((_, value_span)) = self.value { + self.name_span.with_hi(value_span.hi()) + } else { + self.name_span + } + } +} + #[derive(Clone, Debug, HashStable_Generic, Encodable, Decodable, PrintAttribute)] pub struct CfgHideShow { pub kind: HideOrShow, diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs index 6cad4301b313..1413f7f56c96 100644 --- a/src/librustdoc/clean/cfg.rs +++ b/src/librustdoc/clean/cfg.rs @@ -47,7 +47,7 @@ fn is_simple_cfg(cfg: &CfgEntry) -> bool { } } -/// Whether the configuration consists of just `Cfg`, `Not` or `All`. +/// Returns `false` if is `Any`, otherwise returns `true`. fn is_all_cfg(cfg: &CfgEntry) -> bool { match cfg { CfgEntry::Bool(..) @@ -756,7 +756,6 @@ fn handle_auto_cfg_hide_show( tcx: TyCtxt<'_>, cfg_info: &mut CfgInfo, attr: &CfgHideShow, - attr_span: Span, new_show_attrs: &mut FxHashMap<(Symbol, Option), rustc_span::Span>, new_hide_attrs: &mut FxHashMap<(Symbol, Option), rustc_span::Span>, ) { @@ -764,16 +763,16 @@ fn handle_auto_cfg_hide_show( let simple = NameValueCfg::from(value); if attr.kind == HideOrShow::Show { if let Some(span) = new_hide_attrs.get(&(simple.name, simple.value)) { - show_hide_show_conflict_error(tcx, attr_span, *span); + show_hide_show_conflict_error(tcx, value.span_for_name_and_value(), *span); } else { - new_show_attrs.insert((simple.name, simple.value), attr_span); + new_show_attrs.insert((simple.name, simple.value), value.span_for_name_and_value()); } cfg_info.hidden_cfg.remove(&simple); } else { if let Some(span) = new_show_attrs.get(&(simple.name, simple.value)) { - show_hide_show_conflict_error(tcx, attr_span, *span); + show_hide_show_conflict_error(tcx, value.span_for_name_and_value(), *span); } else { - new_hide_attrs.insert((simple.name, simple.value), attr_span); + new_hide_attrs.insert((simple.name, simple.value), value.span_for_name_and_value()); } cfg_info.hidden_cfg.insert(simple); } @@ -871,12 +870,11 @@ pub(crate) fn extract_cfg_from_attrs<'a, I: Iterator ) { return None; } - for (value, span) in &d.auto_cfg { + for (value, _) in &d.auto_cfg { handle_auto_cfg_hide_show( tcx, cfg_info, value, - *span, &mut new_show_attrs, &mut new_hide_attrs, ); diff --git a/tests/rustdoc-ui/cfg-hide-show-conflict.stderr b/tests/rustdoc-ui/cfg-hide-show-conflict.stderr index 384a9f1a0b1f..22231e82cd7b 100644 --- a/tests/rustdoc-ui/cfg-hide-show-conflict.stderr +++ b/tests/rustdoc-ui/cfg-hide-show-conflict.stderr @@ -1,14 +1,14 @@ error: same `cfg` was in `auto_cfg(hide(...))` and `auto_cfg(show(...))` on the same item - --> $DIR/cfg-hide-show-conflict.rs:3:8 + --> $DIR/cfg-hide-show-conflict.rs:3:31 | LL | #![doc(auto_cfg(show(windows, target_os = "linux")))] - | ^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ | note: first change was here - --> $DIR/cfg-hide-show-conflict.rs:2:8 + --> $DIR/cfg-hide-show-conflict.rs:2:22 | LL | #![doc(auto_cfg(hide(target_os = "linux")))] - | ^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ error: aborting due to 1 previous error From 6230b56eaa04df03ee46100823ec4aedd78e522a Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 8 Dec 2025 22:44:41 +0100 Subject: [PATCH 31/64] Update clippy code --- .../clippy_lints/src/doc/doc_suspicious_footnotes.rs | 9 ++++++++- .../clippy_lints/src/doc/suspicious_doc_comments.rs | 8 ++++---- src/tools/clippy/clippy_utils/src/attrs.rs | 7 +------ 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/tools/clippy/clippy_lints/src/doc/doc_suspicious_footnotes.rs b/src/tools/clippy/clippy_lints/src/doc/doc_suspicious_footnotes.rs index 1944cd7c91d3..deca29a1885f 100644 --- a/src/tools/clippy/clippy_lints/src/doc/doc_suspicious_footnotes.rs +++ b/src/tools/clippy/clippy_lints/src/doc/doc_suspicious_footnotes.rs @@ -2,6 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use rustc_ast::attr::AttributeExt as _; use rustc_ast::token::{CommentKind, DocFragmentKind}; use rustc_errors::Applicability; +use rustc_hir::attrs::AttributeKind; use rustc_hir::{AttrStyle, Attribute}; use rustc_lint::{LateContext, LintContext}; @@ -45,7 +46,13 @@ pub fn check(cx: &LateContext<'_>, doc: &str, range: Range, fragments: &F if let DocFragmentKind::Sugared(_) = this_fragment.kind { let (doc_attr, doc_attr_comment_kind, attr_style) = attrs .iter() - .filter(|attr| attr.span().overlaps(this_fragment.span)) + .filter(|attr| { + matches!( + attr, + Attribute::Parsed(AttributeKind::DocComment { span, .. }) + if span.overlaps(this_fragment.span), + ) + }) .rev() .find_map(|attr| { let (_, fragment) = attr.doc_str_and_fragment_kind()?; diff --git a/src/tools/clippy/clippy_lints/src/doc/suspicious_doc_comments.rs b/src/tools/clippy/clippy_lints/src/doc/suspicious_doc_comments.rs index e751600f00a6..178d688264b7 100644 --- a/src/tools/clippy/clippy_lints/src/doc/suspicious_doc_comments.rs +++ b/src/tools/clippy/clippy_lints/src/doc/suspicious_doc_comments.rs @@ -39,15 +39,15 @@ fn collect_doc_replacements(attrs: &[Attribute]) -> Vec<(Span, String)> { .filter_map(|attr| { if let Attribute::Parsed(AttributeKind::DocComment { style: AttrStyle::Outer, - kind, + kind: DocFragmentKind::Sugared(comment_kind), comment, .. }) = attr && let Some(com) = comment.as_str().strip_prefix('!') { - let sugg = match kind { - DocFragmentKind::Sugared(CommentKind::Block) => format!("/*!{com}*/"), - DocFragmentKind::Sugared(CommentKind::Line) | DocFragmentKind::Raw(_) => format!("//!{com}"), + let sugg = match comment_kind { + CommentKind::Block => format!("/*!{com}*/"), + CommentKind::Line => format!("//!{com}"), }; Some((attr.span(), sugg)) } else { diff --git a/src/tools/clippy/clippy_utils/src/attrs.rs b/src/tools/clippy/clippy_utils/src/attrs.rs index 671b266ba008..2fd773b06781 100644 --- a/src/tools/clippy/clippy_utils/src/attrs.rs +++ b/src/tools/clippy/clippy_utils/src/attrs.rs @@ -2,7 +2,6 @@ use crate::source::SpanRangeExt; use crate::{sym, tokenize_with_text}; -use rustc_ast::attr; use rustc_ast::attr::AttributeExt; use rustc_errors::Applicability; use rustc_hir::attrs::AttributeKind; @@ -87,11 +86,7 @@ pub fn is_proc_macro(attrs: &[impl AttributeExt]) -> bool { /// Checks whether `attrs` contain `#[doc(hidden)]` pub fn is_doc_hidden(attrs: &[impl AttributeExt]) -> bool { - attrs - .iter() - .filter(|attr| attr.has_name(sym::doc)) - .filter_map(AttributeExt::meta_item_list) - .any(|l| attr::list_contains_name(&l, sym::hidden)) + attrs.iter().any(|attr| attr.is_doc_hidden()) } /// Checks whether the given ADT, or any of its fields/variants, are marked as `#[non_exhaustive]` From 40907f522d6e57abb83f80db7c62719bed7d8d46 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 8 Dec 2025 23:17:16 +0100 Subject: [PATCH 32/64] Fix doc alias suggestion --- compiler/rustc_attr_parsing/src/attributes/doc.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/doc.rs b/compiler/rustc_attr_parsing/src/attributes/doc.rs index 5714d33e861f..a26f22c4455d 100644 --- a/compiler/rustc_attr_parsing/src/attributes/doc.rs +++ b/compiler/rustc_attr_parsing/src/attributes/doc.rs @@ -137,10 +137,8 @@ impl DocParser { cx: &'c mut AcceptContext<'_, '_, S>, alias: Symbol, span: Span, - is_list: bool, ) { - let attr_str = - &format!("`#[doc(alias{})]`", if is_list { "(\"...\")" } else { " = \"...\"" }); + let attr_str = "`#[doc(alias = \"...\")]`"; if alias == sym::empty { cx.emit_err(DocAliasEmpty { span, attr_str }); return; @@ -186,7 +184,7 @@ impl DocParser { continue; }; - self.add_alias(cx, alias, i.span(), false); + self.add_alias(cx, alias, i.span()); } } ArgParser::NameValue(nv) => { @@ -194,7 +192,7 @@ impl DocParser { cx.expected_string_literal(nv.value_span, Some(nv.value_as_lit())); return; }; - self.add_alias(cx, alias, nv.value_span, false); + self.add_alias(cx, alias, nv.value_span); } } } From 64aaeacd7168ae1995fed60974142db14e246840 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 9 Dec 2025 22:27:28 +0100 Subject: [PATCH 33/64] Update to new API, allowing to remove `check_doc_cfg.rs` file from librustdoc --- .../src/attributes/cfg_old.rs | 1 - .../rustc_attr_parsing/src/attributes/doc.rs | 11 ++- .../rustc_hir/src/attrs/data_structures.rs | 11 +-- library/std/build.rs | 3 + src/librustdoc/clean/cfg.rs | 43 ++++------- src/librustdoc/clean/cfg/tests.rs | 11 +-- src/librustdoc/lib.rs | 1 - src/librustdoc/passes/check_doc_cfg.rs | 72 ------------------- src/librustdoc/passes/mod.rs | 5 -- tests/rustdoc-ui/doc-cfg-2.rs | 2 + tests/rustdoc-ui/doc-cfg-2.stderr | 20 +++++- .../doc-cfg-check-cfg.cfg_empty.stderr | 12 ++-- tests/rustdoc-ui/issues/issue-91713.stdout | 2 - 13 files changed, 59 insertions(+), 135 deletions(-) delete mode 100644 src/librustdoc/passes/check_doc_cfg.rs diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg_old.rs b/compiler/rustc_attr_parsing/src/attributes/cfg_old.rs index 29be000d476d..acb234480d5d 100644 --- a/compiler/rustc_attr_parsing/src/attributes/cfg_old.rs +++ b/compiler/rustc_attr_parsing/src/attributes/cfg_old.rs @@ -2,7 +2,6 @@ use rustc_ast::{LitKind, MetaItem, MetaItemInner, MetaItemKind, MetaItemLit, Nod use rustc_ast_pretty::pprust; use rustc_feature::{Features, GatedCfg, find_gated_cfg}; use rustc_hir::RustcVersion; -use rustc_hir::lints::AttributeLintKind; use rustc_session::Session; use rustc_session::lint::{BuiltinLintDiag, Lint}; use rustc_session::parse::feature_err; diff --git a/compiler/rustc_attr_parsing/src/attributes/doc.rs b/compiler/rustc_attr_parsing/src/attributes/doc.rs index a26f22c4455d..ccb6a873fb12 100644 --- a/compiler/rustc_attr_parsing/src/attributes/doc.rs +++ b/compiler/rustc_attr_parsing/src/attributes/doc.rs @@ -294,7 +294,7 @@ impl DocParser { cx.expected_identifier(sub_item.path().span()); continue; }; - if let Ok(CfgEntry::NameValue { name, name_span, value, .. }) = + if let Ok(CfgEntry::NameValue { name, value, .. }) = super::cfg::parse_name_value( name, sub_item.path().span(), @@ -303,7 +303,14 @@ impl DocParser { cx, ) { - cfg_hide_show.values.push(CfgInfo { name, name_span, value }) + cfg_hide_show.values.push(CfgInfo { + name, + name_span: sub_item.path().span(), + // If `value` is `Some`, `a.name_value()` will always return + // `Some` as well. + value: value + .map(|v| (v, a.name_value().unwrap().value_span)), + }) } } _ => { diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index e4a55bf39333..b7f8be3ec88f 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -218,14 +218,7 @@ impl CfgEntry { ( Self::NameValue { name: name1, value: value1, .. }, Self::NameValue { name: name2, value: value2, .. }, - ) => { - name1 == name2 - && match (value1, value2) { - (Some((a, _)), Some((b, _))) => a == b, - (None, None) => true, - _ => false, - } - } + ) => name1 == name2 && value1 == value2, (Self::Version(a, _), Self::Version(b, _)) => a == b, _ => false, } @@ -257,7 +250,7 @@ impl fmt::Display for CfgEntry { match value { // We use `as_str` and debug display to have characters escaped and `"` // characters surrounding the string. - Some((value, _)) => write!(f, "{name} = {:?}", value.as_str()), + Some(value) => write!(f, "{name} = {:?}", value.as_str()), None => write!(f, "{name}"), } } diff --git a/library/std/build.rs b/library/std/build.rs index bee28e88491d..c0a6e30b3808 100644 --- a/library/std/build.rs +++ b/library/std/build.rs @@ -13,6 +13,9 @@ fn main() { println!("cargo:rustc-cfg=netbsd10"); } + // Needed for `#![doc(auto_cfg(hide(no_global_oom_handling)))]` attribute. + println!("cargo::rustc-check-cfg=cfg(no_global_oom_handling)"); + println!("cargo:rustc-check-cfg=cfg(restricted_std)"); if target_os == "linux" || target_os == "android" diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs index 1413f7f56c96..97a60c5a5098 100644 --- a/src/librustdoc/clean/cfg.rs +++ b/src/librustdoc/clean/cfg.rs @@ -140,12 +140,7 @@ impl Cfg { if exclude.contains(&NameValueCfg::new(name)) { Ok(None) } else { - Ok(Some(Cfg(CfgEntry::NameValue { - name, - value: None, - name_span: DUMMY_SP, - span: DUMMY_SP, - }))) + Ok(Some(Cfg(CfgEntry::NameValue { name, value: None, span: DUMMY_SP }))) } } MetaItemKind::NameValue(ref lit) => match lit.kind { @@ -155,8 +150,7 @@ impl Cfg { } else { Ok(Some(Cfg(CfgEntry::NameValue { name, - value: Some((value, DUMMY_SP)), - name_span: DUMMY_SP, + value: Some(value), span: DUMMY_SP, }))) } @@ -226,9 +220,7 @@ impl Cfg { CfgEntry::Any(sub_cfgs, _) => { sub_cfgs.iter().any(|sub_cfg| cfg_matches(sub_cfg, psess)) } - CfgEntry::NameValue { name, value, .. } => { - psess.config.contains(&(*name, value.clone().map(|(s, _)| s))) - } + CfgEntry::NameValue { name, value, .. } => psess.config.contains(&(*name, *value)), CfgEntry::Version(..) => { // FIXME: should be handled. false @@ -497,7 +489,7 @@ impl Display<'_> { sub_cfgs .iter() .map(|sub_cfg| { - if let CfgEntry::NameValue { value: Some((feat, _)), .. } = sub_cfg + if let CfgEntry::NameValue { value: Some(feat), .. } = sub_cfg && short_longhand { Either::Left(self.code_wrappers().wrap(feat)) @@ -557,7 +549,7 @@ impl fmt::Display for Display<'_> { (sym::unix, None) => "Unix", (sym::windows, None) => "Windows", (sym::debug_assertions, None) => "debug-assertions enabled", - (sym::target_os, Some((os, _))) => match os.as_str() { + (sym::target_os, Some(os)) => match os.as_str() { "android" => "Android", "cygwin" => "Cygwin", "dragonfly" => "DragonFly BSD", @@ -582,7 +574,7 @@ impl fmt::Display for Display<'_> { "visionos" => "visionOS", _ => "", }, - (sym::target_arch, Some((arch, _))) => match arch.as_str() { + (sym::target_arch, Some(arch)) => match arch.as_str() { "aarch64" => "AArch64", "arm" => "ARM", "loongarch32" => "LoongArch LA32", @@ -605,14 +597,14 @@ impl fmt::Display for Display<'_> { "x86_64" => "x86-64", _ => "", }, - (sym::target_vendor, Some((vendor, _))) => match vendor.as_str() { + (sym::target_vendor, Some(vendor)) => match vendor.as_str() { "apple" => "Apple", "pc" => "PC", "sun" => "Sun", "fortanix" => "Fortanix", _ => "", }, - (sym::target_env, Some((env, _))) => match env.as_str() { + (sym::target_env, Some(env)) => match env.as_str() { "gnu" => "GNU", "msvc" => "MSVC", "musl" => "musl", @@ -621,20 +613,20 @@ impl fmt::Display for Display<'_> { "sgx" => "SGX", _ => "", }, - (sym::target_endian, Some((endian, _))) => { + (sym::target_endian, Some(endian)) => { return write!(fmt, "{endian}-endian"); } - (sym::target_pointer_width, Some((bits, _))) => { + (sym::target_pointer_width, Some(bits)) => { return write!(fmt, "{bits}-bit"); } - (sym::target_feature, Some((feat, _))) => match self.1 { + (sym::target_feature, Some(feat)) => match self.1 { Format::LongHtml => { return write!(fmt, "target feature {feat}"); } Format::LongPlain => return write!(fmt, "target feature `{feat}`"), Format::ShortHtml => return write!(fmt, "{feat}"), }, - (sym::feature, Some((feat, _))) => match self.1 { + (sym::feature, Some(feat)) => match self.1 { Format::LongHtml => { return write!(fmt, "crate feature {feat}"); } @@ -647,9 +639,7 @@ impl fmt::Display for Display<'_> { fmt.write_str(human_readable) } else { let value = value - .map(|(v, _)| { - fmt::from_fn(move |f| write!(f, "={}", self.1.escape(v.as_str()))) - }) + .map(|v| fmt::from_fn(move |f| write!(f, "={}", self.1.escape(v.as_str())))) .maybe_display(); self.code_wrappers() .wrap(format_args!("{}{value}", self.1.escape(name.as_str()))) @@ -684,9 +674,7 @@ impl NameValueCfg { impl<'a> From<&'a CfgEntry> for NameValueCfg { fn from(cfg: &'a CfgEntry) -> Self { match cfg { - CfgEntry::NameValue { name, value, .. } => { - NameValueCfg { name: *name, value: (*value).map(|(v, _)| v) } - } + CfgEntry::NameValue { name, value, .. } => NameValueCfg { name: *name, value: *value }, _ => NameValueCfg { name: sym::empty, value: None }, } } @@ -886,8 +874,7 @@ pub(crate) fn extract_cfg_from_attrs<'a, I: Iterator for (feature, _) in features { cfg_info.current_cfg &= Cfg(CfgEntry::NameValue { name: sym::target_feature, - value: Some((*feature, DUMMY_SP)), - name_span: DUMMY_SP, + value: Some(*feature), span: DUMMY_SP, }); } diff --git a/src/librustdoc/clean/cfg/tests.rs b/src/librustdoc/clean/cfg/tests.rs index 4eb6c060cbd2..09316ead76ac 100644 --- a/src/librustdoc/clean/cfg/tests.rs +++ b/src/librustdoc/clean/cfg/tests.rs @@ -12,12 +12,7 @@ fn word_cfg(name: &str) -> Cfg { } fn word_cfg_e(name: &str) -> CfgEntry { - CfgEntry::NameValue { - name: Symbol::intern(name), - name_span: DUMMY_SP, - value: None, - span: DUMMY_SP, - } + CfgEntry::NameValue { name: Symbol::intern(name), value: None, span: DUMMY_SP } } fn name_value_cfg(name: &str, value: &str) -> Cfg { @@ -27,8 +22,8 @@ fn name_value_cfg(name: &str, value: &str) -> Cfg { fn name_value_cfg_e(name: &str, value: &str) -> CfgEntry { CfgEntry::NameValue { name: Symbol::intern(name), - name_span: DUMMY_SP, - value: Some((Symbol::intern(value), DUMMY_SP)), + + value: Some(Symbol::intern(value)), span: DUMMY_SP, } } diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 5e582eb61997..cc8a308688d2 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -32,7 +32,6 @@ extern crate rustc_abi; extern crate rustc_ast; extern crate rustc_ast_pretty; -extern crate rustc_attr_parsing; extern crate rustc_data_structures; extern crate rustc_driver; extern crate rustc_errors; diff --git a/src/librustdoc/passes/check_doc_cfg.rs b/src/librustdoc/passes/check_doc_cfg.rs deleted file mode 100644 index 9e7fae5e14e4..000000000000 --- a/src/librustdoc/passes/check_doc_cfg.rs +++ /dev/null @@ -1,72 +0,0 @@ -use rustc_attr_parsing::{ShouldEmit, eval_config_entry}; -use rustc_hir::attrs::AttributeKind; -use rustc_hir::def_id::LocalDefId; -use rustc_hir::{Attribute, HirId}; -use rustc_middle::ty::TyCtxt; - -use super::Pass; -use crate::clean::{Attributes, Crate, Item}; -use crate::core::DocContext; -use crate::visit::DocVisitor; - -pub(crate) const CHECK_DOC_CFG: Pass = Pass { - name: "check-doc-cfg", - run: Some(check_doc_cfg), - description: "checks `#[doc(cfg(...))]` for stability feature and unexpected cfgs", -}; - -pub(crate) fn check_doc_cfg(krate: Crate, cx: &mut DocContext<'_>) -> Crate { - let mut checker = DocCfgChecker { cx }; - checker.visit_crate(&krate); - krate -} - -struct RustdocCfgMatchesLintEmitter<'a>(TyCtxt<'a>, HirId); - -impl<'a> rustc_attr_parsing::CfgMatchesLintEmitter for RustdocCfgMatchesLintEmitter<'a> { - fn emit_span_lint( - &self, - sess: &rustc_session::Session, - lint: &'static rustc_lint::Lint, - sp: rustc_span::Span, - builtin_diag: rustc_lint_defs::BuiltinLintDiag, - ) { - self.0.node_span_lint(lint, self.1, sp, |diag| { - rustc_lint::decorate_builtin_lint(sess, Some(self.0), builtin_diag, diag) - }); - } -} - -struct DocCfgChecker<'a, 'tcx> { - cx: &'a mut DocContext<'tcx>, -} - -impl DocCfgChecker<'_, '_> { - fn check_attrs(&mut self, attrs: &Attributes, did: LocalDefId) { - for attr in &attrs.other_attrs { - let Attribute::Parsed(AttributeKind::Doc(d)) = attr else { continue }; - - for doc_cfg in &d.cfg { - let _ = eval_config_entry( - &self.cx.tcx.sess, - doc_cfg, - &RustdocCfgMatchesLintEmitter( - self.cx.tcx, - self.cx.tcx.local_def_id_to_hir_id(did), - ), - ShouldEmit::ErrorsAndLints, - ); - } - } - } -} - -impl DocVisitor<'_> for DocCfgChecker<'_, '_> { - fn visit_item(&mut self, item: &'_ Item) { - if let Some(Some(local_did)) = item.def_id().map(|did| did.as_local()) { - self.check_attrs(&item.attrs, local_did); - } - - self.visit_item_recur(item); - } -} diff --git a/src/librustdoc/passes/mod.rs b/src/librustdoc/passes/mod.rs index a1e8e7530623..18e1afaf8a24 100644 --- a/src/librustdoc/passes/mod.rs +++ b/src/librustdoc/passes/mod.rs @@ -32,9 +32,6 @@ pub(crate) use self::collect_intra_doc_links::COLLECT_INTRA_DOC_LINKS; mod check_doc_test_visibility; pub(crate) use self::check_doc_test_visibility::CHECK_DOC_TEST_VISIBILITY; -mod check_doc_cfg; -pub(crate) use self::check_doc_cfg::CHECK_DOC_CFG; - mod collect_trait_impls; pub(crate) use self::collect_trait_impls::COLLECT_TRAIT_IMPLS; @@ -75,7 +72,6 @@ pub(crate) enum Condition { /// The full list of passes. pub(crate) const PASSES: &[Pass] = &[ - CHECK_DOC_CFG, CHECK_DOC_TEST_VISIBILITY, PROPAGATE_DOC_CFG, STRIP_ALIASED_NON_LOCAL, @@ -93,7 +89,6 @@ pub(crate) const PASSES: &[Pass] = &[ pub(crate) const DEFAULT_PASSES: &[ConditionalPass] = &[ ConditionalPass::always(COLLECT_TRAIT_IMPLS), ConditionalPass::always(CHECK_DOC_TEST_VISIBILITY), - ConditionalPass::always(CHECK_DOC_CFG), ConditionalPass::always(STRIP_ALIASED_NON_LOCAL), ConditionalPass::always(PROPAGATE_DOC_CFG), ConditionalPass::new(STRIP_HIDDEN, WhenNotDocumentHidden), diff --git a/tests/rustdoc-ui/doc-cfg-2.rs b/tests/rustdoc-ui/doc-cfg-2.rs index bd6a2dc18be9..7a5d1f3e3dbb 100644 --- a/tests/rustdoc-ui/doc-cfg-2.rs +++ b/tests/rustdoc-ui/doc-cfg-2.rs @@ -12,5 +12,7 @@ // Shouldn't lint #[doc(auto_cfg(hide(windows)))] #[doc(auto_cfg(hide(feature = "windows")))] +//~^ WARN unexpected `cfg` condition name: `feature` #[doc(auto_cfg(hide(foo)))] +//~^ WARN unexpected `cfg` condition name: `foo` pub fn foo() {} diff --git a/tests/rustdoc-ui/doc-cfg-2.stderr b/tests/rustdoc-ui/doc-cfg-2.stderr index f3d67abfb8dd..1272e569897b 100644 --- a/tests/rustdoc-ui/doc-cfg-2.stderr +++ b/tests/rustdoc-ui/doc-cfg-2.stderr @@ -56,5 +56,23 @@ error: expected boolean for `#[doc(auto_cfg = ...)]` LL | #[doc(auto_cfg = "a")] | ^^^ -error: aborting due to 6 previous errors; 2 warnings emitted +warning: unexpected `cfg` condition name: `feature` + --> $DIR/doc-cfg-2.rs:14:21 + | +LL | #[doc(auto_cfg(hide(feature = "windows")))] + | ^^^^^^^^^^^^^^^^^^^ + | + = help: to expect this configuration use `--check-cfg=cfg(feature, values("windows"))` + = note: see for more information about checking conditional configuration + +warning: unexpected `cfg` condition name: `foo` + --> $DIR/doc-cfg-2.rs:16:21 + | +LL | #[doc(auto_cfg(hide(foo)))] + | ^^^ + | + = help: to expect this configuration use `--check-cfg=cfg(foo)` + = note: see for more information about checking conditional configuration + +error: aborting due to 6 previous errors; 4 warnings emitted diff --git a/tests/rustdoc-ui/doc-cfg-check-cfg.cfg_empty.stderr b/tests/rustdoc-ui/doc-cfg-check-cfg.cfg_empty.stderr index 0878f7edbf48..3f67b85900aa 100644 --- a/tests/rustdoc-ui/doc-cfg-check-cfg.cfg_empty.stderr +++ b/tests/rustdoc-ui/doc-cfg-check-cfg.cfg_empty.stderr @@ -1,8 +1,8 @@ warning: unexpected `cfg` condition name: `foo` - --> $DIR/doc-cfg-check-cfg.rs:12:12 + --> $DIR/doc-cfg-check-cfg.rs:15:11 | -LL | #![doc(cfg(foo))] - | ^^^ +LL | #[doc(cfg(foo))] + | ^^^ | = help: to expect this configuration use `--check-cfg=cfg(foo)` = note: see for more information about checking conditional configuration @@ -18,10 +18,10 @@ LL | #[doc(cfg(foo))] = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition name: `foo` - --> $DIR/doc-cfg-check-cfg.rs:15:11 + --> $DIR/doc-cfg-check-cfg.rs:12:12 | -LL | #[doc(cfg(foo))] - | ^^^ +LL | #![doc(cfg(foo))] + | ^^^ | = help: to expect this configuration use `--check-cfg=cfg(foo)` = note: see for more information about checking conditional configuration diff --git a/tests/rustdoc-ui/issues/issue-91713.stdout b/tests/rustdoc-ui/issues/issue-91713.stdout index c0cd454e8f3a..e7b8a1dccf80 100644 --- a/tests/rustdoc-ui/issues/issue-91713.stdout +++ b/tests/rustdoc-ui/issues/issue-91713.stdout @@ -1,5 +1,4 @@ Available passes for running rustdoc: - check-doc-cfg - checks `#[doc(cfg(...))]` for stability feature and unexpected cfgs check_doc_test_visibility - run various visibility-related lints on doctests propagate-doc-cfg - propagates `#[doc(cfg(...))]` to child items strip-aliased-non-local - strips all non-local private aliased items from the output @@ -15,7 +14,6 @@ calculate-doc-coverage - counts the number of items with and without documentati Default passes for rustdoc: collect-trait-impls check_doc_test_visibility - check-doc-cfg strip-aliased-non-local propagate-doc-cfg strip-hidden (when not --document-hidden-items) From 3ea946216700c1c6ede64a0d5db658419afc3017 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 10 Dec 2025 12:27:26 +0100 Subject: [PATCH 34/64] Remove `Cfg::matches` and use `eval_config_entry` instead --- src/librustdoc/clean/cfg.rs | 29 ++++------------------------- src/librustdoc/doctest/rust.rs | 3 ++- src/librustdoc/lib.rs | 1 + 3 files changed, 7 insertions(+), 26 deletions(-) diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs index 97a60c5a5098..7ab2a72d75b5 100644 --- a/src/librustdoc/clean/cfg.rs +++ b/src/librustdoc/clean/cfg.rs @@ -14,7 +14,6 @@ use rustc_hir as hir; use rustc_hir::Attribute; use rustc_hir::attrs::{self, AttributeKind, CfgEntry, CfgHideShow, HideOrShow}; use rustc_middle::ty::TyCtxt; -use rustc_session::parse::ParseSess; use rustc_span::symbol::{Symbol, sym}; use rustc_span::{DUMMY_SP, Span}; @@ -206,30 +205,6 @@ impl Cfg { Self::parse_nested(cfg, &FxHashSet::default()).map(|ret| ret.unwrap()) } - /// Checks whether the given configuration can be matched in the current session. - /// - /// Equivalent to `attr::cfg_matches`. - pub(crate) fn matches(&self, psess: &ParseSess) -> bool { - fn cfg_matches(cfg: &CfgEntry, psess: &ParseSess) -> bool { - match cfg { - CfgEntry::Bool(v, _) => *v, - CfgEntry::Not(child, _) => !cfg_matches(child, psess), - CfgEntry::All(sub_cfgs, _) => { - sub_cfgs.iter().all(|sub_cfg| cfg_matches(sub_cfg, psess)) - } - CfgEntry::Any(sub_cfgs, _) => { - sub_cfgs.iter().any(|sub_cfg| cfg_matches(sub_cfg, psess)) - } - CfgEntry::NameValue { name, value, .. } => psess.config.contains(&(*name, *value)), - CfgEntry::Version(..) => { - // FIXME: should be handled. - false - } - } - } - cfg_matches(&self.0, psess) - } - /// Renders the configuration for human display, as a short HTML description. pub(crate) fn render_short_html(&self) -> String { let mut msg = Display(&self.0, Format::ShortHtml).to_string(); @@ -320,6 +295,10 @@ impl Cfg { fn omit_preposition(&self) -> bool { matches!(self.0, CfgEntry::Bool(..)) } + + pub(crate) fn inner(&self) -> &CfgEntry { + &self.0 + } } impl ops::Not for Cfg { diff --git a/src/librustdoc/doctest/rust.rs b/src/librustdoc/doctest/rust.rs index 987e1c2ddbf9..ee1419d17d6e 100644 --- a/src/librustdoc/doctest/rust.rs +++ b/src/librustdoc/doctest/rust.rs @@ -6,6 +6,7 @@ use std::str::FromStr; use std::sync::Arc; use proc_macro2::{TokenStream, TokenTree}; +use rustc_attr_parsing::eval_config_entry; use rustc_hir::attrs::AttributeKind; use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId}; use rustc_hir::{self as hir, Attribute, CRATE_HIR_ID, intravisit}; @@ -123,7 +124,7 @@ impl HirCollector<'_> { let ast_attrs = self.tcx.hir_attrs(self.tcx.local_def_id_to_hir_id(def_id)); if let Some(ref cfg) = extract_cfg_from_attrs(ast_attrs.iter(), self.tcx, &mut CfgInfo::default()) - && !cfg.matches(&self.tcx.sess.psess) + && !eval_config_entry(&self.tcx.sess, cfg.inner()).as_bool() { return; } diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index cc8a308688d2..5e582eb61997 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -32,6 +32,7 @@ extern crate rustc_abi; extern crate rustc_ast; extern crate rustc_ast_pretty; +extern crate rustc_attr_parsing; extern crate rustc_data_structures; extern crate rustc_driver; extern crate rustc_errors; From 9fdec8194e6045133629d899bc4b7048d00311d4 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 10 Dec 2025 12:35:17 +0100 Subject: [PATCH 35/64] Fix new merge conflict --- .../parser/attribute/attr-unquoted-ident.rs | 5 ++++- .../attribute/attr-unquoted-ident.stderr | 19 ++++++++++++++++++- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/tests/ui/parser/attribute/attr-unquoted-ident.rs b/tests/ui/parser/attribute/attr-unquoted-ident.rs index 152448bf8a0f..6207662a6e19 100644 --- a/tests/ui/parser/attribute/attr-unquoted-ident.rs +++ b/tests/ui/parser/attribute/attr-unquoted-ident.rs @@ -26,7 +26,10 @@ fn main() { macro_rules! make { ($name:ident) => { #[doc(alias = $name)] pub struct S; } - //~^ ERROR: expected unsuffixed literal, found identifier `nickname` + //~^ ERROR: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found expression + //~| NOTE: expressions are not allowed here + //~| HELP: surround the identifier with quotation marks to make it into a string literal } make!(nickname); //~ NOTE: in this expansion +//~^ NOTE in this expansion of make diff --git a/tests/ui/parser/attribute/attr-unquoted-ident.stderr b/tests/ui/parser/attribute/attr-unquoted-ident.stderr index 00fb539f8a86..48ca499ba78f 100644 --- a/tests/ui/parser/attribute/attr-unquoted-ident.stderr +++ b/tests/ui/parser/attribute/attr-unquoted-ident.stderr @@ -20,14 +20,31 @@ help: surround the identifier with quotation marks to make it into a string lite LL | #[cfg(key="foo bar baz")] | + + +error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found expression + --> $DIR/attr-unquoted-ident.rs:18:15 + | +LL | #[cfg(key=foo 1 bar 2.0 baz.)] + | ^^^ expressions are not allowed here + | +help: surround the identifier with quotation marks to make it into a string literal + | +LL | #[cfg(key="foo 1 bar 2.0 baz.")] + | + + + +error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found expression + --> $DIR/attr-unquoted-ident.rs:28:38 | LL | ($name:ident) => { #[doc(alias = $name)] pub struct S; } - | ^^^^^ + | ^^^^^ expressions are not allowed here ... LL | make!(nickname); | --------------- in this macro invocation | = note: this error originates in the macro `make` (in Nightly builds, run with -Z macro-backtrace for more info) +help: surround the identifier with quotation marks to make it into a string literal + | +LL | ($name:ident) => { #[doc(alias = "$name")] pub struct S; } + | + + error: aborting due to 4 previous errors From 787886861746f88af4b502e8691099223494b51c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Tue, 4 Nov 2025 13:42:30 +0000 Subject: [PATCH 36/64] don't normalize where-clauses in wfcheck --- compiler/rustc_hir_analysis/src/check/wfcheck.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 0e8859facf58..0a6be9aa4b2f 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -1147,17 +1147,16 @@ fn check_trait(tcx: TyCtxt<'_>, item: &hir::Item<'_>) -> Result<(), ErrorGuarant /// /// Assuming the defaults are used, check that all predicates (bounds on the /// assoc type and where clauses on the trait) hold. -fn check_associated_type_bounds(wfcx: &WfCheckingCtxt<'_, '_>, item: ty::AssocItem, span: Span) { +fn check_associated_type_bounds(wfcx: &WfCheckingCtxt<'_, '_>, item: ty::AssocItem, _span: Span) { let bounds = wfcx.tcx().explicit_item_bounds(item.def_id); debug!("check_associated_type_bounds: bounds={:?}", bounds); let wf_obligations = bounds.iter_identity_copied().flat_map(|(bound, bound_span)| { - let normalized_bound = wfcx.normalize(span, None, bound); traits::wf::clause_obligations( wfcx.infcx, wfcx.param_env, wfcx.body_def_id, - normalized_bound, + bound, bound_span, ) }); @@ -1525,7 +1524,6 @@ pub(super) fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, def_id: assert_eq!(predicates.predicates.len(), predicates.spans.len()); let wf_obligations = predicates.into_iter().flat_map(|(p, sp)| { - let p = wfcx.normalize(sp, None, p); traits::wf::clause_obligations(infcx, wfcx.param_env, wfcx.body_def_id, p, sp) }); let obligations: Vec<_> = wf_obligations.chain(default_obligations).collect(); From fa775988245e635b20278551ecdc334193d754fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Tue, 4 Nov 2025 14:04:02 +0000 Subject: [PATCH 37/64] update tests and bless expectations just to show the diagnostics impact --- .../assoc-const-eq-bound-var-in-ty-not-wf.rs | 3 +- ...soc-const-eq-bound-var-in-ty-not-wf.stderr | 15 +--- tests/ui/associated-types/issue-38821.rs | 12 +-- tests/ui/associated-types/issue-38821.stderr | 85 ++++++++++++------- .../in-trait/refine-resolution-errors.rs | 1 + .../in-trait/refine-resolution-errors.stderr | 10 ++- .../ui/lifetimes/issue-76168-hr-outlives-3.rs | 3 - .../issue-76168-hr-outlives-3.stderr | 28 +----- tests/ui/methods/filter-relevant-fn-bounds.rs | 2 - .../methods/filter-relevant-fn-bounds.stderr | 32 ++----- .../regions-normalize-in-where-clause-list.rs | 1 + ...ions-normalize-in-where-clause-list.stderr | 27 +++++- .../regions-enum-not-wf.rs | 1 + .../regions-enum-not-wf.stderr | 16 +++- tests/ui/traits/deep-norm-pending.rs | 4 +- tests/ui/traits/deep-norm-pending.stderr | 20 +++-- 16 files changed, 137 insertions(+), 123 deletions(-) diff --git a/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty-not-wf.rs b/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty-not-wf.rs index 5232b895803e..8334e67ae9a1 100644 --- a/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty-not-wf.rs +++ b/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty-not-wf.rs @@ -21,8 +21,7 @@ fn take( K = { () } >, ) {} -//~^^^^^ ERROR implementation of `Project` is not general enough -//~^^^^ ERROR higher-ranked subtype error +//~^^^ ERROR higher-ranked subtype error //~| ERROR higher-ranked subtype error trait Project { type Out; } diff --git a/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty-not-wf.stderr b/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty-not-wf.stderr index a0329e2b15d1..9fac60763dae 100644 --- a/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty-not-wf.stderr +++ b/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty-not-wf.stderr @@ -12,18 +12,5 @@ LL | K = { () } | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: implementation of `Project` is not general enough - --> $DIR/assoc-const-eq-bound-var-in-ty-not-wf.rs:19:13 - | -LL | _: impl Trait< - | _____________^ -LL | | < fn(&'a str) -> &'a str as Project>::Out as Discard>::Out, -LL | | K = { () } -LL | | >, - | |_____^ implementation of `Project` is not general enough - | - = note: `Project` would have to be implemented for the type `for<'a> fn(&'a str) -> &'a str` - = note: ...but `Project` is actually implemented for the type `fn(&'0 str) -> &'0 str`, for some specific lifetime `'0` - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors diff --git a/tests/ui/associated-types/issue-38821.rs b/tests/ui/associated-types/issue-38821.rs index 60d3b224a5bf..5212bc886f0d 100644 --- a/tests/ui/associated-types/issue-38821.rs +++ b/tests/ui/associated-types/issue-38821.rs @@ -32,16 +32,16 @@ pub trait Column: Expression {} //~| ERROR the trait bound `::SqlType: NotNull` is not satisfied //~| ERROR the trait bound `::SqlType: NotNull` is not satisfied //~| ERROR the trait bound `::SqlType: NotNull` is not satisfied +//~| ERROR the trait bound `::SqlType: NotNull` is not satisfied +//~| ERROR the trait bound `::SqlType: NotNull` is not satisfied +//~| ERROR the trait bound `::SqlType: NotNull` is not satisfied +//~| ERROR the trait bound `::SqlType: NotNull` is not satisfied +//~| ERROR the trait bound `::SqlType: NotNull` is not satisfied pub enum ColumnInsertValue where //~^ ERROR the trait bound `::SqlType: NotNull` is not satisfied Col: Column, Expr: Expression::Nullable>, -//~^ ERROR the trait bound `::SqlType: NotNull` is not satisfied -//~| ERROR the trait bound `::SqlType: NotNull` is not satisfied -//~| ERROR the trait bound `::SqlType: NotNull` is not satisfied -//~| ERROR the trait bound `::SqlType: NotNull` is not satisfied -//~| ERROR the trait bound `::SqlType: NotNull` is not satisfied -//~| ERROR the trait bound `::SqlType: NotNull` is not satisfied +//~^ ERROR the trait bound `::SqlType: IntoNullable` is not satisfied { Expression(Col, Expr), Default(Col), diff --git a/tests/ui/associated-types/issue-38821.stderr b/tests/ui/associated-types/issue-38821.stderr index b03a3cf7f47e..01329f69c3be 100644 --- a/tests/ui/associated-types/issue-38821.stderr +++ b/tests/ui/associated-types/issue-38821.stderr @@ -1,5 +1,5 @@ error[E0277]: the trait bound `::SqlType: NotNull` is not satisfied - --> $DIR/issue-38821.rs:35:1 + --> $DIR/issue-38821.rs:40:1 | LL | pub enum ColumnInsertValue where | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `NotNull` is not implemented for `::SqlType` @@ -16,8 +16,8 @@ help: consider extending the `where` clause, but there might be an alternative b LL | Expr: Expression::Nullable>, ::SqlType: NotNull | +++++++++++++++++++++++++++++++++++++ -error[E0277]: the trait bound `::SqlType: NotNull` is not satisfied - --> $DIR/issue-38821.rs:38:22 +error[E0277]: the trait bound `::SqlType: IntoNullable` is not satisfied + --> $DIR/issue-38821.rs:43:22 | LL | Expr: Expression::Nullable>, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `NotNull` is not implemented for `::SqlType` @@ -82,10 +82,36 @@ LL | impl IntoNullable for T { = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0277]: the trait bound `::SqlType: NotNull` is not satisfied - --> $DIR/issue-38821.rs:38:22 + --> $DIR/issue-38821.rs:23:10 | +LL | #[derive(Debug, Copy, Clone)] + | ^^^^^ the trait `NotNull` is not implemented for `::SqlType` + | +note: required for `::SqlType` to implement `IntoNullable` + --> $DIR/issue-38821.rs:9:18 + | +LL | impl IntoNullable for T { + | ------- ^^^^^^^^^^^^ ^ + | | + | unsatisfied trait bound introduced here +note: required for `ColumnInsertValue` to implement `Debug` + --> $DIR/issue-38821.rs:23:10 + | +LL | #[derive(Debug, Copy, Clone)] + | ^^^^^ +... LL | Expr: Expression::Nullable>, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `NotNull` is not implemented for `::SqlType` + | ------------------------------------------------ unsatisfied trait bound introduced in this `derive` macro +help: consider further restricting the associated type + | +LL | Expr: Expression::Nullable>, ::SqlType: NotNull, + | +++++++++++++++++++++++++++++++++++++++ + +error[E0277]: the trait bound `::SqlType: NotNull` is not satisfied + --> $DIR/issue-38821.rs:23:17 + | +LL | #[derive(Debug, Copy, Clone)] + | ^^^^ the trait `NotNull` is not implemented for `::SqlType` | note: required for `::SqlType` to implement `IntoNullable` --> $DIR/issue-38821.rs:9:18 @@ -112,24 +138,14 @@ LL | impl IntoNullable for T { | ------- ^^^^^^^^^^^^ ^ | | | unsatisfied trait bound introduced here -help: consider further restricting the associated type - | -LL | Expr: Expression::Nullable>, ::SqlType: NotNull, - | +++++++++++++++++++++++++++++++++++++++ - -error[E0277]: the trait bound `::SqlType: NotNull` is not satisfied - --> $DIR/issue-38821.rs:38:22 +note: required for `ColumnInsertValue` to implement `Copy` + --> $DIR/issue-38821.rs:23:17 | +LL | #[derive(Debug, Copy, Clone)] + | ^^^^ +... LL | Expr: Expression::Nullable>, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `NotNull` is not implemented for `::SqlType` - | -note: required for `::SqlType` to implement `IntoNullable` - --> $DIR/issue-38821.rs:9:18 - | -LL | impl IntoNullable for T { - | ------- ^^^^^^^^^^^^ ^ - | | - | unsatisfied trait bound introduced here + | ------------------------------------------------ unsatisfied trait bound introduced in this `derive` macro help: consider further restricting the associated type | LL | Expr: Expression::Nullable>, ::SqlType: NotNull, @@ -183,10 +199,10 @@ LL | impl IntoNullable for T { = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0277]: the trait bound `::SqlType: NotNull` is not satisfied - --> $DIR/issue-38821.rs:38:22 + --> $DIR/issue-38821.rs:23:23 | -LL | Expr: Expression::Nullable>, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `NotNull` is not implemented for `::SqlType` +LL | #[derive(Debug, Copy, Clone)] + | ^^^^^ the trait `NotNull` is not implemented for `::SqlType` | note: required for `::SqlType` to implement `IntoNullable` --> $DIR/issue-38821.rs:9:18 @@ -195,6 +211,14 @@ LL | impl IntoNullable for T { | ------- ^^^^^^^^^^^^ ^ | | | unsatisfied trait bound introduced here +note: required for `ColumnInsertValue` to implement `Clone` + --> $DIR/issue-38821.rs:23:23 + | +LL | #[derive(Debug, Copy, Clone)] + | ^^^^^ +... +LL | Expr: Expression::Nullable>, + | ------------------------------------------------ unsatisfied trait bound introduced in this `derive` macro help: consider further restricting the associated type | LL | Expr: Expression::Nullable>, ::SqlType: NotNull, @@ -216,10 +240,10 @@ LL | impl IntoNullable for T { = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0277]: the trait bound `::SqlType: NotNull` is not satisfied - --> $DIR/issue-38821.rs:38:22 + --> $DIR/issue-38821.rs:23:10 | -LL | Expr: Expression::Nullable>, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `NotNull` is not implemented for `::SqlType` +LL | #[derive(Debug, Copy, Clone)] + | ^^^^^ the trait `NotNull` is not implemented for `::SqlType` | note: required for `::SqlType` to implement `IntoNullable` --> $DIR/issue-38821.rs:9:18 @@ -245,10 +269,10 @@ LL | impl IntoNullable for T { = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0277]: the trait bound `::SqlType: NotNull` is not satisfied - --> $DIR/issue-38821.rs:38:22 + --> $DIR/issue-38821.rs:23:23 | -LL | Expr: Expression::Nullable>, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `NotNull` is not implemented for `::SqlType` +LL | #[derive(Debug, Copy, Clone)] + | ^^^^^ the trait `NotNull` is not implemented for `::SqlType` | note: required for `::SqlType` to implement `IntoNullable` --> $DIR/issue-38821.rs:9:18 @@ -257,7 +281,6 @@ LL | impl IntoNullable for T { | ------- ^^^^^^^^^^^^ ^ | | | unsatisfied trait bound introduced here - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0277]: the trait bound `::SqlType: NotNull` is not satisfied --> $DIR/issue-38821.rs:23:10 diff --git a/tests/ui/impl-trait/in-trait/refine-resolution-errors.rs b/tests/ui/impl-trait/in-trait/refine-resolution-errors.rs index 8433fb72b5e0..fa4ce66d54e6 100644 --- a/tests/ui/impl-trait/in-trait/refine-resolution-errors.rs +++ b/tests/ui/impl-trait/in-trait/refine-resolution-errors.rs @@ -14,6 +14,7 @@ impl Mirror for () { pub trait First { async fn first() -> <() as Mirror>::Assoc; + //~^ ERROR type annotations needed } impl First for () { diff --git a/tests/ui/impl-trait/in-trait/refine-resolution-errors.stderr b/tests/ui/impl-trait/in-trait/refine-resolution-errors.stderr index fd53c9fef443..af71e52b87d7 100644 --- a/tests/ui/impl-trait/in-trait/refine-resolution-errors.stderr +++ b/tests/ui/impl-trait/in-trait/refine-resolution-errors.stderr @@ -28,7 +28,13 @@ help: consider relaxing the implicit `Sized` restriction LL | type Assoc: ?Sized; | ++++++++ -error: aborting due to 2 previous errors +error[E0282]: type annotations needed + --> $DIR/refine-resolution-errors.rs:16:25 + | +LL | async fn first() -> <() as Mirror>::Assoc; + | ^^^^^^^^^^^^^^^^^^^^^ cannot infer type -Some errors have detailed explanations: E0207, E0277. +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0207, E0277, E0282. For more information about an error, try `rustc --explain E0207`. diff --git a/tests/ui/lifetimes/issue-76168-hr-outlives-3.rs b/tests/ui/lifetimes/issue-76168-hr-outlives-3.rs index d6fda129e363..85eeb5d4c901 100644 --- a/tests/ui/lifetimes/issue-76168-hr-outlives-3.rs +++ b/tests/ui/lifetimes/issue-76168-hr-outlives-3.rs @@ -10,9 +10,6 @@ async fn wrapper(f: F) where F:, for<'a> >::Output: Future + 'a, -//~^ ERROR: expected a `FnOnce(&'a mut i32)` closure, found `i32` -//~| ERROR: expected a `FnOnce(&'a mut i32)` closure, found `i32` -//~| ERROR: expected a `FnOnce(&'a mut i32)` closure, found `i32` { //~^ ERROR: expected a `FnOnce(&'a mut i32)` closure, found `i32` let mut i = 41; diff --git a/tests/ui/lifetimes/issue-76168-hr-outlives-3.stderr b/tests/ui/lifetimes/issue-76168-hr-outlives-3.stderr index bb8e84724257..6da9f7380d59 100644 --- a/tests/ui/lifetimes/issue-76168-hr-outlives-3.stderr +++ b/tests/ui/lifetimes/issue-76168-hr-outlives-3.stderr @@ -9,30 +9,6 @@ LL | | for<'a> >::Output: Future + 'a | = help: the trait `for<'a> FnOnce(&'a mut i32)` is not implemented for `i32` -error[E0277]: expected a `FnOnce(&'a mut i32)` closure, found `i32` - --> $DIR/issue-76168-hr-outlives-3.rs:12:50 - | -LL | for<'a> >::Output: Future + 'a, - | ^^^^^^^^^^^^^^^^^^^ expected an `FnOnce(&'a mut i32)` closure, found `i32` - | - = help: the trait `for<'a> FnOnce(&'a mut i32)` is not implemented for `i32` - -error[E0277]: expected a `FnOnce(&'a mut i32)` closure, found `i32` - --> $DIR/issue-76168-hr-outlives-3.rs:12:57 - | -LL | for<'a> >::Output: Future + 'a, - | ^^^^^^^^^^^ expected an `FnOnce(&'a mut i32)` closure, found `i32` - | - = help: the trait `for<'a> FnOnce(&'a mut i32)` is not implemented for `i32` - -error[E0277]: expected a `FnOnce(&'a mut i32)` closure, found `i32` - --> $DIR/issue-76168-hr-outlives-3.rs:12:72 - | -LL | for<'a> >::Output: Future + 'a, - | ^^ expected an `FnOnce(&'a mut i32)` closure, found `i32` - | - = help: the trait `for<'a> FnOnce(&'a mut i32)` is not implemented for `i32` - error[E0277]: expected a `FnOnce(&'a mut i32)` closure, found `i32` --> $DIR/issue-76168-hr-outlives-3.rs:6:26 | @@ -51,7 +27,7 @@ LL | async fn wrapper(f: F) = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0277]: expected a `FnOnce(&'a mut i32)` closure, found `i32` - --> $DIR/issue-76168-hr-outlives-3.rs:16:1 + --> $DIR/issue-76168-hr-outlives-3.rs:13:1 | LL | / { LL | | @@ -62,6 +38,6 @@ LL | | } | = help: the trait `for<'a> FnOnce(&'a mut i32)` is not implemented for `i32` -error: aborting due to 7 previous errors +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/methods/filter-relevant-fn-bounds.rs b/tests/ui/methods/filter-relevant-fn-bounds.rs index 6233c9db53a0..7945eaa0daa2 100644 --- a/tests/ui/methods/filter-relevant-fn-bounds.rs +++ b/tests/ui/methods/filter-relevant-fn-bounds.rs @@ -9,8 +9,6 @@ impl Wrapper { //~^ ERROR the trait bound `for<'a> F: Output<'a>` is not satisfied where F: for<'a> FnOnce(>::Type), - //~^ ERROR the trait bound `for<'a> F: Output<'a>` is not satisfied - //~| ERROR the trait bound `for<'a> F: Output<'a>` is not satisfied { } } diff --git a/tests/ui/methods/filter-relevant-fn-bounds.stderr b/tests/ui/methods/filter-relevant-fn-bounds.stderr index 82103e62ddfe..4efe40ae0903 100644 --- a/tests/ui/methods/filter-relevant-fn-bounds.stderr +++ b/tests/ui/methods/filter-relevant-fn-bounds.stderr @@ -12,37 +12,15 @@ help: consider further restricting type parameter `F` with trait `Output` LL | F: for<'a> FnOnce(>::Type) + for<'a> Output<'a>, | ++++++++++++++++++++ -error[E0277]: the trait bound `for<'a> F: Output<'a>` is not satisfied - --> $DIR/filter-relevant-fn-bounds.rs:11:12 - | -LL | F: for<'a> FnOnce(>::Type), - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'a> Output<'a>` is not implemented for `F` - | -help: consider further restricting type parameter `F` with trait `Output` - | -LL | F: for<'a> FnOnce(>::Type) + for<'a> Output<'a>, - | ++++++++++++++++++++ - -error[E0277]: the trait bound `for<'a> F: Output<'a>` is not satisfied - --> $DIR/filter-relevant-fn-bounds.rs:11:20 - | -LL | F: for<'a> FnOnce(>::Type), - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'a> Output<'a>` is not implemented for `F` - | -help: consider further restricting type parameter `F` with trait `Output` - | -LL | F: for<'a> FnOnce(>::Type) + for<'a> Output<'a>, - | ++++++++++++++++++++ - -error[E0277]: expected a `FnOnce(<{closure@$DIR/filter-relevant-fn-bounds.rs:20:34: 20:41} as Output<'a>>::Type)` closure, found `{closure@$DIR/filter-relevant-fn-bounds.rs:20:34: 20:41}` - --> $DIR/filter-relevant-fn-bounds.rs:20:34 +error[E0277]: expected a `FnOnce(<{closure@$DIR/filter-relevant-fn-bounds.rs:18:34: 18:41} as Output<'a>>::Type)` closure, found `{closure@$DIR/filter-relevant-fn-bounds.rs:18:34: 18:41}` + --> $DIR/filter-relevant-fn-bounds.rs:18:34 | LL | wrapper.do_something_wrapper(|value| ()); - | -------------------- ^^^^^^^^^^ expected an `FnOnce(<{closure@$DIR/filter-relevant-fn-bounds.rs:20:34: 20:41} as Output<'a>>::Type)` closure, found `{closure@$DIR/filter-relevant-fn-bounds.rs:20:34: 20:41}` + | -------------------- ^^^^^^^^^^ expected an `FnOnce(<{closure@$DIR/filter-relevant-fn-bounds.rs:18:34: 18:41} as Output<'a>>::Type)` closure, found `{closure@$DIR/filter-relevant-fn-bounds.rs:18:34: 18:41}` | | | required by a bound introduced by this call | - = help: the trait `for<'a> Output<'a>` is not implemented for closure `{closure@$DIR/filter-relevant-fn-bounds.rs:20:34: 20:41}` + = help: the trait `for<'a> Output<'a>` is not implemented for closure `{closure@$DIR/filter-relevant-fn-bounds.rs:18:34: 18:41}` help: this trait has no implementations, consider adding one --> $DIR/filter-relevant-fn-bounds.rs:1:1 | @@ -57,6 +35,6 @@ LL | fn do_something_wrapper(self, _: F) LL | F: for<'a> FnOnce(>::Type), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Wrapper::do_something_wrapper` -error: aborting due to 4 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/regions/regions-normalize-in-where-clause-list.rs b/tests/ui/regions/regions-normalize-in-where-clause-list.rs index 9b046e6baed6..bcc5da406b4e 100644 --- a/tests/ui/regions/regions-normalize-in-where-clause-list.rs +++ b/tests/ui/regions/regions-normalize-in-where-clause-list.rs @@ -25,6 +25,7 @@ fn bar<'a, 'b>() where <() as Project<'a, 'b>>::Item: Eq, //~^ ERROR cannot infer + //~| ERROR cannot infer { } diff --git a/tests/ui/regions/regions-normalize-in-where-clause-list.stderr b/tests/ui/regions/regions-normalize-in-where-clause-list.stderr index 9a5c9ae53de3..1a20055836ac 100644 --- a/tests/ui/regions/regions-normalize-in-where-clause-list.stderr +++ b/tests/ui/regions/regions-normalize-in-where-clause-list.stderr @@ -22,6 +22,31 @@ LL | <() as Project<'a, 'b>>::Item: Eq, = note: expected `Project<'a, 'b>` found `Project<'_, '_>` -error: aborting due to 1 previous error +error[E0803]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements + --> $DIR/regions-normalize-in-where-clause-list.rs:26:36 + | +LL | <() as Project<'a, 'b>>::Item: Eq, + | ^^ + | +note: first, the lifetime cannot outlive the lifetime `'a` as defined here... + --> $DIR/regions-normalize-in-where-clause-list.rs:24:8 + | +LL | fn bar<'a, 'b>() + | ^^ +note: ...but the lifetime must also be valid for the lifetime `'b` as defined here... + --> $DIR/regions-normalize-in-where-clause-list.rs:24:12 + | +LL | fn bar<'a, 'b>() + | ^^ +note: ...so that the types are compatible + --> $DIR/regions-normalize-in-where-clause-list.rs:26:36 + | +LL | <() as Project<'a, 'b>>::Item: Eq, + | ^^ + = note: expected `Project<'a, 'b>` + found `Project<'_, '_>` + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0803`. diff --git a/tests/ui/rfcs/rfc-2093-infer-outlives/regions-enum-not-wf.rs b/tests/ui/rfcs/rfc-2093-infer-outlives/regions-enum-not-wf.rs index 038f53034ab0..c5e9d147d567 100644 --- a/tests/ui/rfcs/rfc-2093-infer-outlives/regions-enum-not-wf.rs +++ b/tests/ui/rfcs/rfc-2093-infer-outlives/regions-enum-not-wf.rs @@ -34,6 +34,7 @@ enum RefIndirect<'a, T> { enum RefDouble<'a, 'b, T> { RefDoubleVariant1(&'a RequireOutlives<'b, T>), //~^ ERROR the parameter type `T` may not live long enough [E0309] + //~| ERROR the parameter type `T` may not live long enough [E0309] } fn main() {} diff --git a/tests/ui/rfcs/rfc-2093-infer-outlives/regions-enum-not-wf.stderr b/tests/ui/rfcs/rfc-2093-infer-outlives/regions-enum-not-wf.stderr index 5b605f3eef56..2799164bbda2 100644 --- a/tests/ui/rfcs/rfc-2093-infer-outlives/regions-enum-not-wf.stderr +++ b/tests/ui/rfcs/rfc-2093-infer-outlives/regions-enum-not-wf.stderr @@ -38,6 +38,20 @@ help: consider adding an explicit lifetime bound LL | enum RefDouble<'a, 'b, T: 'b> { | ++++ -error: aborting due to 3 previous errors +error[E0309]: the parameter type `T` may not live long enough + --> $DIR/regions-enum-not-wf.rs:35:23 + | +LL | enum RefDouble<'a, 'b, T> { + | -- the parameter type `T` must be valid for the lifetime `'b` as defined here... +LL | RefDoubleVariant1(&'a RequireOutlives<'b, T>), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: consider adding an explicit lifetime bound + | +LL | enum RefDouble<'a, 'b, T: 'b> { + | ++++ + +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0309`. diff --git a/tests/ui/traits/deep-norm-pending.rs b/tests/ui/traits/deep-norm-pending.rs index d6c498dcf2bd..9b1ec522bef3 100644 --- a/tests/ui/traits/deep-norm-pending.rs +++ b/tests/ui/traits/deep-norm-pending.rs @@ -7,11 +7,11 @@ trait Bar { //~^ ERROR the trait bound `T: Foo` is not satisfied } impl Bar for T -//~^ ERROR the trait bound `T: Foo` is not satisfied +//~^ ERROR the trait bound `T: Bar` is not satisfied +//~| ERROR the trait bound `T: Foo` is not satisfied where ::Assoc: Sized, //~^ ERROR the trait bound `T: Foo` is not satisfied - //~| ERROR the trait bound `T: Foo` is not satisfied { fn method() {} //~^ ERROR the trait bound `T: Foo` is not satisfied diff --git a/tests/ui/traits/deep-norm-pending.stderr b/tests/ui/traits/deep-norm-pending.stderr index c1d6120c390d..f2b59748ced9 100644 --- a/tests/ui/traits/deep-norm-pending.stderr +++ b/tests/ui/traits/deep-norm-pending.stderr @@ -3,6 +3,7 @@ error[E0277]: the trait bound `T: Foo` is not satisfied | LL | / impl Bar for T LL | | +LL | | LL | | where LL | | ::Assoc: Sized, | |_____________________________^ the trait `Foo` is not implemented for `T` @@ -85,12 +86,20 @@ help: consider further restricting type parameter `T` with trait `Foo` LL | ::Assoc: Sized, T: Foo | ++++++ -error[E0277]: the trait bound `T: Foo` is not satisfied - --> $DIR/deep-norm-pending.rs:12:24 +error[E0277]: the trait bound `T: Bar` is not satisfied + --> $DIR/deep-norm-pending.rs:9:17 | +LL | impl Bar for T + | ^ the trait `Foo` is not implemented for `T` + | +note: required for `T` to implement `Bar` + --> $DIR/deep-norm-pending.rs:9:9 + | +LL | impl Bar for T + | ^^^ ^ +... LL | ::Assoc: Sized, - | ^^^^^ the trait `Foo` is not implemented for `T` - | + | ----- unsatisfied trait bound introduced here help: consider further restricting type parameter `T` with trait `Foo` | LL | ::Assoc: Sized, T: Foo @@ -109,12 +118,11 @@ LL | ::Assoc: Sized, T: Foo | ++++++ error[E0277]: the trait bound `T: Foo` is not satisfied - --> $DIR/deep-norm-pending.rs:12:24 + --> $DIR/deep-norm-pending.rs:13:24 | LL | ::Assoc: Sized, | ^^^^^ the trait `Foo` is not implemented for `T` | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` help: consider further restricting type parameter `T` with trait `Foo` | LL | ::Assoc: Sized, T: Foo From cdf43ad5ef5986b42170cba38ce03c0f3e81c0e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Wed, 26 Nov 2025 15:24:07 +0000 Subject: [PATCH 38/64] add test from modcholesky breakage --- .../wf/wf-where-clauses-pre-normalization.rs | 20 +++++++++++++++++++ .../wf-where-clauses-pre-normalization.stderr | 17 ++++++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 tests/ui/wf/wf-where-clauses-pre-normalization.rs create mode 100644 tests/ui/wf/wf-where-clauses-pre-normalization.stderr diff --git a/tests/ui/wf/wf-where-clauses-pre-normalization.rs b/tests/ui/wf/wf-where-clauses-pre-normalization.rs new file mode 100644 index 000000000000..16c102f1faef --- /dev/null +++ b/tests/ui/wf/wf-where-clauses-pre-normalization.rs @@ -0,0 +1,20 @@ +// This is a test, extracted from `modcholesky`, that used to pass wfcheck because we checked +// well-formedness of where-clauses *after* normalization. We generally want to move to always check +// WF pre-normalization. + +pub struct View(A); +pub trait Data { + type Elem; +} +impl<'a, A> Data for View<&'a A> { + type Elem = A; +} + +pub fn repro<'a, T>() +where + as Data>::Elem: Sized, + //~^ ERROR: the parameter type `T` may not live long enough +{ +} + +fn main() {} diff --git a/tests/ui/wf/wf-where-clauses-pre-normalization.stderr b/tests/ui/wf/wf-where-clauses-pre-normalization.stderr new file mode 100644 index 000000000000..a7836cae5db2 --- /dev/null +++ b/tests/ui/wf/wf-where-clauses-pre-normalization.stderr @@ -0,0 +1,17 @@ +error[E0309]: the parameter type `T` may not live long enough + --> $DIR/wf-where-clauses-pre-normalization.rs:15:34 + | +LL | pub fn repro<'a, T>() + | -- the parameter type `T` must be valid for the lifetime `'a` as defined here... +LL | where +LL | as Data>::Elem: Sized, + | ^^^^^ ...so that the reference type `&'a T` does not outlive the data it points at + | +help: consider adding an explicit lifetime bound + | +LL | pub fn repro<'a, T: 'a>() + | ++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0309`. From 99f7e785c5276bd9ec6014c97a5688e2283953de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Wed, 26 Nov 2025 15:45:48 +0000 Subject: [PATCH 39/64] mark crash test as requiring debug-assertions --- tests/crashes/133613.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/crashes/133613.rs b/tests/crashes/133613.rs index f01780d7cf42..066c50b49477 100644 --- a/tests/crashes/133613.rs +++ b/tests/crashes/133613.rs @@ -1,3 +1,4 @@ +//@ needs-rustc-debug-assertions //@ known-bug: #133613 struct Wrapper<'a>(); From 4d697d243302066fcb5cb6a9daacf7e6cdc891c7 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 10 Dec 2025 15:16:41 +0100 Subject: [PATCH 40/64] Remove "tidy" tool for `tests/rustdoc` testsuite --- src/tools/compiletest/src/common.rs | 9 - src/tools/compiletest/src/executor.rs | 9 - src/tools/compiletest/src/lib.rs | 28 +-- src/tools/compiletest/src/runtest.rs | 164 +----------------- .../compiletest/src/runtest/compute_diff.rs | 57 ------ src/tools/compiletest/src/runtest/rustdoc.rs | 4 +- src/tools/compiletest/src/rustdoc_gui_test.rs | 2 - 7 files changed, 8 insertions(+), 265 deletions(-) diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index 02b93593cbbd..ddbe8601de20 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -9,7 +9,6 @@ use camino::{Utf8Path, Utf8PathBuf}; use semver::Version; use crate::edition::Edition; -use crate::executor::ColorConfig; use crate::fatal; use crate::util::{Utf8PathBufExt, add_dylib_path, string_enum}; @@ -597,11 +596,6 @@ pub struct Config { /// FIXME: this is *way* too coarse; the user can't select *which* info to verbosely dump. pub verbose: bool, - /// Whether to use colors in test output. - /// - /// Note: the exact control mechanism is delegated to [`colored`]. - pub color: ColorConfig, - /// Where to find the remote test client process, if we're using it. /// /// Note: this is *only* used for target platform executables created by `run-make` test @@ -623,9 +617,6 @@ pub struct Config { /// created in `$test_suite_build_root/rustfix_missing_coverage.txt` pub rustfix_coverage: bool, - /// Whether to run `tidy` (html-tidy) when a rustdoc test fails. - pub has_html_tidy: bool, - /// Whether to run `enzyme` autodiff tests. pub has_enzyme: bool, diff --git a/src/tools/compiletest/src/executor.rs b/src/tools/compiletest/src/executor.rs index 4dd4b1f85aaa..c800d11d6b2f 100644 --- a/src/tools/compiletest/src/executor.rs +++ b/src/tools/compiletest/src/executor.rs @@ -341,15 +341,6 @@ pub(crate) struct CollectedTestDesc { pub(crate) should_fail: ShouldFail, } -/// Whether console output should be colored or not. -#[derive(Copy, Clone, Default, Debug)] -pub enum ColorConfig { - #[default] - AutoColor, - AlwaysColor, - NeverColor, -} - /// Tests with `//@ should-fail` are tests of compiletest itself, and should /// be reported as successful if and only if they would have _failed_. #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs index ff4cd81d33ff..7c237102ed84 100644 --- a/src/tools/compiletest/src/lib.rs +++ b/src/tools/compiletest/src/lib.rs @@ -24,7 +24,6 @@ use core::panic; use std::collections::HashSet; use std::fmt::Write; use std::io::{self, ErrorKind}; -use std::process::{Command, Stdio}; use std::sync::{Arc, OnceLock}; use std::time::SystemTime; use std::{env, fs, vec}; @@ -43,7 +42,7 @@ use crate::common::{ }; use crate::directives::{AuxProps, DirectivesCache, FileDirectives}; use crate::edition::parse_edition; -use crate::executor::{CollectedTest, ColorConfig}; +use crate::executor::CollectedTest; /// Creates the `Config` instance for this invocation of compiletest. /// @@ -136,8 +135,9 @@ fn parse_config(args: Vec) -> Config { "overwrite stderr/stdout files instead of complaining about a mismatch", ) .optflag("", "fail-fast", "stop as soon as possible after any test fails") - .optopt("", "color", "coloring: auto, always, never", "WHEN") .optopt("", "target", "the target to build for", "TARGET") + // FIXME: Should be removed once `bootstrap` will be updated to not use this option. + .optopt("", "color", "coloring: auto, always, never", "WHEN") .optopt("", "host", "the host to build for", "HOST") .optopt("", "cdb", "path to CDB to use for CDB debuginfo tests", "PATH") .optopt("", "gdb", "path to GDB to use for GDB debuginfo tests", "PATH") @@ -276,12 +276,6 @@ fn parse_config(args: Vec) -> Config { let lldb = matches.opt_str("lldb").map(Utf8PathBuf::from); let lldb_version = matches.opt_str("lldb-version").as_deref().and_then(debuggers::extract_lldb_version); - let color = match matches.opt_str("color").as_deref() { - Some("auto") | None => ColorConfig::AutoColor, - Some("always") => ColorConfig::AlwaysColor, - Some("never") => ColorConfig::NeverColor, - Some(x) => panic!("argument for --color must be auto, always, or never, but found `{}`", x), - }; // FIXME: this is very questionable, we really should be obtaining LLVM version info from // `bootstrap`, and not trying to be figuring out that in `compiletest` by running the // `FileCheck` binary. @@ -306,16 +300,6 @@ fn parse_config(args: Vec) -> Config { let with_rustc_debug_assertions = matches.opt_present("with-rustc-debug-assertions"); let with_std_debug_assertions = matches.opt_present("with-std-debug-assertions"); let mode = matches.opt_str("mode").unwrap().parse().expect("invalid mode"); - let has_html_tidy = if mode == TestMode::Rustdoc { - Command::new("tidy") - .arg("--version") - .stdout(Stdio::null()) - .status() - .map_or(false, |status| status.success()) - } else { - // Avoid spawning an external command when we know html-tidy won't be used. - false - }; let has_enzyme = matches.opt_present("has-enzyme"); let filters = if mode == TestMode::RunMake { matches @@ -457,11 +441,9 @@ fn parse_config(args: Vec) -> Config { adb_device_status, verbose: matches.opt_present("verbose"), only_modified: matches.opt_present("only-modified"), - color, remote_test_client: matches.opt_str("remote-test-client").map(Utf8PathBuf::from), compare_mode, rustfix_coverage: matches.opt_present("rustfix-coverage"), - has_html_tidy, has_enzyme, channel: matches.opt_str("channel").unwrap(), git_hash: matches.opt_present("git-hash"), @@ -1146,10 +1128,6 @@ fn check_for_overlapping_test_paths(found_path_stems: &HashSet) { } fn early_config_check(config: &Config) { - if !config.has_html_tidy && config.mode == TestMode::Rustdoc { - warning!("`tidy` (html-tidy.org) is not installed; diffs will not be generated"); - } - if !config.profiler_runtime && config.mode == TestMode::CoverageRun { let actioned = if config.bless { "blessed" } else { "checked" }; warning!("profiler runtime is not available, so `.coverage` files won't be {actioned}"); diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 54d6e0190ddc..f28f70ed453e 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -1,12 +1,11 @@ use std::borrow::Cow; use std::collections::{HashMap, HashSet}; use std::ffi::OsString; -use std::fs::{self, File, create_dir_all}; +use std::fs::{self, create_dir_all}; use std::hash::{DefaultHasher, Hash, Hasher}; use std::io::prelude::*; -use std::io::{self, BufReader}; use std::process::{Child, Command, ExitStatus, Output, Stdio}; -use std::{env, fmt, iter, str}; +use std::{env, fmt, io, iter, str}; use build_helper::fs::remove_and_create_dir_all; use camino::{Utf8Path, Utf8PathBuf}; @@ -23,9 +22,9 @@ use crate::directives::TestProps; use crate::errors::{Error, ErrorKind, load_errors}; use crate::output_capture::ConsoleOut; use crate::read2::{Truncated, read2_abbreviated}; -use crate::runtest::compute_diff::{DiffLine, make_diff, write_diff, write_filtered_diff}; +use crate::runtest::compute_diff::{DiffLine, make_diff, write_diff}; use crate::util::{Utf8PathBufExt, add_dylib_path, static_regex}; -use crate::{ColorConfig, help, json, stamp_file_path, warning}; +use crate::{json, stamp_file_path}; // Helper modules that implement test running logic for each test suite. // tidy-alphabetical-start @@ -2162,161 +2161,6 @@ impl<'test> TestCx<'test> { if cfg!(target_os = "freebsd") { "ISO-8859-1" } else { "UTF-8" } } - fn compare_to_default_rustdoc(&self, out_dir: &Utf8Path) { - if !self.config.has_html_tidy { - return; - } - writeln!(self.stdout, "info: generating a diff against nightly rustdoc"); - - let suffix = - self.safe_revision().map_or("nightly".into(), |path| path.to_owned() + "-nightly"); - let compare_dir = output_base_dir(self.config, self.testpaths, Some(&suffix)); - remove_and_create_dir_all(&compare_dir).unwrap_or_else(|e| { - panic!("failed to remove and recreate output directory `{compare_dir}`: {e}") - }); - - // We need to create a new struct for the lifetimes on `config` to work. - let new_rustdoc = TestCx { - config: &Config { - // FIXME: use beta or a user-specified rustdoc instead of - // hardcoding the default toolchain - rustdoc_path: Some("rustdoc".into()), - // Needed for building auxiliary docs below - rustc_path: "rustc".into(), - ..self.config.clone() - }, - ..*self - }; - - let output_file = TargetLocation::ThisDirectory(new_rustdoc.aux_output_dir_name()); - let mut rustc = new_rustdoc.make_compile_args( - &new_rustdoc.testpaths.file, - output_file, - Emit::None, - AllowUnused::Yes, - LinkToAux::Yes, - Vec::new(), - ); - let aux_dir = new_rustdoc.aux_output_dir(); - new_rustdoc.build_all_auxiliary(&aux_dir, &mut rustc); - - let proc_res = new_rustdoc.document(&compare_dir, DocKind::Html); - if !proc_res.status.success() { - writeln!(self.stderr, "failed to run nightly rustdoc"); - return; - } - - #[rustfmt::skip] - let tidy_args = [ - "--new-blocklevel-tags", "rustdoc-search,rustdoc-toolbar,rustdoc-topbar", - "--indent", "yes", - "--indent-spaces", "2", - "--wrap", "0", - "--show-warnings", "no", - "--markup", "yes", - "--quiet", "yes", - "-modify", - ]; - let tidy_dir = |dir| { - for entry in walkdir::WalkDir::new(dir) { - let entry = entry.expect("failed to read file"); - if entry.file_type().is_file() - && entry.path().extension().and_then(|p| p.to_str()) == Some("html") - { - let status = - Command::new("tidy").args(&tidy_args).arg(entry.path()).status().unwrap(); - // `tidy` returns 1 if it modified the file. - assert!(status.success() || status.code() == Some(1)); - } - } - }; - tidy_dir(out_dir); - tidy_dir(&compare_dir); - - let pager = { - let output = Command::new("git").args(&["config", "--get", "core.pager"]).output().ok(); - output.and_then(|out| { - if out.status.success() { - Some(String::from_utf8(out.stdout).expect("invalid UTF8 in git pager")) - } else { - None - } - }) - }; - - let diff_filename = format!("build/tmp/rustdoc-compare-{}.diff", std::process::id()); - - if !write_filtered_diff( - self, - &diff_filename, - out_dir, - &compare_dir, - self.config.verbose, - |file_type, extension| { - file_type.is_file() && (extension == Some("html") || extension == Some("js")) - }, - ) { - return; - } - - match self.config.color { - ColorConfig::AlwaysColor => colored::control::set_override(true), - ColorConfig::NeverColor => colored::control::set_override(false), - _ => {} - } - - if let Some(pager) = pager { - let pager = pager.trim(); - if self.config.verbose { - writeln!(self.stderr, "using pager {}", pager); - } - let output = Command::new(pager) - // disable paging; we want this to be non-interactive - .env("PAGER", "") - .stdin(File::open(&diff_filename).unwrap()) - // Capture output and print it explicitly so it will in turn be - // captured by output-capture. - .output() - .unwrap(); - assert!(output.status.success()); - writeln!(self.stdout, "{}", String::from_utf8_lossy(&output.stdout)); - writeln!(self.stderr, "{}", String::from_utf8_lossy(&output.stderr)); - } else { - warning!("no pager configured, falling back to unified diff"); - help!( - "try configuring a git pager (e.g. `delta`) with \ - `git config --global core.pager delta`" - ); - let mut out = io::stdout(); - let mut diff = BufReader::new(File::open(&diff_filename).unwrap()); - let mut line = Vec::new(); - loop { - line.truncate(0); - match diff.read_until(b'\n', &mut line) { - Ok(0) => break, - Ok(_) => {} - Err(e) => writeln!(self.stderr, "ERROR: {:?}", e), - } - match String::from_utf8(line.clone()) { - Ok(line) => { - if line.starts_with('+') { - write!(&mut out, "{}", line.green()).unwrap(); - } else if line.starts_with('-') { - write!(&mut out, "{}", line.red()).unwrap(); - } else if line.starts_with('@') { - write!(&mut out, "{}", line.blue()).unwrap(); - } else { - out.write_all(line.as_bytes()).unwrap(); - } - } - Err(_) => { - write!(&mut out, "{}", String::from_utf8_lossy(&line).reversed()).unwrap(); - } - } - } - }; - } - fn get_lines(&self, path: &Utf8Path, mut other_files: Option<&mut Vec>) -> Vec { let content = fs::read_to_string(path.as_std_path()).unwrap(); let mut ignore = false; diff --git a/src/tools/compiletest/src/runtest/compute_diff.rs b/src/tools/compiletest/src/runtest/compute_diff.rs index 3363127b3ea3..8418dcbaf963 100644 --- a/src/tools/compiletest/src/runtest/compute_diff.rs +++ b/src/tools/compiletest/src/runtest/compute_diff.rs @@ -1,9 +1,4 @@ use std::collections::VecDeque; -use std::fs::{File, FileType}; - -use camino::Utf8Path; - -use crate::runtest::TestCx; #[derive(Debug, PartialEq)] pub enum DiffLine { @@ -109,55 +104,3 @@ pub(crate) fn write_diff(expected: &str, actual: &str, context_size: usize) -> S } output } - -/// Filters based on filetype and extension whether to diff a file. -/// -/// Returns whether any data was actually written. -pub(crate) fn write_filtered_diff( - cx: &TestCx<'_>, - diff_filename: &str, - out_dir: &Utf8Path, - compare_dir: &Utf8Path, - verbose: bool, - filter: Filter, -) -> bool -where - Filter: Fn(FileType, Option<&str>) -> bool, -{ - use std::io::{Read, Write}; - let mut diff_output = File::create(diff_filename).unwrap(); - let mut wrote_data = false; - for entry in walkdir::WalkDir::new(out_dir.as_std_path()) { - let entry = entry.expect("failed to read file"); - let extension = entry.path().extension().and_then(|p| p.to_str()); - if filter(entry.file_type(), extension) { - let expected_path = compare_dir - .as_std_path() - .join(entry.path().strip_prefix(&out_dir.as_std_path()).unwrap()); - let expected = if let Ok(s) = std::fs::read(&expected_path) { s } else { continue }; - let actual_path = entry.path(); - let actual = std::fs::read(&actual_path).unwrap(); - let diff = unified_diff::diff( - &expected, - &expected_path.to_str().unwrap(), - &actual, - &actual_path.to_str().unwrap(), - 3, - ); - wrote_data |= !diff.is_empty(); - diff_output.write_all(&diff).unwrap(); - } - } - - if !wrote_data { - writeln!(cx.stdout, "note: diff is identical to nightly rustdoc"); - assert!(diff_output.metadata().unwrap().len() == 0); - return false; - } else if verbose { - writeln!(cx.stderr, "printing diff:"); - let mut buf = Vec::new(); - diff_output.read_to_end(&mut buf).unwrap(); - std::io::stderr().lock().write_all(&mut buf).unwrap(); - } - true -} diff --git a/src/tools/compiletest/src/runtest/rustdoc.rs b/src/tools/compiletest/src/runtest/rustdoc.rs index a4558de5f1c0..3c80521e51ec 100644 --- a/src/tools/compiletest/src/runtest/rustdoc.rs +++ b/src/tools/compiletest/src/runtest/rustdoc.rs @@ -28,9 +28,7 @@ impl TestCx<'_> { } let res = self.run_command_to_procres(&mut cmd); if !res.status.success() { - self.fatal_proc_rec_general("htmldocck failed!", None, &res, || { - self.compare_to_default_rustdoc(&out_dir); - }); + self.fatal_proc_rec("htmldocck failed!", &res); } } } diff --git a/src/tools/compiletest/src/rustdoc_gui_test.rs b/src/tools/compiletest/src/rustdoc_gui_test.rs index f6d026ab9cfd..c30f3d1e10ea 100644 --- a/src/tools/compiletest/src/rustdoc_gui_test.rs +++ b/src/tools/compiletest/src/rustdoc_gui_test.rs @@ -108,11 +108,9 @@ fn incomplete_config_for_rustdoc_gui_test() -> Config { adb_test_dir: Default::default(), adb_device_status: Default::default(), verbose: Default::default(), - color: Default::default(), remote_test_client: Default::default(), compare_mode: Default::default(), rustfix_coverage: Default::default(), - has_html_tidy: Default::default(), has_enzyme: Default::default(), channel: Default::default(), git_hash: Default::default(), From 450916305fe8482dfe2f192c0d288b0490d3a517 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 11 Jun 2025 21:29:06 +0200 Subject: [PATCH 41/64] Put negative implementors first and apply same ordering logic to foreign implementors --- src/librustdoc/formats/mod.rs | 4 ++ src/librustdoc/html/render/print_item.rs | 43 ++++++++++++++++-- src/librustdoc/html/render/write_shared.rs | 45 +++++++++++++++++-- .../html/render/write_shared/tests.rs | 6 +-- src/librustdoc/html/static/css/rustdoc.css | 3 ++ src/librustdoc/html/static/js/main.js | 39 ++++++++++++---- src/librustdoc/html/static/js/rustdoc.d.ts | 2 +- 7 files changed, 122 insertions(+), 20 deletions(-) diff --git a/src/librustdoc/formats/mod.rs b/src/librustdoc/formats/mod.rs index 2e8b5d9f5948..80c110ec07f5 100644 --- a/src/librustdoc/formats/mod.rs +++ b/src/librustdoc/formats/mod.rs @@ -76,4 +76,8 @@ impl Impl { }; true } + + pub(crate) fn is_negative_trait_impl(&self) -> bool { + self.inner_impl().is_negative_trait_impl() + } } diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 0c511738d7c8..47e587626352 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -646,6 +646,27 @@ fn item_function(cx: &Context<'_>, it: &clean::Item, f: &clean::Function) -> imp }) } +/// Struct used to handle insertion of "negative impl" marker in the generated DOM. +/// +/// This marker appears once in all trait impl lists to divide negative impls from positive impls. +struct NegativeMarker { + inserted_negative_marker: bool, +} + +impl NegativeMarker { + fn new() -> Self { + Self { inserted_negative_marker: false } + } + + fn insert_if_needed(&mut self, w: &mut fmt::Formatter<'_>, implementor: &Impl) -> fmt::Result { + if !self.inserted_negative_marker && !implementor.is_negative_trait_impl() { + write!(w, "
")?; + self.inserted_negative_marker = true; + } + Ok(()) + } +} + fn item_trait(cx: &Context<'_>, it: &clean::Item, t: &clean::Trait) -> impl fmt::Display { fmt::from_fn(|w| { let tcx = cx.tcx(); @@ -1072,7 +1093,9 @@ fn item_trait(cx: &Context<'_>, it: &clean::Item, t: &clean::Trait) -> impl fmt: "
", ) )?; + let mut negative_marker = NegativeMarker::new(); for implementor in concrete { + negative_marker.insert_if_needed(w, implementor)?; write!(w, "{}", render_implementor(cx, implementor, it, &implementor_dups, &[]))?; } w.write_str("
")?; @@ -1088,7 +1111,9 @@ fn item_trait(cx: &Context<'_>, it: &clean::Item, t: &clean::Trait) -> impl fmt: "
", ) )?; + let mut negative_marker = NegativeMarker::new(); for implementor in synthetic { + negative_marker.insert_if_needed(w, implementor)?; write!( w, "{}", @@ -2302,11 +2327,18 @@ where } #[derive(PartialEq, Eq)] -struct ImplString(String); +struct ImplString { + rendered: String, + is_negative: bool, +} impl ImplString { fn new(i: &Impl, cx: &Context<'_>) -> ImplString { - ImplString(format!("{}", print_impl(i.inner_impl(), false, cx))) + let impl_ = i.inner_impl(); + ImplString { + is_negative: impl_.is_negative_trait_impl(), + rendered: format!("{}", print_impl(impl_, false, cx)), + } } } @@ -2318,7 +2350,12 @@ impl PartialOrd for ImplString { impl Ord for ImplString { fn cmp(&self, other: &Self) -> Ordering { - compare_names(&self.0, &other.0) + // We sort negative impls first. + match (self.is_negative, other.is_negative) { + (false, true) => Ordering::Greater, + (true, false) => Ordering::Less, + _ => compare_names(&self.rendered, &other.rendered), + } } } diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs index 6bf116c3b75a..ca33531174b1 100644 --- a/src/librustdoc/html/render/write_shared.rs +++ b/src/librustdoc/html/render/write_shared.rs @@ -14,6 +14,7 @@ //! or contains "invocation-specific". use std::cell::RefCell; +use std::cmp::Ordering; use std::ffi::{OsStr, OsString}; use std::fs::File; use std::io::{self, Write as _}; @@ -47,6 +48,7 @@ use crate::formats::item_type::ItemType; use crate::html::format::{print_impl, print_path}; use crate::html::layout; use crate::html::render::ordered_json::{EscapedJson, OrderedJson}; +use crate::html::render::print_item::compare_names; use crate::html::render::search_index::{SerializedSearchIndex, build_index}; use crate::html::render::sorted_template::{self, FileFormat, SortedTemplate}; use crate::html::render::{AssocItemLink, ImplRenderingParameters, StylePath}; @@ -667,7 +669,7 @@ impl TraitAliasPart { fn blank() -> SortedTemplate<::FileFormat> { SortedTemplate::from_before_after( r"(function() { - var implementors = Object.fromEntries([", + const implementors = Object.fromEntries([", r"]); if (window.register_implementors) { window.register_implementors(implementors); @@ -720,10 +722,12 @@ impl TraitAliasPart { { None } else { + let impl_ = imp.inner_impl(); Some(Implementor { - text: print_impl(imp.inner_impl(), false, cx).to_string(), + text: print_impl(impl_, false, cx).to_string(), synthetic: imp.inner_impl().kind.is_auto(), types: collect_paths_for_type(&imp.inner_impl().for_, cache), + is_negative: impl_.is_negative_trait_impl(), }) } }) @@ -742,8 +746,15 @@ impl TraitAliasPart { } path.push(format!("{remote_item_type}.{}.js", remote_path[remote_path.len() - 1])); - let part = OrderedJson::array_sorted( - implementors.map(|implementor| OrderedJson::serialize(implementor).unwrap()), + let mut implementors = implementors.collect::>(); + implementors.sort_unstable(); + + let part = OrderedJson::array_unsorted( + implementors + .iter() + .map(OrderedJson::serialize) + .collect::, _>>() + .unwrap(), ); path_parts.push(path, OrderedJson::array_unsorted([crate_name_json, &part])); } @@ -751,10 +762,12 @@ impl TraitAliasPart { } } +#[derive(Eq)] struct Implementor { text: String, synthetic: bool, types: Vec, + is_negative: bool, } impl Serialize for Implementor { @@ -764,6 +777,7 @@ impl Serialize for Implementor { { let mut seq = serializer.serialize_seq(None)?; seq.serialize_element(&self.text)?; + seq.serialize_element(if self.is_negative { &1 } else { &0 })?; if self.synthetic { seq.serialize_element(&1)?; seq.serialize_element(&self.types)?; @@ -772,6 +786,29 @@ impl Serialize for Implementor { } } +impl PartialEq for Implementor { + fn eq(&self, other: &Self) -> bool { + self.cmp(other) == Ordering::Equal + } +} + +impl PartialOrd for Implementor { + fn partial_cmp(&self, other: &Self) -> Option { + Some(Ord::cmp(self, other)) + } +} + +impl Ord for Implementor { + fn cmp(&self, other: &Self) -> Ordering { + // We sort negative impls first. + match (self.is_negative, other.is_negative) { + (false, true) => Ordering::Greater, + (true, false) => Ordering::Less, + _ => compare_names(&self.text, &other.text), + } + } +} + /// Collect the list of aliased types and their aliases. /// /// diff --git a/src/librustdoc/html/render/write_shared/tests.rs b/src/librustdoc/html/render/write_shared/tests.rs index 1989a1f87aae..48d592c22f6f 100644 --- a/src/librustdoc/html/render/write_shared/tests.rs +++ b/src/librustdoc/html/render/write_shared/tests.rs @@ -68,7 +68,7 @@ fn trait_alias_template() { assert_eq!( but_last_line(&template.to_string()), r#"(function() { - var implementors = Object.fromEntries([]); + const implementors = Object.fromEntries([]); if (window.register_implementors) { window.register_implementors(implementors); } else { @@ -80,7 +80,7 @@ fn trait_alias_template() { assert_eq!( but_last_line(&template.to_string()), r#"(function() { - var implementors = Object.fromEntries([["a"]]); + const implementors = Object.fromEntries([["a"]]); if (window.register_implementors) { window.register_implementors(implementors); } else { @@ -92,7 +92,7 @@ fn trait_alias_template() { assert_eq!( but_last_line(&template.to_string()), r#"(function() { - var implementors = Object.fromEntries([["a"],["b"]]); + const implementors = Object.fromEntries([["a"],["b"]]); if (window.register_implementors) { window.register_implementors(implementors); } else { diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index 7f4785694849..36f44a8072af 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -2976,6 +2976,9 @@ in src-script.js and main.js { margin-bottom: 0.75em; } +.negative-marker { + display: none; +} .variants > .docblock, .implementors-toggle > .docblock, diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index dff40485e9a9..fb6b70492181 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -800,21 +800,34 @@ function preLoadCss(cssUrl) { // window.register_implementors = imp => { - const implementors = document.getElementById("implementors-list"); - const synthetic_implementors = document.getElementById("synthetic-implementors-list"); + /** Takes an ID as input and returns a list of two elements. The first element is the DOM + * element with the given ID and the second is the "negative marker", meaning the location + * between the negative and non-negative impls. + * + * @param {string} id: ID of the DOM element. + * + * @return {[HTMLElement|null, HTMLElement|null]} + */ + function implementorsElems(id) { + const elem = document.getElementById(id); + return [elem, elem ? elem.querySelector(".negative-marker") : null]; + } + const implementors = implementorsElems("implementors-list"); + const synthetic_implementors = implementorsElems("synthetic-implementors-list"); const inlined_types = new Set(); const TEXT_IDX = 0; - const SYNTHETIC_IDX = 1; - const TYPES_IDX = 2; + const IS_NEG_IDX = 1; + const SYNTHETIC_IDX = 2; + const TYPES_IDX = 3; - if (synthetic_implementors) { + if (synthetic_implementors[0]) { // This `inlined_types` variable is used to avoid having the same implementation // showing up twice. For example "String" in the "Sync" doc page. // // By the way, this is only used by and useful for traits implemented automatically // (like "Send" and "Sync"). - onEachLazy(synthetic_implementors.getElementsByClassName("impl"), el => { + onEachLazy(synthetic_implementors[0].getElementsByClassName("impl"), el => { const aliases = el.getAttribute("data-aliases"); if (!aliases) { return; @@ -827,7 +840,7 @@ function preLoadCss(cssUrl) { } // @ts-expect-error - let currentNbImpls = implementors.getElementsByClassName("impl").length; + let currentNbImpls = implementors[0].getElementsByClassName("impl").length; // @ts-expect-error const traitName = document.querySelector(".main-heading h1 > .trait").textContent; const baseIdName = "impl-" + traitName + "-"; @@ -884,8 +897,16 @@ function preLoadCss(cssUrl) { addClass(display, "impl"); display.appendChild(anchor); display.appendChild(code); - // @ts-expect-error - list.appendChild(display); + + // If this is a negative implementor, we put it into the right location (just + // before the negative impl marker). + if (struct[IS_NEG_IDX]) { + // @ts-expect-error + list[1].before(display); + } else { + // @ts-expect-error + list[0].appendChild(display); + } currentNbImpls += 1; } } diff --git a/src/librustdoc/html/static/js/rustdoc.d.ts b/src/librustdoc/html/static/js/rustdoc.d.ts index 18d3b6a455d3..60df4fc10b8c 100644 --- a/src/librustdoc/html/static/js/rustdoc.d.ts +++ b/src/librustdoc/html/static/js/rustdoc.d.ts @@ -520,7 +520,7 @@ declare namespace rustdoc { * Provided by generated `trait.impl` files. */ type Implementors = { - [key: string]: Array<[string, number, Array]> + [key: string]: Array<[string, 0|1, number, Array]> } type TypeImpls = { From 985178dacf81d2baa21d0261c2cc85b374d0dd8c Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 11 Jun 2025 22:19:47 +0200 Subject: [PATCH 42/64] Add GUI test to ensure that negative impls are correctly sorted --- tests/rustdoc-gui/implementors.goml | 47 +++++++++++++++---- .../rustdoc-gui/src/lib2/implementors/lib.rs | 5 ++ tests/rustdoc-gui/src/lib2/lib.rs | 3 ++ 3 files changed, 45 insertions(+), 10 deletions(-) diff --git a/tests/rustdoc-gui/implementors.goml b/tests/rustdoc-gui/implementors.goml index b39b95c1a9bf..99fb9b9aff54 100644 --- a/tests/rustdoc-gui/implementors.goml +++ b/tests/rustdoc-gui/implementors.goml @@ -2,18 +2,45 @@ // have the same display than the "local" ones. go-to: "file://" + |DOC_PATH| + "/implementors/trait.Whatever.html" assert: "#implementors-list" -// There are supposed to be two implementors listed. -assert-count: ("#implementors-list .impl", 2) +// There are supposed to be four implementors listed. +assert-count: ("#implementors-list .impl", 4) +// There are supposed to be two non-negative implementors. +assert-count: ("#implementors-list .negative-marker ~ *", 2) // Now we check that both implementors have an anchor, an ID and a similar DOM. -assert: ("#implementors-list .impl:nth-child(1) > a.anchor") -assert-attribute: ("#implementors-list .impl:nth-child(1)", {"id": "impl-Whatever-for-Struct"}) -assert-attribute: ("#implementors-list .impl:nth-child(1) > a.anchor", {"href": "#impl-Whatever-for-Struct"}) -assert: "#implementors-list .impl:nth-child(1) > .code-header" +define-function: ( + "check-dom", + [id], + block { + assert-attribute: (|id| + " > a.anchor", {"href": |id|}) + assert: |id| + " > .code-header" + }, +) -assert: ("#implementors-list .impl:nth-child(2) > a.anchor") -assert-attribute: ("#implementors-list .impl:nth-child(2)", {"id": "impl-Whatever-1"}) -assert-attribute: ("#implementors-list .impl:nth-child(2) > a.anchor", {"href": "#impl-Whatever-1"}) -assert: "#implementors-list .impl:nth-child(2) > .code-header" +call-function: ("check-dom", {"id": "#impl-Whatever-for-Struct2"}) +call-function: ("check-dom", {"id": "#impl-Whatever-2"}) +call-function: ("check-dom", {"id": "#impl-Whatever-for-Struct"}) +call-function: ("check-dom", {"id": "#impl-Whatever-3"}) + +// Ensure that negative impl are sorted first. +assert-property: ( + "#implementors-list > *:nth-child(1) > h3", + {"textContent": "impl !Whatever for Struct2"}, +) +assert-property: ( + "#implementors-list > *:nth-child(2) > h3", + {"textContent": "impl !Whatever for StructToImplOnReexport"}, +) +// Third one is the negative marker. +assert-attribute: ("#implementors-list > *:nth-child(3)", {"class": "negative-marker"}) +// This one is a `` so the selector is a bit different. +assert-property: ( + "#implementors-list > *:nth-child(4) section > h3", + {"textContent": "impl Whatever for Struct"}, +) +assert-property: ( + "#implementors-list > *:nth-child(5) > h3", + {"textContent": "impl Whatever for Foo"}, +) go-to: "file://" + |DOC_PATH| + "/test_docs/struct.HasEmptyTraits.html" compare-elements-position-near-false: ( diff --git a/tests/rustdoc-gui/src/lib2/implementors/lib.rs b/tests/rustdoc-gui/src/lib2/implementors/lib.rs index 2842ac50dc1e..f08182003927 100644 --- a/tests/rustdoc-gui/src/lib2/implementors/lib.rs +++ b/tests/rustdoc-gui/src/lib2/implementors/lib.rs @@ -1,3 +1,5 @@ +#![feature(negative_impls)] + pub trait Whatever { type Foo; @@ -5,11 +7,14 @@ pub trait Whatever { } pub struct Struct; +pub struct Struct2; impl Whatever for Struct { type Foo = u8; } +impl !Whatever for Struct2 {} + impl http::HttpTrait for Struct {} mod traits { diff --git a/tests/rustdoc-gui/src/lib2/lib.rs b/tests/rustdoc-gui/src/lib2/lib.rs index 400488cbe857..b87fdeea89da 100644 --- a/tests/rustdoc-gui/src/lib2/lib.rs +++ b/tests/rustdoc-gui/src/lib2/lib.rs @@ -1,6 +1,7 @@ // ignore-tidy-linelength #![feature(doc_cfg)] +#![feature(negative_impls)] pub mod another_folder; pub mod another_mod; @@ -60,6 +61,8 @@ impl implementors::Whatever for Foo { type Foo = u32; } +impl !implementors::Whatever for StructToImplOnReexport {} + #[doc(inline)] pub use implementors::TraitToReexport; From 13091ddc932be37c0ad3db7581e5f7776cf429d0 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 24 Jun 2025 17:05:43 +0200 Subject: [PATCH 43/64] Make implementors list visible only when filled --- src/librustdoc/html/static/css/noscript.css | 4 ++++ src/librustdoc/html/static/css/rustdoc.css | 6 ++++++ src/librustdoc/html/static/js/main.js | 14 ++++++++++---- tests/rustdoc-gui/implementors.goml | 7 ++++++- 4 files changed, 26 insertions(+), 5 deletions(-) diff --git a/src/librustdoc/html/static/css/noscript.css b/src/librustdoc/html/static/css/noscript.css index 5c02e2eb26a3..6b80d3e7bbee 100644 --- a/src/librustdoc/html/static/css/noscript.css +++ b/src/librustdoc/html/static/css/noscript.css @@ -29,6 +29,10 @@ nav.sub { display: none; } +#synthetic-implementors-list, #implementors-list { + display: block; +} + /* Begin: styles for themes Keep the default light and dark themes synchronized with the ones in rustdoc.css */ diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index 36f44a8072af..a5e43e1d7d19 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -1158,6 +1158,12 @@ div.where { margin-left: calc(var(--docblock-indent) + var(--impl-items-indent)); } +#synthetic-implementors-list, #implementors-list { + /* To prevent layout shift when loading the page with extra implementors being loaded + from JS, we hide the list until it's complete. */ + display: none; +} + .item-info code { font-size: 0.875rem; } diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index fb6b70492181..72d7e6131814 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -813,7 +813,7 @@ function preLoadCss(cssUrl) { return [elem, elem ? elem.querySelector(".negative-marker") : null]; } const implementors = implementorsElems("implementors-list"); - const synthetic_implementors = implementorsElems("synthetic-implementors-list"); + const syntheticImplementors = implementorsElems("synthetic-implementors-list"); const inlined_types = new Set(); const TEXT_IDX = 0; @@ -821,13 +821,13 @@ function preLoadCss(cssUrl) { const SYNTHETIC_IDX = 2; const TYPES_IDX = 3; - if (synthetic_implementors[0]) { + if (syntheticImplementors[0]) { // This `inlined_types` variable is used to avoid having the same implementation // showing up twice. For example "String" in the "Sync" doc page. // // By the way, this is only used by and useful for traits implemented automatically // (like "Send" and "Sync"). - onEachLazy(synthetic_implementors[0].getElementsByClassName("impl"), el => { + onEachLazy(syntheticImplementors[0].getElementsByClassName("impl"), el => { const aliases = el.getAttribute("data-aliases"); if (!aliases) { return; @@ -862,7 +862,7 @@ function preLoadCss(cssUrl) { struct_loop: for (const struct of structs) { - const list = struct[SYNTHETIC_IDX] ? synthetic_implementors : implementors; + const list = struct[SYNTHETIC_IDX] ? syntheticImplementors : implementors; // The types list is only used for synthetic impls. // If this changes, `main.js` and `write_shared.rs` both need changed. @@ -910,6 +910,12 @@ function preLoadCss(cssUrl) { currentNbImpls += 1; } } + if (implementors[0]) { + implementors[0].style.display = "block"; + } + if (syntheticImplementors[0]) { + syntheticImplementors[0].style.display = "block"; + } }; if (window.pending_implementors) { window.register_implementors(window.pending_implementors); diff --git a/tests/rustdoc-gui/implementors.goml b/tests/rustdoc-gui/implementors.goml index 99fb9b9aff54..d4542c6f7817 100644 --- a/tests/rustdoc-gui/implementors.goml +++ b/tests/rustdoc-gui/implementors.goml @@ -1,7 +1,7 @@ // The goal of this test is to check that the external trait implementors, generated with JS, // have the same display than the "local" ones. go-to: "file://" + |DOC_PATH| + "/implementors/trait.Whatever.html" -assert: "#implementors-list" +wait-for-css: ("#implementors-list", {"display": "block"}) // There are supposed to be four implementors listed. assert-count: ("#implementors-list .impl", 4) // There are supposed to be two non-negative implementors. @@ -66,3 +66,8 @@ assert-count: ("#implementors-list .impl", 1) go-to: "file://" + |DOC_PATH| + "/http/trait.HttpTrait.html" assert-count: ("#implementors-list .impl", 1) assert-attribute: ("#implementors-list .impl a.trait", {"href": "../http/trait.HttpTrait.html"}) + +// Now we check that if JS is disabled, the implementors list will be visible. +javascript: false +reload: +assert-css: ("#implementors-list", {"display": "block"}) From fb9d3a5db4c3358f8ca22302f0e078675bc1a596 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 10 Dec 2025 17:34:08 +0100 Subject: [PATCH 44/64] Simplify the sorting of impls and use CSS classes instead of plain JS to show/hide implementors --- src/librustdoc/html/render/print_item.rs | 10 +++---- src/librustdoc/html/render/write_shared.rs | 33 +++++---------------- src/librustdoc/html/static/css/noscript.css | 2 +- src/librustdoc/html/static/css/rustdoc.css | 2 +- src/librustdoc/html/static/js/main.js | 4 +-- 5 files changed, 17 insertions(+), 34 deletions(-) diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 47e587626352..f88a5b8974fb 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -650,18 +650,18 @@ fn item_function(cx: &Context<'_>, it: &clean::Item, f: &clean::Function) -> imp /// /// This marker appears once in all trait impl lists to divide negative impls from positive impls. struct NegativeMarker { - inserted_negative_marker: bool, + inserted: bool, } impl NegativeMarker { fn new() -> Self { - Self { inserted_negative_marker: false } + Self { inserted: false } } fn insert_if_needed(&mut self, w: &mut fmt::Formatter<'_>, implementor: &Impl) -> fmt::Result { - if !self.inserted_negative_marker && !implementor.is_negative_trait_impl() { - write!(w, "
")?; - self.inserted_negative_marker = true; + if !self.inserted && !implementor.is_negative_trait_impl() { + w.write_str("
")?; + self.inserted = true; } Ok(()) } diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs index ca33531174b1..e0a37c95257c 100644 --- a/src/librustdoc/html/render/write_shared.rs +++ b/src/librustdoc/html/render/write_shared.rs @@ -747,7 +747,14 @@ impl TraitAliasPart { path.push(format!("{remote_item_type}.{}.js", remote_path[remote_path.len() - 1])); let mut implementors = implementors.collect::>(); - implementors.sort_unstable(); + implementors.sort_unstable_by(|a, b| { + // We sort negative impls first. + match (a.is_negative, b.is_negative) { + (false, true) => Ordering::Greater, + (true, false) => Ordering::Less, + _ => compare_names(&a.text, &b.text), + } + }); let part = OrderedJson::array_unsorted( implementors @@ -762,7 +769,6 @@ impl TraitAliasPart { } } -#[derive(Eq)] struct Implementor { text: String, synthetic: bool, @@ -786,29 +792,6 @@ impl Serialize for Implementor { } } -impl PartialEq for Implementor { - fn eq(&self, other: &Self) -> bool { - self.cmp(other) == Ordering::Equal - } -} - -impl PartialOrd for Implementor { - fn partial_cmp(&self, other: &Self) -> Option { - Some(Ord::cmp(self, other)) - } -} - -impl Ord for Implementor { - fn cmp(&self, other: &Self) -> Ordering { - // We sort negative impls first. - match (self.is_negative, other.is_negative) { - (false, true) => Ordering::Greater, - (true, false) => Ordering::Less, - _ => compare_names(&self.text, &other.text), - } - } -} - /// Collect the list of aliased types and their aliases. /// /// diff --git a/src/librustdoc/html/static/css/noscript.css b/src/librustdoc/html/static/css/noscript.css index 6b80d3e7bbee..6f44854b6914 100644 --- a/src/librustdoc/html/static/css/noscript.css +++ b/src/librustdoc/html/static/css/noscript.css @@ -29,7 +29,7 @@ nav.sub { display: none; } -#synthetic-implementors-list, #implementors-list { +#synthetic-implementors-list:not(.loaded), #implementors-list:not(.loaded) { display: block; } diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index a5e43e1d7d19..69a79f2736e7 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -1158,7 +1158,7 @@ div.where { margin-left: calc(var(--docblock-indent) + var(--impl-items-indent)); } -#synthetic-implementors-list, #implementors-list { +#synthetic-implementors-list:not(.loaded), #implementors-list:not(.loaded) { /* To prevent layout shift when loading the page with extra implementors being loaded from JS, we hide the list until it's complete. */ display: none; diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index 72d7e6131814..476ecd42d6f9 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -911,10 +911,10 @@ function preLoadCss(cssUrl) { } } if (implementors[0]) { - implementors[0].style.display = "block"; + implementors[0].classList.add("loaded"); } if (syntheticImplementors[0]) { - syntheticImplementors[0].style.display = "block"; + syntheticImplementors[0].classList.add("loaded"); } }; if (window.pending_implementors) { From 40891c79e67bd4e83f98c5866e62d24e2f2e06eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Tue, 9 Dec 2025 11:31:24 +0100 Subject: [PATCH 45/64] Use ubuntu:24.04 for the `x86_64-gnu-miri` and `x86_64-gnu-aux` jobs --- src/ci/docker/host-x86_64/x86_64-gnu-aux/Dockerfile | 2 +- src/ci/docker/host-x86_64/x86_64-gnu-miri/Dockerfile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-aux/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-aux/Dockerfile index a74db2250fc6..d4113736b544 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-aux/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-aux/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:22.04 +FROM ghcr.io/rust-lang/ubuntu:24.04 ARG DEBIAN_FRONTEND=noninteractive RUN apt-get update && apt-get install -y --no-install-recommends \ diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-miri/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-miri/Dockerfile index ad2ee85c7bb5..db4fca71d637 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-miri/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-miri/Dockerfile @@ -1,4 +1,4 @@ -FROM ghcr.io/rust-lang/ubuntu:22.04 +FROM ghcr.io/rust-lang/ubuntu:24.04 ARG DEBIAN_FRONTEND=noninteractive RUN apt-get update && apt-get install -y --no-install-recommends \ From 96a700010103799b6988ab9800f72f2f2b43b696 Mon Sep 17 00:00:00 2001 From: Pavel Grigorenko Date: Mon, 8 Dec 2025 16:25:43 +0300 Subject: [PATCH 46/64] Rename some issue-* tests --- src/tools/tidy/src/issues.txt | 4 ---- .../const-item-no-type/dont-suggest-type-error.rs} | 0 .../const-item-no-type/dont-suggest-type-error.stderr} | 4 ++-- .../const-item-no-type/empty-array.rs} | 0 .../const-item-no-type/empty-array.stderr} | 4 ++-- .../const-item-no-type/in-macro.rs} | 0 .../const-item-no-type/in-macro.stderr} | 6 +++--- .../const-item-no-type/with-colon.fixed} | 0 .../const-item-no-type/with-colon.rs} | 0 .../const-item-no-type/with-colon.stderr} | 4 ++-- 10 files changed, 9 insertions(+), 13 deletions(-) rename tests/ui/{typeck/issue-79040.rs => consts/const-item-no-type/dont-suggest-type-error.rs} (100%) rename tests/ui/{typeck/issue-79040.stderr => consts/const-item-no-type/dont-suggest-type-error.stderr} (85%) rename tests/ui/{parser/issues/issue-89574.rs => consts/const-item-no-type/empty-array.rs} (100%) rename tests/ui/{parser/issues/issue-89574.stderr => consts/const-item-no-type/empty-array.stderr} (88%) rename tests/ui/{macros/issue-69396-const-no-type-in-macro.rs => consts/const-item-no-type/in-macro.rs} (100%) rename tests/ui/{macros/issue-69396-const-no-type-in-macro.stderr => consts/const-item-no-type/in-macro.stderr} (89%) rename tests/ui/{typeck/issue-100164.fixed => consts/const-item-no-type/with-colon.fixed} (100%) rename tests/ui/{typeck/issue-100164.rs => consts/const-item-no-type/with-colon.rs} (100%) rename tests/ui/{typeck/issue-100164.stderr => consts/const-item-no-type/with-colon.stderr} (82%) diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt index 1500c82c411a..45187a0b6450 100644 --- a/src/tools/tidy/src/issues.txt +++ b/src/tools/tidy/src/issues.txt @@ -1583,7 +1583,6 @@ ui/macros/issue-6596-1.rs ui/macros/issue-6596-2.rs ui/macros/issue-68058.rs ui/macros/issue-68060.rs -ui/macros/issue-69396-const-no-type-in-macro.rs ui/macros/issue-69838-mods-relative-to-included-path.rs ui/macros/issue-70446.rs ui/macros/issue-75982-foreign-macro-weird-mod.rs @@ -2100,7 +2099,6 @@ ui/parser/issues/issue-88770.rs ui/parser/issues/issue-88818.rs ui/parser/issues/issue-89388.rs ui/parser/issues/issue-89396.rs -ui/parser/issues/issue-89574.rs ui/parser/issues/issue-89971-outer-attr-following-inner-attr-ice.rs ui/parser/issues/issue-90728.rs ui/parser/issues/issue-90993.rs @@ -2880,7 +2878,6 @@ ui/type/type-check/issue-88577-check-fn-with-more-than-65535-arguments.rs ui/typeck/auxiliary/issue-29181.rs ui/typeck/auxiliary/issue-36708.rs ui/typeck/auxiliary/issue-81943-lib.rs -ui/typeck/issue-100164.rs ui/typeck/issue-100246.rs ui/typeck/issue-100285.rs ui/typeck/issue-103899.rs @@ -2937,7 +2934,6 @@ ui/typeck/issue-74933.rs ui/typeck/issue-75883.rs ui/typeck/issue-75889.rs ui/typeck/issue-7813.rs -ui/typeck/issue-79040.rs ui/typeck/issue-80207-unsized-return.rs ui/typeck/issue-80779.rs ui/typeck/issue-81293.rs diff --git a/tests/ui/typeck/issue-79040.rs b/tests/ui/consts/const-item-no-type/dont-suggest-type-error.rs similarity index 100% rename from tests/ui/typeck/issue-79040.rs rename to tests/ui/consts/const-item-no-type/dont-suggest-type-error.rs diff --git a/tests/ui/typeck/issue-79040.stderr b/tests/ui/consts/const-item-no-type/dont-suggest-type-error.stderr similarity index 85% rename from tests/ui/typeck/issue-79040.stderr rename to tests/ui/consts/const-item-no-type/dont-suggest-type-error.stderr index 4ab8df8f6c93..8f1fcc645b9c 100644 --- a/tests/ui/typeck/issue-79040.stderr +++ b/tests/ui/consts/const-item-no-type/dont-suggest-type-error.stderr @@ -1,5 +1,5 @@ error[E0369]: cannot add `{integer}` to `&str` - --> $DIR/issue-79040.rs:2:25 + --> $DIR/dont-suggest-type-error.rs:2:25 | LL | const FOO = "hello" + 1; | ------- ^ - {integer} @@ -7,7 +7,7 @@ LL | const FOO = "hello" + 1; | &str error: missing type for `const` item - --> $DIR/issue-79040.rs:2:14 + --> $DIR/dont-suggest-type-error.rs:2:14 | LL | const FOO = "hello" + 1; | ^ diff --git a/tests/ui/parser/issues/issue-89574.rs b/tests/ui/consts/const-item-no-type/empty-array.rs similarity index 100% rename from tests/ui/parser/issues/issue-89574.rs rename to tests/ui/consts/const-item-no-type/empty-array.rs diff --git a/tests/ui/parser/issues/issue-89574.stderr b/tests/ui/consts/const-item-no-type/empty-array.stderr similarity index 88% rename from tests/ui/parser/issues/issue-89574.stderr rename to tests/ui/consts/const-item-no-type/empty-array.stderr index f40f5aded8ef..fe307d50353e 100644 --- a/tests/ui/parser/issues/issue-89574.stderr +++ b/tests/ui/consts/const-item-no-type/empty-array.stderr @@ -1,11 +1,11 @@ error[E0282]: type annotations needed - --> $DIR/issue-89574.rs:2:25 + --> $DIR/empty-array.rs:2:25 | LL | const EMPTY_ARRAY = []; | ^^ cannot infer type error: missing type for `const` item - --> $DIR/issue-89574.rs:2:22 + --> $DIR/empty-array.rs:2:22 | LL | const EMPTY_ARRAY = []; | ^ diff --git a/tests/ui/macros/issue-69396-const-no-type-in-macro.rs b/tests/ui/consts/const-item-no-type/in-macro.rs similarity index 100% rename from tests/ui/macros/issue-69396-const-no-type-in-macro.rs rename to tests/ui/consts/const-item-no-type/in-macro.rs diff --git a/tests/ui/macros/issue-69396-const-no-type-in-macro.stderr b/tests/ui/consts/const-item-no-type/in-macro.stderr similarity index 89% rename from tests/ui/macros/issue-69396-const-no-type-in-macro.stderr rename to tests/ui/consts/const-item-no-type/in-macro.stderr index 4342d7d88f54..d6182aa11427 100644 --- a/tests/ui/macros/issue-69396-const-no-type-in-macro.stderr +++ b/tests/ui/consts/const-item-no-type/in-macro.stderr @@ -1,5 +1,5 @@ error[E0428]: the name `A` is defined multiple times - --> $DIR/issue-69396-const-no-type-in-macro.rs:4:13 + --> $DIR/in-macro.rs:4:13 | LL | const A = "A".$fn(); | ^^^^^^^^^^^^^^^^^^^^ `A` redefined here @@ -14,7 +14,7 @@ LL | | } = note: this error originates in the macro `suite` (in Nightly builds, run with -Z macro-backtrace for more info) error: missing type for `const` item - --> $DIR/issue-69396-const-no-type-in-macro.rs:4:20 + --> $DIR/in-macro.rs:4:20 | LL | const A = "A".$fn(); | ^ help: provide a type for the constant: `: usize` @@ -28,7 +28,7 @@ LL | | } = note: this error originates in the macro `suite` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0121]: missing type for item - --> $DIR/issue-69396-const-no-type-in-macro.rs:4:20 + --> $DIR/in-macro.rs:4:20 | LL | const A = "A".$fn(); | ^ not allowed in type signatures diff --git a/tests/ui/typeck/issue-100164.fixed b/tests/ui/consts/const-item-no-type/with-colon.fixed similarity index 100% rename from tests/ui/typeck/issue-100164.fixed rename to tests/ui/consts/const-item-no-type/with-colon.fixed diff --git a/tests/ui/typeck/issue-100164.rs b/tests/ui/consts/const-item-no-type/with-colon.rs similarity index 100% rename from tests/ui/typeck/issue-100164.rs rename to tests/ui/consts/const-item-no-type/with-colon.rs diff --git a/tests/ui/typeck/issue-100164.stderr b/tests/ui/consts/const-item-no-type/with-colon.stderr similarity index 82% rename from tests/ui/typeck/issue-100164.stderr rename to tests/ui/consts/const-item-no-type/with-colon.stderr index 06a132d65142..adbea1f355a0 100644 --- a/tests/ui/typeck/issue-100164.stderr +++ b/tests/ui/consts/const-item-no-type/with-colon.stderr @@ -1,11 +1,11 @@ error: missing type for `const` item - --> $DIR/issue-100164.rs:3:10 + --> $DIR/with-colon.rs:3:10 | LL | const _A: = 123; | ^ help: provide a type for the constant: `i32` error: missing type for `const` item - --> $DIR/issue-100164.rs:7:14 + --> $DIR/with-colon.rs:7:14 | LL | const _B: = 123; | ^ help: provide a type for the constant: `i32` From 2bc2a0db6956f960a5218cea19f07ff8dd4c04cd Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 10 Dec 2025 20:18:42 +0100 Subject: [PATCH 47/64] For now, ignore target checking for doc attributes in attr_parsing --- .../rustc_attr_parsing/src/attributes/doc.rs | 66 ++++++++++--------- .../ui/attributes/issue-115264-expr-field.rs | 2 - .../attributes/issue-115264-expr-field.stderr | 12 ---- tests/ui/attributes/issue-115264-pat-field.rs | 2 - .../attributes/issue-115264-pat-field.stderr | 12 ---- tests/ui/lint/unused/useless-comment.rs | 6 -- tests/ui/lint/unused/useless-comment.stderr | 62 +++++------------ .../rustdoc/check-doc-alias-attr-location.rs | 8 --- .../check-doc-alias-attr-location.stderr | 45 ++----------- 9 files changed, 53 insertions(+), 162 deletions(-) delete mode 100644 tests/ui/attributes/issue-115264-expr-field.stderr delete mode 100644 tests/ui/attributes/issue-115264-pat-field.stderr diff --git a/compiler/rustc_attr_parsing/src/attributes/doc.rs b/compiler/rustc_attr_parsing/src/attributes/doc.rs index ccb6a873fb12..2fe1b4ad174c 100644 --- a/compiler/rustc_attr_parsing/src/attributes/doc.rs +++ b/compiler/rustc_attr_parsing/src/attributes/doc.rs @@ -7,7 +7,7 @@ use rustc_hir::lints::AttributeLintKind; use rustc_span::{Span, Symbol, edition, sym}; use thin_vec::ThinVec; -use super::prelude::{Allow, AllowedTargets, Error, MethodKind, Target}; +use super::prelude::{ALL_TARGETS, AllowedTargets}; use super::{AcceptMapping, AttributeParser}; use crate::context::{AcceptContext, FinalizeContext, Stage}; use crate::parser::{ArgParser, MetaItemOrLitParser, MetaItemParser, PathParser}; @@ -583,37 +583,39 @@ impl AttributeParser for DocParser { this.accept_single_doc_attr(cx, args); }, )]; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[ - Allow(Target::ExternCrate), - Allow(Target::Use), - Allow(Target::Static), - Allow(Target::Const), - Allow(Target::Fn), - Allow(Target::Mod), - Allow(Target::ForeignMod), - Allow(Target::TyAlias), - Allow(Target::Enum), - Allow(Target::Variant), - Allow(Target::Struct), - Allow(Target::Field), - Allow(Target::Union), - Allow(Target::Trait), - Allow(Target::TraitAlias), - Allow(Target::Impl { of_trait: true }), - Allow(Target::Impl { of_trait: false }), - Allow(Target::AssocConst), - Allow(Target::Method(MethodKind::Inherent)), - Allow(Target::Method(MethodKind::Trait { body: true })), - Allow(Target::Method(MethodKind::Trait { body: false })), - Allow(Target::Method(MethodKind::TraitImpl)), - Allow(Target::AssocTy), - Allow(Target::ForeignFn), - Allow(Target::ForeignStatic), - Allow(Target::ForeignTy), - Allow(Target::MacroDef), - Allow(Target::Crate), - Error(Target::WherePredicate), - ]); + // FIXME: Currently emitted from 2 different places, generating duplicated warnings. + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); + // const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[ + // Allow(Target::ExternCrate), + // Allow(Target::Use), + // Allow(Target::Static), + // Allow(Target::Const), + // Allow(Target::Fn), + // Allow(Target::Mod), + // Allow(Target::ForeignMod), + // Allow(Target::TyAlias), + // Allow(Target::Enum), + // Allow(Target::Variant), + // Allow(Target::Struct), + // Allow(Target::Field), + // Allow(Target::Union), + // Allow(Target::Trait), + // Allow(Target::TraitAlias), + // Allow(Target::Impl { of_trait: true }), + // Allow(Target::Impl { of_trait: false }), + // Allow(Target::AssocConst), + // Allow(Target::Method(MethodKind::Inherent)), + // Allow(Target::Method(MethodKind::Trait { body: true })), + // Allow(Target::Method(MethodKind::Trait { body: false })), + // Allow(Target::Method(MethodKind::TraitImpl)), + // Allow(Target::AssocTy), + // Allow(Target::ForeignFn), + // Allow(Target::ForeignStatic), + // Allow(Target::ForeignTy), + // Allow(Target::MacroDef), + // Allow(Target::Crate), + // Error(Target::WherePredicate), + // ]); fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option { if self.nb_doc_attrs != 0 { diff --git a/tests/ui/attributes/issue-115264-expr-field.rs b/tests/ui/attributes/issue-115264-expr-field.rs index d8189626fb0f..8adb68deb5b4 100644 --- a/tests/ui/attributes/issue-115264-expr-field.rs +++ b/tests/ui/attributes/issue-115264-expr-field.rs @@ -12,8 +12,6 @@ struct X { fn main() { let _ = X { #[doc(alias = "StructItem")] - //~^ WARN: attribute cannot be used on struct fields - //~| WARN: this was previously accepted by the compiler but is being phased out foo: 123, }; } diff --git a/tests/ui/attributes/issue-115264-expr-field.stderr b/tests/ui/attributes/issue-115264-expr-field.stderr deleted file mode 100644 index 6bb9dfc90c93..000000000000 --- a/tests/ui/attributes/issue-115264-expr-field.stderr +++ /dev/null @@ -1,12 +0,0 @@ -warning: `#[doc]` attribute cannot be used on struct fields - --> $DIR/issue-115264-expr-field.rs:14:9 - | -LL | #[doc(alias = "StructItem")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[doc]` can be applied to associated consts, associated types, constants, crates, data types, enum variants, extern crates, foreign modules, foreign statics, functions, impl blocks, macro defs, modules, statics, struct fields, trait aliases, traits, type aliases, unions, and use statements - = note: requested on the command line with `-W unused-attributes` - -warning: 1 warning emitted - diff --git a/tests/ui/attributes/issue-115264-pat-field.rs b/tests/ui/attributes/issue-115264-pat-field.rs index 0c8966b5893f..53e3b4524d60 100644 --- a/tests/ui/attributes/issue-115264-pat-field.rs +++ b/tests/ui/attributes/issue-115264-pat-field.rs @@ -12,8 +12,6 @@ struct X { fn main() { let X { #[doc(alias = "StructItem")] - //~^ WARN: attribute cannot be used on pattern fields - //~| WARN: this was previously accepted by the compiler but is being phased out foo } = X { foo: 123 diff --git a/tests/ui/attributes/issue-115264-pat-field.stderr b/tests/ui/attributes/issue-115264-pat-field.stderr deleted file mode 100644 index a5b221110789..000000000000 --- a/tests/ui/attributes/issue-115264-pat-field.stderr +++ /dev/null @@ -1,12 +0,0 @@ -warning: `#[doc]` attribute cannot be used on pattern fields - --> $DIR/issue-115264-pat-field.rs:14:9 - | -LL | #[doc(alias = "StructItem")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[doc]` can be applied to associated consts, associated types, constants, crates, data types, enum variants, extern crates, foreign modules, foreign statics, functions, impl blocks, macro defs, modules, statics, struct fields, trait aliases, traits, type aliases, unions, and use statements - = note: requested on the command line with `-W unused-attributes` - -warning: 1 warning emitted - diff --git a/tests/ui/lint/unused/useless-comment.rs b/tests/ui/lint/unused/useless-comment.rs index fee6cff640f6..24ff91752081 100644 --- a/tests/ui/lint/unused/useless-comment.rs +++ b/tests/ui/lint/unused/useless-comment.rs @@ -18,8 +18,6 @@ fn foo() { /// a //~ ERROR unused doc comment #[doc(test(attr(allow(dead_code))))] //~^ ERROR unused doc comment - //~| ERROR `#[doc]` attribute cannot be used on statements - //~| WARN this was previously accepted by the compiler let x = 12; /// multi-line //~ ERROR unused doc comment @@ -30,8 +28,6 @@ fn foo() { 1 => {}, #[doc(test(attr(allow(dead_code))))] //~^ ERROR unused doc comment - //~| ERROR `#[doc]` attribute cannot be used on match arms [unused_attributes] - //~| WARN this was previously accepted by the compiler _ => {} } @@ -47,8 +43,6 @@ fn foo() { #[doc(test(attr(allow(dead_code))))] //~^ ERROR unused doc comment - //~| ERROR `#[doc]` attribute cannot be used on statements - //~| WARN this was previously accepted by the compiler let x = /** comment */ 47; //~ ERROR unused doc comment /// dox //~ ERROR unused doc comment diff --git a/tests/ui/lint/unused/useless-comment.stderr b/tests/ui/lint/unused/useless-comment.stderr index 3d3937e7a402..22e63caf607a 100644 --- a/tests/ui/lint/unused/useless-comment.stderr +++ b/tests/ui/lint/unused/useless-comment.stderr @@ -33,7 +33,7 @@ LL | unsafe extern "C" { } = help: use `//` for a plain comment error: unused doc comment - --> $DIR/useless-comment.rs:45:5 + --> $DIR/useless-comment.rs:41:5 | LL | /// bar | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ rustdoc does not generate documentation for macro invocations @@ -56,14 +56,14 @@ error: unused doc comment | LL | #[doc(test(attr(allow(dead_code))))] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -... +LL | LL | let x = 12; | ----------- rustdoc does not generate documentation for statements | = help: use `//` for a plain comment error: unused doc comment - --> $DIR/useless-comment.rs:25:5 + --> $DIR/useless-comment.rs:23:5 | LL | / /// multi-line LL | | /// doc comment @@ -73,7 +73,7 @@ LL | / match x { LL | | /// c LL | | 1 => {}, LL | | #[doc(test(attr(allow(dead_code))))] -... | +LL | | LL | | _ => {} LL | | } | |_____- rustdoc does not generate documentation for expressions @@ -81,7 +81,7 @@ LL | | } = help: use `//` for a plain comment error: unused doc comment - --> $DIR/useless-comment.rs:29:9 + --> $DIR/useless-comment.rs:27:9 | LL | /// c | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -91,18 +91,18 @@ LL | 1 => {}, = help: use `//` for a plain comment error: unused doc comment - --> $DIR/useless-comment.rs:31:9 + --> $DIR/useless-comment.rs:29:9 | LL | #[doc(test(attr(allow(dead_code))))] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -... +LL | LL | _ => {} | ------- rustdoc does not generate documentation for match arms | = help: use `//` for a plain comment error: unused doc comment - --> $DIR/useless-comment.rs:38:5 + --> $DIR/useless-comment.rs:34:5 | LL | /// foo | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -112,7 +112,7 @@ LL | unsafe {} = help: use `//` for a plain comment error: unused doc comment - --> $DIR/useless-comment.rs:41:5 + --> $DIR/useless-comment.rs:37:5 | LL | #[doc = "foo"] | ^^^^^^^^^^^^^^ @@ -123,7 +123,7 @@ LL | 3; = help: use `//` for a plain comment error: unused doc comment - --> $DIR/useless-comment.rs:42:5 + --> $DIR/useless-comment.rs:38:5 | LL | #[doc = "bar"] | ^^^^^^^^^^^^^^ @@ -133,18 +133,18 @@ LL | 3; = help: use `//` for a plain comment error: unused doc comment - --> $DIR/useless-comment.rs:48:5 + --> $DIR/useless-comment.rs:44:5 | LL | #[doc(test(attr(allow(dead_code))))] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -... +LL | LL | let x = /** comment */ 47; | -------------------------- rustdoc does not generate documentation for statements | = help: use `//` for a plain comment error: unused doc comment - --> $DIR/useless-comment.rs:52:13 + --> $DIR/useless-comment.rs:46:13 | LL | let x = /** comment */ 47; | ^^^^^^^^^^^^^^ -- rustdoc does not generate documentation for expressions @@ -152,7 +152,7 @@ LL | let x = /** comment */ 47; = help: use `/* */` for a plain comment error: unused doc comment - --> $DIR/useless-comment.rs:54:5 + --> $DIR/useless-comment.rs:48:5 | LL | /// dox | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -163,37 +163,5 @@ LL | | } | = help: use `//` for a plain comment -error: `#[doc]` attribute cannot be used on statements - --> $DIR/useless-comment.rs:19:5 - | -LL | #[doc(test(attr(allow(dead_code))))] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[doc]` can be applied to associated consts, associated types, constants, crates, data types, enum variants, extern crates, foreign modules, foreign statics, functions, impl blocks, macro defs, modules, statics, struct fields, trait aliases, traits, type aliases, unions, and use statements -note: the lint level is defined here - --> $DIR/useless-comment.rs:4:9 - | -LL | #![deny(unused_attributes)] - | ^^^^^^^^^^^^^^^^^ - -error: `#[doc]` attribute cannot be used on match arms - --> $DIR/useless-comment.rs:31:9 - | -LL | #[doc(test(attr(allow(dead_code))))] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[doc]` can be applied to associated consts, associated types, constants, crates, data types, enum variants, extern crates, foreign modules, foreign statics, functions, impl blocks, macro defs, modules, statics, struct fields, trait aliases, traits, type aliases, unions, and use statements - -error: `#[doc]` attribute cannot be used on statements - --> $DIR/useless-comment.rs:48:5 - | -LL | #[doc(test(attr(allow(dead_code))))] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[doc]` can be applied to associated consts, associated types, constants, crates, data types, enum variants, extern crates, foreign modules, foreign statics, functions, impl blocks, macro defs, modules, statics, struct fields, trait aliases, traits, type aliases, unions, and use statements - -error: aborting due to 18 previous errors +error: aborting due to 15 previous errors diff --git a/tests/ui/rustdoc/check-doc-alias-attr-location.rs b/tests/ui/rustdoc/check-doc-alias-attr-location.rs index 8ba6cfde2d6d..45777c5edf4d 100644 --- a/tests/ui/rustdoc/check-doc-alias-attr-location.rs +++ b/tests/ui/rustdoc/check-doc-alias-attr-location.rs @@ -21,22 +21,14 @@ impl Foo for Bar { type X = i32; fn foo(#[doc(alias = "qux")] _x: u32) -> Self::X { //~^ ERROR - //~| WARN `#[doc]` attribute cannot be used on function params - //~| WARN: this was previously accepted by the compiler #[doc(alias = "stmt")] //~^ ERROR - //~| WARN `#[doc]` attribute cannot be used on statements - //~| WARN: this was previously accepted by the compiler let x = 0; #[doc(alias = "expr")] //~^ ERROR - //~| WARN `#[doc]` attribute cannot be used on expressions - //~| WARN: this was previously accepted by the compiler match x { #[doc(alias = "arm")] //~^ ERROR - //~| WARN `#[doc]` attribute cannot be used on match arms - //~| WARN: this was previously accepted by the compiler _ => 0 } } diff --git a/tests/ui/rustdoc/check-doc-alias-attr-location.stderr b/tests/ui/rustdoc/check-doc-alias-attr-location.stderr index 24be42036f6f..f587c17c1f3e 100644 --- a/tests/ui/rustdoc/check-doc-alias-attr-location.stderr +++ b/tests/ui/rustdoc/check-doc-alias-attr-location.stderr @@ -29,59 +29,22 @@ LL | #[doc(alias = "assoc")] | ^^^^^^^ error: `#[doc(alias = "...")]` isn't allowed on statement - --> $DIR/check-doc-alias-attr-location.rs:26:23 + --> $DIR/check-doc-alias-attr-location.rs:24:23 | LL | #[doc(alias = "stmt")] | ^^^^^^ error: `#[doc(alias = "...")]` isn't allowed on expression - --> $DIR/check-doc-alias-attr-location.rs:31:23 + --> $DIR/check-doc-alias-attr-location.rs:27:23 | LL | #[doc(alias = "expr")] | ^^^^^^ error: `#[doc(alias = "...")]` isn't allowed on match arm - --> $DIR/check-doc-alias-attr-location.rs:36:27 + --> $DIR/check-doc-alias-attr-location.rs:30:27 | LL | #[doc(alias = "arm")] | ^^^^^ -warning: `#[doc]` attribute cannot be used on function params - --> $DIR/check-doc-alias-attr-location.rs:22:12 - | -LL | fn foo(#[doc(alias = "qux")] _x: u32) -> Self::X { - | ^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[doc]` can be applied to associated consts, associated types, constants, crates, data types, enum variants, extern crates, foreign modules, foreign statics, functions, impl blocks, macro defs, modules, statics, struct fields, trait aliases, traits, type aliases, unions, and use statements - = note: requested on the command line with `-W unused-attributes` - -warning: `#[doc]` attribute cannot be used on statements - --> $DIR/check-doc-alias-attr-location.rs:26:9 - | -LL | #[doc(alias = "stmt")] - | ^^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[doc]` can be applied to associated consts, associated types, constants, crates, data types, enum variants, extern crates, foreign modules, foreign statics, functions, impl blocks, macro defs, modules, statics, struct fields, trait aliases, traits, type aliases, unions, and use statements - -warning: `#[doc]` attribute cannot be used on expressions - --> $DIR/check-doc-alias-attr-location.rs:31:9 - | -LL | #[doc(alias = "expr")] - | ^^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[doc]` can be applied to associated consts, associated types, constants, crates, data types, enum variants, extern crates, foreign modules, foreign statics, functions, impl blocks, macro defs, modules, statics, struct fields, trait aliases, traits, type aliases, unions, and use statements - -warning: `#[doc]` attribute cannot be used on match arms - --> $DIR/check-doc-alias-attr-location.rs:36:13 - | -LL | #[doc(alias = "arm")] - | ^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[doc]` can be applied to associated consts, associated types, constants, crates, data types, enum variants, extern crates, foreign modules, foreign statics, functions, impl blocks, macro defs, modules, statics, struct fields, trait aliases, traits, type aliases, unions, and use statements - -error: aborting due to 8 previous errors; 4 warnings emitted +error: aborting due to 8 previous errors From 507b67f45745194e151e373325e7ec2154589484 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sat, 8 Nov 2025 22:26:43 +0000 Subject: [PATCH 48/64] Add test for incorrect macro span replacement --- .../ui/span/macro-span-caller-replacement.rs | 16 ++++++++++ .../span/macro-span-caller-replacement.stderr | 29 +++++++++++++++++++ 2 files changed, 45 insertions(+) create mode 100644 tests/ui/span/macro-span-caller-replacement.rs create mode 100644 tests/ui/span/macro-span-caller-replacement.stderr diff --git a/tests/ui/span/macro-span-caller-replacement.rs b/tests/ui/span/macro-span-caller-replacement.rs new file mode 100644 index 000000000000..45af729beb1a --- /dev/null +++ b/tests/ui/span/macro-span-caller-replacement.rs @@ -0,0 +1,16 @@ +macro_rules! macro_with_format { () => { + fn check_5(arg : usize) -> String { + let s : &str; + if arg < 5 { + s = format!("{arg}"); + } else { + s = String::new(); //~ ERROR mismatched types + } + String::from(s) + } +}} + +fn main() { + macro_with_format!(); //~ ERROR mismatched types + println!( "{}", check_5(6) ); +} diff --git a/tests/ui/span/macro-span-caller-replacement.stderr b/tests/ui/span/macro-span-caller-replacement.stderr new file mode 100644 index 000000000000..1c831f96ec0c --- /dev/null +++ b/tests/ui/span/macro-span-caller-replacement.stderr @@ -0,0 +1,29 @@ +error[E0308]: mismatched types + --> $DIR/macro-span-caller-replacement.rs:5:17 + | +LL | macro_with_format!(); + | ^^^^^^^^^^^^^^^^^^^^ expected `&str`, found `String` + | + = note: this error originates in the macro `format` which comes from the expansion of the macro `macro_with_format` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0308]: mismatched types + --> $DIR/macro-span-caller-replacement.rs:7:17 + | +LL | let s : &str; + | ---- expected due to this type +... +LL | s = String::new(); + | ^^^^^^^^^^^^^ expected `&str`, found `String` +... +LL | macro_with_format!(); + | -------------------- in this macro invocation + | + = note: this error originates in the macro `macro_with_format` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider borrowing here + | +LL | s = &String::new(); + | + + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. From 1bd7934d891cee73664367cfff8f914edda3d9d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sat, 8 Nov 2025 23:35:55 +0000 Subject: [PATCH 49/64] Point at span within local macros even when error happens in nested external macro ``` error[E0308]: mismatched types --> $DIR/macro-span-caller-replacement.rs:5:17 | LL | s = format!("{arg}"); | ^^^^^^^^^^^^^^^^ expected `&str`, found `String` ... LL | macro_with_format!(); | -------------------- in this macro invocation | = note: this error originates in the macro `format` which comes from the expansion of the macro `macro_with_format` (in Nightly builds, run with -Z macro-backtrace for more info) ``` --- compiler/rustc_errors/src/emitter.rs | 9 +- .../tests/fail/panic/tls_macro_drop_panic.rs | 2 +- .../rustc-dev-remap.only-remap.stderr | 3 + .../rustc-dev-remap.remap-unremap.stderr | 5 +- ...diagnostic-derive-doc-comment-field.stderr | 6 + .../diagnostic-derive.stderr | 3 + tests/ui/binop/binary-op-suggest-deref.stderr | 12 +- tests/ui/binop/binop-mul-i32-f32.stderr | 12 +- .../const_param_ty_bad.stderr | 6 + .../const-eval/const-eval-overflow-3b.stderr | 12 +- .../const-eval/const-eval-overflow-4b.stderr | 12 +- tests/ui/consts/const-eval/issue-85155.stderr | 7 +- tests/ui/consts/const-eval/parse_ints.stderr | 12 ++ tests/ui/consts/const-ptr-is-null.stderr | 7 + .../ui/consts/const_transmute_type_id2.stderr | 4 + .../ui/consts/const_transmute_type_id3.stderr | 4 + .../ui/consts/const_transmute_type_id4.stderr | 4 + .../ui/consts/const_transmute_type_id5.stderr | 4 + .../ui/consts/const_transmute_type_id6.stderr | 4 + tests/ui/consts/timeout.stderr | 5 + .../hygiene/cross-crate-name-hiding-2.stderr | 6 +- tests/ui/impl-trait/equality.stderr | 12 +- .../ambiguous-glob-vs-expanded-extern.stderr | 14 +- .../issue-41731-infinite-macro-print.stderr | 14 +- .../issue-41731-infinite-macro-println.stderr | 14 +- .../invalid-iterator-chain-fixable.stderr | 24 +++- ...valid-iterator-chain-with-int-infer.stderr | 8 +- .../iterators/invalid-iterator-chain.stderr | 40 ++++-- tests/ui/mismatched_types/binops.stderr | 12 +- ...oat-integer-subtraction-error-24352.stderr | 12 +- tests/ui/never_type/issue-13352.stderr | 12 +- .../not-suggest-float-literal.stderr | 132 +++++++++++++----- .../suggest-float-literal.stderr | 96 +++++++++---- tests/ui/on-unimplemented/slice-index.stderr | 3 + tests/ui/on-unimplemented/sum.stderr | 16 ++- tests/ui/proc-macro/mixed-site-span.stderr | 28 ++-- .../ui/span/macro-span-caller-replacement.rs | 6 +- .../span/macro-span-caller-replacement.stderr | 5 +- tests/ui/span/multiline-span-simple.stderr | 12 +- ...ut-not-available.alignment_mismatch.stderr | 3 + ...gest-deref-inside-macro-issue-58298.stderr | 7 +- .../invalid-suggest-deref-issue-127590.stderr | 16 +++ tests/ui/try-trait/bad-interconversion.stderr | 6 + .../self-referential-2.current.stderr | 3 + .../self-referential-3.stderr | 3 + .../self-referential-4.stderr | 9 ++ .../self-referential.stderr | 9 ++ tests/ui/type/type-check-defaults.stderr | 12 +- ...0017-format-into-help-deletes-macro.stderr | 21 ++- ...2007-leaked-writeln-macro-internals.stderr | 7 +- tests/ui/typeck/issue-81293.stderr | 12 +- tests/ui/ufcs/ufcs-qpath-self-mismatch.stderr | 24 +++- 52 files changed, 569 insertions(+), 162 deletions(-) diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index d08d5a5a1ea2..78feb60261bd 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -474,9 +474,12 @@ pub trait Emitter { .chain(span.span_labels().iter().map(|sp_label| sp_label.span)) .filter_map(|sp| { if !sp.is_dummy() && source_map.is_imported(sp) { - let maybe_callsite = sp.source_callsite(); - if sp != maybe_callsite { - return Some((sp, maybe_callsite)); + let mut span = sp; + while let Some(callsite) = span.parent_callsite() { + span = callsite; + if !source_map.is_imported(span) { + return Some((sp, span)); + } } } None diff --git a/src/tools/miri/tests/fail/panic/tls_macro_drop_panic.rs b/src/tools/miri/tests/fail/panic/tls_macro_drop_panic.rs index 107d70a3b3c7..a207d3923124 100644 --- a/src/tools/miri/tests/fail/panic/tls_macro_drop_panic.rs +++ b/src/tools/miri/tests/fail/panic/tls_macro_drop_panic.rs @@ -1,7 +1,7 @@ //@error-in-other-file: aborted execution // Backtraces vary wildly between platforms, we have to normalize away almost the entire thing //@normalize-stderr-test: "'main'|''" -> "$$NAME" -//@normalize-stderr-test: ".*(note|-->|\|).*\n" -> "" +//@normalize-stderr-test: ".*(note|-->|:::|\|).*\n" -> "" pub struct NoisyDrop {} diff --git a/tests/ui-fulldeps/rustc-dev-remap.only-remap.stderr b/tests/ui-fulldeps/rustc-dev-remap.only-remap.stderr index 15e2cf66f8f8..d2303ef4bbb5 100644 --- a/tests/ui-fulldeps/rustc-dev-remap.only-remap.stderr +++ b/tests/ui-fulldeps/rustc-dev-remap.only-remap.stderr @@ -18,6 +18,9 @@ help: the following other types implement trait `VisitorResult` = note: `ControlFlow` note: required by a bound in `rustc_ast::visit::Visitor::Result` --> /rustc-dev/xyz/compiler/rustc_ast/src/visit.rs:LL:COL + ::: /rustc-dev/xyz/compiler/rustc_ast/src/visit.rs:LL:COL + | + = note: in this macro invocation = note: this error originates in the macro `common_visitor_and_walkers` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 1 previous error diff --git a/tests/ui-fulldeps/rustc-dev-remap.remap-unremap.stderr b/tests/ui-fulldeps/rustc-dev-remap.remap-unremap.stderr index b9276974c465..50bb60e78d68 100644 --- a/tests/ui-fulldeps/rustc-dev-remap.remap-unremap.stderr +++ b/tests/ui-fulldeps/rustc-dev-remap.remap-unremap.stderr @@ -20,8 +20,11 @@ LL | impl VisitorResult for ControlFlow { note: required by a bound in `rustc_ast::visit::Visitor::Result` --> $COMPILER_DIR_REAL/rustc_ast/src/visit.rs:LL:COL | +LL | type Result: VisitorResult = (); + | ^^^^^^^^^^^^^ required by this bound in `Visitor::Result` +... LL | common_visitor_and_walkers!(Visitor<'a>); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Visitor::Result` + | ---------------------------------------- in this macro invocation = note: this error originates in the macro `common_visitor_and_walkers` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 1 previous error diff --git a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-doc-comment-field.stderr b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-doc-comment-field.stderr index 8b6c4b181c0f..72e150dd5178 100644 --- a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-doc-comment-field.stderr +++ b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-doc-comment-field.stderr @@ -15,6 +15,9 @@ LL | struct NotIntoDiagArg; = help: normalized in stderr note: required by a bound in `Diag::<'a, G>::arg` --> $COMPILER_DIR/rustc_errors/src/diagnostic.rs:LL:CC + ::: $COMPILER_DIR/rustc_errors/src/diagnostic.rs:LL:CC + | + = note: in this macro invocation = note: this error originates in the macro `with_fn` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `NotIntoDiagArg: IntoDiagArg` is not satisfied @@ -34,6 +37,9 @@ LL | struct NotIntoDiagArg; = help: normalized in stderr note: required by a bound in `Diag::<'a, G>::arg` --> $COMPILER_DIR/rustc_errors/src/diagnostic.rs:LL:CC + ::: $COMPILER_DIR/rustc_errors/src/diagnostic.rs:LL:CC + | + = note: in this macro invocation = note: this error originates in the macro `with_fn` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 2 previous errors diff --git a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr index 8a0e753a9c52..f2244a968769 100644 --- a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr +++ b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr @@ -665,6 +665,9 @@ LL | struct Hello {} = help: normalized in stderr note: required by a bound in `Diag::<'a, G>::arg` --> $COMPILER_DIR/rustc_errors/src/diagnostic.rs:LL:CC + ::: $COMPILER_DIR/rustc_errors/src/diagnostic.rs:LL:CC + | + = note: in this macro invocation = note: this error originates in the macro `with_fn` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 85 previous errors diff --git a/tests/ui/binop/binary-op-suggest-deref.stderr b/tests/ui/binop/binary-op-suggest-deref.stderr index 0c9b1d9bd938..eb17c6cbbc66 100644 --- a/tests/ui/binop/binary-op-suggest-deref.stderr +++ b/tests/ui/binop/binary-op-suggest-deref.stderr @@ -305,13 +305,19 @@ LL | let _ = FOO & (*"Sized".to_string().into_boxed_str()); help: the following other types implement trait `BitAnd` --> $SRC_DIR/core/src/ops/bit.rs:LL:COL | - = note: `&i32` implements `BitAnd` + = note: `i32` implements `BitAnd` + ::: $SRC_DIR/core/src/ops/bit.rs:LL:COL | - = note: `&i32` implements `BitAnd` + = note: in this macro invocation + --> $SRC_DIR/core/src/internal_macros.rs:LL:COL + | + = note: `&i32` implements `BitAnd` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | = note: `i32` implements `BitAnd<&i32>` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | - = note: `i32` implements `BitAnd` + = note: `&i32` implements `BitAnd` = note: this error originates in the macro `bitand_impl` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `str` cannot be known at compilation time diff --git a/tests/ui/binop/binop-mul-i32-f32.stderr b/tests/ui/binop/binop-mul-i32-f32.stderr index dc4e7fdf6c14..a8893700b1be 100644 --- a/tests/ui/binop/binop-mul-i32-f32.stderr +++ b/tests/ui/binop/binop-mul-i32-f32.stderr @@ -8,13 +8,19 @@ LL | x * y help: the following other types implement trait `Mul` --> $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&i32` implements `Mul` + = note: `i32` implements `Mul` + ::: $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&i32` implements `Mul` + = note: in this macro invocation + --> $SRC_DIR/core/src/internal_macros.rs:LL:COL + | + = note: `&i32` implements `Mul` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | = note: `i32` implements `Mul<&i32>` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | - = note: `i32` implements `Mul` + = note: `&i32` implements `Mul` = note: this error originates in the macro `mul_impl` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_bad.stderr b/tests/ui/const-generics/adt_const_params/const_param_ty_bad.stderr index 75718fbbba0a..5109dccd96a1 100644 --- a/tests/ui/const-generics/adt_const_params/const_param_ty_bad.stderr +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_bad.stderr @@ -84,6 +84,9 @@ LL | check(&mut () as *mut ()); | help: the trait `ConstParamTy_` is implemented for `()` --> $SRC_DIR/core/src/marker.rs:LL:COL + ::: $SRC_DIR/core/src/marker.rs:LL:COL + | + = note: in this macro invocation note: required by a bound in `check` --> $DIR/const_param_ty_bad.rs:4:18 | @@ -101,6 +104,9 @@ LL | check(&() as *const ()); | help: the trait `ConstParamTy_` is implemented for `()` --> $SRC_DIR/core/src/marker.rs:LL:COL + ::: $SRC_DIR/core/src/marker.rs:LL:COL + | + = note: in this macro invocation note: required by a bound in `check` --> $DIR/const_param_ty_bad.rs:4:18 | diff --git a/tests/ui/consts/const-eval/const-eval-overflow-3b.stderr b/tests/ui/consts/const-eval/const-eval-overflow-3b.stderr index 4209e4bcee52..54d77b1bf3e9 100644 --- a/tests/ui/consts/const-eval/const-eval-overflow-3b.stderr +++ b/tests/ui/consts/const-eval/const-eval-overflow-3b.stderr @@ -14,13 +14,19 @@ LL | = [0; (i8::MAX + 1u8) as usize]; help: the following other types implement trait `Add` --> $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&i8` implements `Add` + = note: `i8` implements `Add` + ::: $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&i8` implements `Add` + = note: in this macro invocation + --> $SRC_DIR/core/src/internal_macros.rs:LL:COL + | + = note: `&i8` implements `Add` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | = note: `i8` implements `Add<&i8>` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | - = note: `i8` implements `Add` + = note: `&i8` implements `Add` = note: this error originates in the macro `add_impl` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 2 previous errors diff --git a/tests/ui/consts/const-eval/const-eval-overflow-4b.stderr b/tests/ui/consts/const-eval/const-eval-overflow-4b.stderr index 2677d7956cc9..6c6472610b72 100644 --- a/tests/ui/consts/const-eval/const-eval-overflow-4b.stderr +++ b/tests/ui/consts/const-eval/const-eval-overflow-4b.stderr @@ -14,13 +14,19 @@ LL | : [u32; (i8::MAX as i8 + 1u8) as usize] help: the following other types implement trait `Add` --> $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&i8` implements `Add` + = note: `i8` implements `Add` + ::: $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&i8` implements `Add` + = note: in this macro invocation + --> $SRC_DIR/core/src/internal_macros.rs:LL:COL + | + = note: `&i8` implements `Add` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | = note: `i8` implements `Add<&i8>` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | - = note: `i8` implements `Add` + = note: `&i8` implements `Add` = note: this error originates in the macro `add_impl` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0604]: only `u8` can be cast as `char`, not `i8` diff --git a/tests/ui/consts/const-eval/issue-85155.stderr b/tests/ui/consts/const-eval/issue-85155.stderr index 486d2adaf8cd..dfc784bc7a4f 100644 --- a/tests/ui/consts/const-eval/issue-85155.stderr +++ b/tests/ui/consts/const-eval/issue-85155.stderr @@ -5,10 +5,13 @@ LL | let _ = 1 / ((IMM >= MIN && IMM <= MAX) as usize); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `post_monomorphization_error::ValidateConstImm::<2, 0, 1>::VALID` failed here note: erroneous constant encountered - --> $DIR/auxiliary/post_monomorphization_error.rs:19:5 + --> $DIR/auxiliary/post_monomorphization_error.rs:13:17 | +LL | let _ = $crate::ValidateConstImm::<$imm, 0, { (1 << 1) - 1 }>::VALID; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... LL | static_assert_imm1!(IMM1); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | ------------------------- in this macro invocation | = note: this note originates in the macro `static_assert_imm1` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/consts/const-eval/parse_ints.stderr b/tests/ui/consts/const-eval/parse_ints.stderr index 9c9d083e7ca2..7f42e20cf8e8 100644 --- a/tests/ui/consts/const-eval/parse_ints.stderr +++ b/tests/ui/consts/const-eval/parse_ints.stderr @@ -6,8 +6,14 @@ LL | const _TOO_LOW: () = { u64::from_str_radix("12345ABCD", 1); }; | note: inside `core::num::::from_str_radix` --> $SRC_DIR/core/src/num/mod.rs:LL:COL + ::: $SRC_DIR/core/src/num/mod.rs:LL:COL + | + = note: in this macro invocation note: inside `core::num::::from_ascii_radix` --> $SRC_DIR/core/src/num/mod.rs:LL:COL + ::: $SRC_DIR/core/src/num/mod.rs:LL:COL + | + = note: in this macro invocation = note: this error originates in the macro `from_str_int_impl` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0080]: evaluation panicked: from_ascii_radix: radix must lie in the range `[2, 36]` @@ -18,8 +24,14 @@ LL | const _TOO_HIGH: () = { u64::from_str_radix("12345ABCD", 37); }; | note: inside `core::num::::from_str_radix` --> $SRC_DIR/core/src/num/mod.rs:LL:COL + ::: $SRC_DIR/core/src/num/mod.rs:LL:COL + | + = note: in this macro invocation note: inside `core::num::::from_ascii_radix` --> $SRC_DIR/core/src/num/mod.rs:LL:COL + ::: $SRC_DIR/core/src/num/mod.rs:LL:COL + | + = note: in this macro invocation = note: this error originates in the macro `from_str_int_impl` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 2 previous errors diff --git a/tests/ui/consts/const-ptr-is-null.stderr b/tests/ui/consts/const-ptr-is-null.stderr index be0a1346c647..b532ed9d4c5f 100644 --- a/tests/ui/consts/const-ptr-is-null.stderr +++ b/tests/ui/consts/const-ptr-is-null.stderr @@ -5,9 +5,16 @@ LL | assert!(!ptr.wrapping_sub(512).is_null()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `MAYBE_NULL` failed inside this call | note: inside `std::ptr::const_ptr::::is_null` + --> $SRC_DIR/core/src/intrinsics/mod.rs:LL:COL --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL + ::: $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL + | + = note: in this macro invocation note: inside `std::ptr::const_ptr::::is_null::compiletime` + --> $SRC_DIR/core/src/panic.rs:LL:COL --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL + | + = note: in this macro invocation error: aborting due to 1 previous error diff --git a/tests/ui/consts/const_transmute_type_id2.stderr b/tests/ui/consts/const_transmute_type_id2.stderr index 5646eb1257d1..b420deaa49ce 100644 --- a/tests/ui/consts/const_transmute_type_id2.stderr +++ b/tests/ui/consts/const_transmute_type_id2.stderr @@ -5,7 +5,11 @@ LL | assert!(a == b); | ^^^^^^ evaluation of `_` failed inside this call | note: inside `::eq` + --> $SRC_DIR/core/src/intrinsics/mod.rs:LL:COL --> $SRC_DIR/core/src/any.rs:LL:COL + ::: $SRC_DIR/core/src/any.rs:LL:COL + | + = note: in this macro invocation note: inside `::eq::compiletime` --> $SRC_DIR/core/src/any.rs:LL:COL = note: this error originates in the macro `$crate::intrinsics::const_eval_select` which comes from the expansion of the macro `crate::intrinsics::const_eval_select` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/consts/const_transmute_type_id3.stderr b/tests/ui/consts/const_transmute_type_id3.stderr index e731f496652e..9f796cda6145 100644 --- a/tests/ui/consts/const_transmute_type_id3.stderr +++ b/tests/ui/consts/const_transmute_type_id3.stderr @@ -5,7 +5,11 @@ LL | assert!(a == b); | ^^^^^^ evaluation of `_` failed inside this call | note: inside `::eq` + --> $SRC_DIR/core/src/intrinsics/mod.rs:LL:COL --> $SRC_DIR/core/src/any.rs:LL:COL + ::: $SRC_DIR/core/src/any.rs:LL:COL + | + = note: in this macro invocation note: inside `::eq::compiletime` --> $SRC_DIR/core/src/any.rs:LL:COL = note: this error originates in the macro `$crate::intrinsics::const_eval_select` which comes from the expansion of the macro `crate::intrinsics::const_eval_select` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/consts/const_transmute_type_id4.stderr b/tests/ui/consts/const_transmute_type_id4.stderr index b224227cf352..c844b10d78cf 100644 --- a/tests/ui/consts/const_transmute_type_id4.stderr +++ b/tests/ui/consts/const_transmute_type_id4.stderr @@ -5,7 +5,11 @@ LL | assert!(a == b); | ^^^^^^ evaluation of `_` failed inside this call | note: inside `::eq` + --> $SRC_DIR/core/src/intrinsics/mod.rs:LL:COL --> $SRC_DIR/core/src/any.rs:LL:COL + ::: $SRC_DIR/core/src/any.rs:LL:COL + | + = note: in this macro invocation note: inside `::eq::compiletime` --> $SRC_DIR/core/src/any.rs:LL:COL = note: this error originates in the macro `$crate::intrinsics::const_eval_select` which comes from the expansion of the macro `crate::intrinsics::const_eval_select` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/consts/const_transmute_type_id5.stderr b/tests/ui/consts/const_transmute_type_id5.stderr index 6205679ebb64..9a7384eb95b4 100644 --- a/tests/ui/consts/const_transmute_type_id5.stderr +++ b/tests/ui/consts/const_transmute_type_id5.stderr @@ -5,7 +5,11 @@ LL | assert!(b == b); | ^^^^^^ evaluation of `_` failed inside this call | note: inside `::eq` + --> $SRC_DIR/core/src/intrinsics/mod.rs:LL:COL --> $SRC_DIR/core/src/any.rs:LL:COL + ::: $SRC_DIR/core/src/any.rs:LL:COL + | + = note: in this macro invocation note: inside `::eq::compiletime` --> $SRC_DIR/core/src/any.rs:LL:COL = note: this error originates in the macro `$crate::intrinsics::const_eval_select` which comes from the expansion of the macro `crate::intrinsics::const_eval_select` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/consts/const_transmute_type_id6.stderr b/tests/ui/consts/const_transmute_type_id6.stderr index f5d90256e7c6..c0b35f3d1081 100644 --- a/tests/ui/consts/const_transmute_type_id6.stderr +++ b/tests/ui/consts/const_transmute_type_id6.stderr @@ -5,7 +5,11 @@ LL | id == id | ^^^^^^^^ evaluation of `X` failed inside this call | note: inside `::eq` + --> $SRC_DIR/core/src/intrinsics/mod.rs:LL:COL --> $SRC_DIR/core/src/any.rs:LL:COL + ::: $SRC_DIR/core/src/any.rs:LL:COL + | + = note: in this macro invocation note: inside `::eq::compiletime` --> $SRC_DIR/core/src/any.rs:LL:COL = note: this error originates in the macro `$crate::intrinsics::const_eval_select` which comes from the expansion of the macro `crate::intrinsics::const_eval_select` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/consts/timeout.stderr b/tests/ui/consts/timeout.stderr index ecefeff76e96..6afb317c3aff 100644 --- a/tests/ui/consts/timeout.stderr +++ b/tests/ui/consts/timeout.stderr @@ -1,5 +1,10 @@ error: constant evaluation is taking a long time + --> $SRC_DIR/core/src/num/uint_macros.rs:LL:COL + | --> $SRC_DIR/core/src/num/mod.rs:LL:COL + ::: $SRC_DIR/core/src/num/mod.rs:LL:COL + | + = note: in this macro invocation | = note: this lint makes sure the compiler doesn't get stuck due to infinite loops in const eval. If your compilation actually takes a long time, you can safely allow the lint. diff --git a/tests/ui/hygiene/cross-crate-name-hiding-2.stderr b/tests/ui/hygiene/cross-crate-name-hiding-2.stderr index fe3a12e93a7e..336d35099c80 100644 --- a/tests/ui/hygiene/cross-crate-name-hiding-2.stderr +++ b/tests/ui/hygiene/cross-crate-name-hiding-2.stderr @@ -4,10 +4,10 @@ error[E0422]: cannot find struct, variant or union type `MyStruct` in this scope LL | let x = MyStruct {}; | ^^^^^^^^ not found in this scope | - ::: $DIR/auxiliary/use_by_macro.rs:15:1 + ::: $DIR/auxiliary/use_by_macro.rs:7:24 | -LL | x!(my_struct); - | ------------- you might have meant to refer to this struct +LL | pub struct MyStruct; + | -------- you might have meant to refer to this struct error: aborting due to 1 previous error diff --git a/tests/ui/impl-trait/equality.stderr b/tests/ui/impl-trait/equality.stderr index c2b889138c89..7f965b9609a9 100644 --- a/tests/ui/impl-trait/equality.stderr +++ b/tests/ui/impl-trait/equality.stderr @@ -33,13 +33,19 @@ LL | n + sum_to(n - 1) help: the following other types implement trait `Add` --> $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&u32` implements `Add` + = note: `u32` implements `Add` + ::: $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&u32` implements `Add` + = note: in this macro invocation + --> $SRC_DIR/core/src/internal_macros.rs:LL:COL + | + = note: `&u32` implements `Add` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | = note: `u32` implements `Add<&u32>` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | - = note: `u32` implements `Add` + = note: `&u32` implements `Add` = note: this error originates in the macro `add_impl` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 2 previous errors; 1 warning emitted diff --git a/tests/ui/imports/ambiguous-glob-vs-expanded-extern.stderr b/tests/ui/imports/ambiguous-glob-vs-expanded-extern.stderr index c2e775e6c862..4a9a6c99819b 100644 --- a/tests/ui/imports/ambiguous-glob-vs-expanded-extern.stderr +++ b/tests/ui/imports/ambiguous-glob-vs-expanded-extern.stderr @@ -8,10 +8,13 @@ LL | glob_vs_expanded::mac!(); = note: for more information, see issue #114095 = note: ambiguous because of a conflict between a name from a glob import and a macro-expanded name in the same module during import or macro resolution note: `mac` could refer to the macro defined here - --> $DIR/auxiliary/glob-vs-expanded.rs:11:1 + --> $DIR/auxiliary/glob-vs-expanded.rs:9:13 | +LL | () => { pub macro mac() {} } + | ^^^^^^^^^^^^^ +LL | } LL | define_mac!(); - | ^^^^^^^^^^^^^ + | ------------- in this macro invocation note: `mac` could also refer to the macro defined here --> $DIR/auxiliary/glob-vs-expanded.rs:5:9 | @@ -33,10 +36,13 @@ LL | glob_vs_expanded::mac!(); = note: for more information, see issue #114095 = note: ambiguous because of a conflict between a name from a glob import and a macro-expanded name in the same module during import or macro resolution note: `mac` could refer to the macro defined here - --> $DIR/auxiliary/glob-vs-expanded.rs:11:1 + --> $DIR/auxiliary/glob-vs-expanded.rs:9:13 | +LL | () => { pub macro mac() {} } + | ^^^^^^^^^^^^^ +LL | } LL | define_mac!(); - | ^^^^^^^^^^^^^ + | ------------- in this macro invocation note: `mac` could also refer to the macro defined here --> $DIR/auxiliary/glob-vs-expanded.rs:5:9 | diff --git a/tests/ui/infinite/issue-41731-infinite-macro-print.stderr b/tests/ui/infinite/issue-41731-infinite-macro-print.stderr index 84436de9aa37..5f5d2c75525d 100644 --- a/tests/ui/infinite/issue-41731-infinite-macro-print.stderr +++ b/tests/ui/infinite/issue-41731-infinite-macro-print.stderr @@ -1,8 +1,11 @@ error: recursion limit reached while expanding `$crate::format_args!` - --> $DIR/issue-41731-infinite-macro-print.rs:14:5 + --> $DIR/issue-41731-infinite-macro-print.rs:8:13 | +LL | print!(stack!($overflow)) + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +... LL | stack!("overflow"); - | ^^^^^^^^^^^^^^^^^^ + | ------------------ in this macro invocation | = help: consider increasing the recursion limit by adding a `#![recursion_limit = "10"]` attribute to your crate (`issue_41731_infinite_macro_print`) = note: this error originates in the macro `print` which comes from the expansion of the macro `stack` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -23,10 +26,13 @@ LL | stack!("overflow"); = note: to `{ $crate :: io :: _print($crate :: format_args! (stack! ("overflow"))); }` error: format argument must be a string literal - --> $DIR/issue-41731-infinite-macro-print.rs:14:5 + --> $DIR/issue-41731-infinite-macro-print.rs:8:13 | +LL | print!(stack!($overflow)) + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +... LL | stack!("overflow"); - | ^^^^^^^^^^^^^^^^^^ + | ------------------ in this macro invocation | = note: this error originates in the macro `print` which comes from the expansion of the macro `stack` (in Nightly builds, run with -Z macro-backtrace for more info) help: you might be missing a string literal to format with diff --git a/tests/ui/infinite/issue-41731-infinite-macro-println.stderr b/tests/ui/infinite/issue-41731-infinite-macro-println.stderr index 6d0432abe4c5..c19039e305e2 100644 --- a/tests/ui/infinite/issue-41731-infinite-macro-println.stderr +++ b/tests/ui/infinite/issue-41731-infinite-macro-println.stderr @@ -1,8 +1,11 @@ error: recursion limit reached while expanding `$crate::format_args_nl!` - --> $DIR/issue-41731-infinite-macro-println.rs:14:5 + --> $DIR/issue-41731-infinite-macro-println.rs:8:13 | +LL | println!(stack!($overflow)) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... LL | stack!("overflow"); - | ^^^^^^^^^^^^^^^^^^ + | ------------------ in this macro invocation | = help: consider increasing the recursion limit by adding a `#![recursion_limit = "10"]` attribute to your crate (`issue_41731_infinite_macro_println`) = note: this error originates in the macro `println` which comes from the expansion of the macro `stack` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -23,10 +26,13 @@ LL | stack!("overflow"); = note: to `{ $crate :: io :: _print($crate :: format_args_nl! (stack! ("overflow"))); }` error: format argument must be a string literal - --> $DIR/issue-41731-infinite-macro-println.rs:14:5 + --> $DIR/issue-41731-infinite-macro-println.rs:8:13 | +LL | println!(stack!($overflow)) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... LL | stack!("overflow"); - | ^^^^^^^^^^^^^^^^^^ + | ------------------ in this macro invocation | = note: this error originates in the macro `println` which comes from the expansion of the macro `stack` (in Nightly builds, run with -Z macro-backtrace for more info) help: you might be missing a string literal to format with diff --git a/tests/ui/iterators/invalid-iterator-chain-fixable.stderr b/tests/ui/iterators/invalid-iterator-chain-fixable.stderr index bef4cb6b0a1b..99bff6b450b5 100644 --- a/tests/ui/iterators/invalid-iterator-chain-fixable.stderr +++ b/tests/ui/iterators/invalid-iterator-chain-fixable.stderr @@ -35,10 +35,14 @@ LL | println!("{}", scores.sum::()); = help: the trait `Sum<()>` is not implemented for `i32` help: the following other types implement trait `Sum
` --> $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL - | - = note: `i32` implements `Sum<&i32>` | = note: `i32` implements `Sum` + ::: $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL + | + = note: `i32` implements `Sum<&i32>` + ::: $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL + | + = note: in this macro invocation note: the method call chain might not have had the expected associated types --> $DIR/invalid-iterator-chain-fixable.rs:14:10 | @@ -72,10 +76,14 @@ LL | .sum::(), = help: the trait `Sum<()>` is not implemented for `i32` help: the following other types implement trait `Sum` --> $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL - | - = note: `i32` implements `Sum<&i32>` | = note: `i32` implements `Sum` + ::: $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL + | + = note: `i32` implements `Sum<&i32>` + ::: $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL + | + = note: in this macro invocation note: the method call chain might not have had the expected associated types --> $DIR/invalid-iterator-chain-fixable.rs:23:14 | @@ -109,10 +117,14 @@ LL | println!("{}", vec![0, 1].iter().map(|x| { x; }).sum::()); = help: the trait `Sum<()>` is not implemented for `i32` help: the following other types implement trait `Sum` --> $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL - | - = note: `i32` implements `Sum<&i32>` | = note: `i32` implements `Sum` + ::: $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL + | + = note: `i32` implements `Sum<&i32>` + ::: $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL + | + = note: in this macro invocation note: the method call chain might not have had the expected associated types --> $DIR/invalid-iterator-chain-fixable.rs:27:38 | diff --git a/tests/ui/iterators/invalid-iterator-chain-with-int-infer.stderr b/tests/ui/iterators/invalid-iterator-chain-with-int-infer.stderr index 638287ed1c64..c94b716e3131 100644 --- a/tests/ui/iterators/invalid-iterator-chain-with-int-infer.stderr +++ b/tests/ui/iterators/invalid-iterator-chain-with-int-infer.stderr @@ -9,10 +9,14 @@ LL | let x = Some(()).iter().map(|()| 1).sum::(); = help: the trait `Sum<{integer}>` is not implemented for `f32` help: the following other types implement trait `Sum` --> $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL - | - = note: `f32` implements `Sum<&f32>` | = note: `f32` implements `Sum` + ::: $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL + | + = note: `f32` implements `Sum<&f32>` + ::: $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL + | + = note: in this macro invocation note: the method call chain might not have had the expected associated types --> $DIR/invalid-iterator-chain-with-int-infer.rs:2:29 | diff --git a/tests/ui/iterators/invalid-iterator-chain.stderr b/tests/ui/iterators/invalid-iterator-chain.stderr index 0fd9d3999966..7f0c154e255a 100644 --- a/tests/ui/iterators/invalid-iterator-chain.stderr +++ b/tests/ui/iterators/invalid-iterator-chain.stderr @@ -35,10 +35,14 @@ LL | println!("{}", scores.sum::()); = help: the trait `Sum<()>` is not implemented for `i32` help: the following other types implement trait `Sum` --> $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL - | - = note: `i32` implements `Sum<&i32>` | = note: `i32` implements `Sum` + ::: $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL + | + = note: `i32` implements `Sum<&i32>` + ::: $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL + | + = note: in this macro invocation note: the method call chain might not have had the expected associated types --> $DIR/invalid-iterator-chain.rs:12:10 | @@ -71,10 +75,14 @@ LL | .sum::(), = help: the trait `Sum<()>` is not implemented for `i32` help: the following other types implement trait `Sum` --> $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL - | - = note: `i32` implements `Sum<&i32>` | = note: `i32` implements `Sum` + ::: $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL + | + = note: `i32` implements `Sum<&i32>` + ::: $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL + | + = note: in this macro invocation note: the method call chain might not have had the expected associated types --> $DIR/invalid-iterator-chain.rs:25:14 | @@ -114,10 +122,14 @@ LL | .sum::(), = help: the trait `Sum` is not implemented for `i32` help: the following other types implement trait `Sum` --> $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL - | - = note: `i32` implements `Sum<&i32>` | = note: `i32` implements `Sum` + ::: $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL + | + = note: `i32` implements `Sum<&i32>` + ::: $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL + | + = note: in this macro invocation note: the method call chain might not have had the expected associated types --> $DIR/invalid-iterator-chain.rs:33:14 | @@ -148,10 +160,14 @@ LL | println!("{}", vec![0, 1].iter().map(|x| { x; }).sum::()); = help: the trait `Sum<()>` is not implemented for `i32` help: the following other types implement trait `Sum` --> $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL - | - = note: `i32` implements `Sum<&i32>` | = note: `i32` implements `Sum` + ::: $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL + | + = note: `i32` implements `Sum<&i32>` + ::: $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL + | + = note: in this macro invocation note: the method call chain might not have had the expected associated types --> $DIR/invalid-iterator-chain.rs:38:38 | @@ -180,10 +196,14 @@ LL | println!("{}", vec![(), ()].iter().sum::()); = help: the trait `Sum<&()>` is not implemented for `i32` help: the following other types implement trait `Sum` --> $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL - | - = note: `i32` implements `Sum<&i32>` | = note: `i32` implements `Sum` + ::: $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL + | + = note: `i32` implements `Sum<&i32>` + ::: $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL + | + = note: in this macro invocation note: the method call chain might not have had the expected associated types --> $DIR/invalid-iterator-chain.rs:39:33 | diff --git a/tests/ui/mismatched_types/binops.stderr b/tests/ui/mismatched_types/binops.stderr index 504b44dfb7f6..ec2a951aac9a 100644 --- a/tests/ui/mismatched_types/binops.stderr +++ b/tests/ui/mismatched_types/binops.stderr @@ -26,13 +26,19 @@ LL | 2 as usize - Some(1); help: the following other types implement trait `Sub` --> $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&usize` implements `Sub` + = note: `usize` implements `Sub` + ::: $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&usize` implements `Sub` + = note: in this macro invocation + --> $SRC_DIR/core/src/internal_macros.rs:LL:COL + | + = note: `&usize` implements `Sub` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | = note: `usize` implements `Sub<&usize>` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | - = note: `usize` implements `Sub` + = note: `&usize` implements `Sub` = note: this error originates in the macro `sub_impl` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: cannot multiply `{integer}` by `()` diff --git a/tests/ui/mismatched_types/float-integer-subtraction-error-24352.stderr b/tests/ui/mismatched_types/float-integer-subtraction-error-24352.stderr index b2d0ffc4710e..54b536744f75 100644 --- a/tests/ui/mismatched_types/float-integer-subtraction-error-24352.stderr +++ b/tests/ui/mismatched_types/float-integer-subtraction-error-24352.stderr @@ -8,13 +8,19 @@ LL | 1.0f64 - 1 help: the following other types implement trait `Sub` --> $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&f64` implements `Sub` + = note: `f64` implements `Sub` + ::: $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&f64` implements `Sub` + = note: in this macro invocation + --> $SRC_DIR/core/src/internal_macros.rs:LL:COL + | + = note: `&f64` implements `Sub` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | = note: `f64` implements `Sub<&f64>` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | - = note: `f64` implements `Sub` + = note: `&f64` implements `Sub` = note: this error originates in the macro `sub_impl` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider using a floating-point literal by writing it with `.0` | diff --git a/tests/ui/never_type/issue-13352.stderr b/tests/ui/never_type/issue-13352.stderr index 344625af683a..5fcbb4aab993 100644 --- a/tests/ui/never_type/issue-13352.stderr +++ b/tests/ui/never_type/issue-13352.stderr @@ -8,13 +8,19 @@ LL | 2_usize + (loop {}); help: the following other types implement trait `Add` --> $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&usize` implements `Add` + = note: `usize` implements `Add` + ::: $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&usize` implements `Add` + = note: in this macro invocation + --> $SRC_DIR/core/src/internal_macros.rs:LL:COL + | + = note: `&usize` implements `Add` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | = note: `usize` implements `Add<&usize>` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | - = note: `usize` implements `Add` + = note: `&usize` implements `Add` = note: this error originates in the macro `add_impl` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 1 previous error diff --git a/tests/ui/numbers-arithmetic/not-suggest-float-literal.stderr b/tests/ui/numbers-arithmetic/not-suggest-float-literal.stderr index 3f5297be3719..a62bf5b6a04d 100644 --- a/tests/ui/numbers-arithmetic/not-suggest-float-literal.stderr +++ b/tests/ui/numbers-arithmetic/not-suggest-float-literal.stderr @@ -8,13 +8,19 @@ LL | x + 100.0 help: the following other types implement trait `Add` --> $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&u8` implements `Add` + = note: `u8` implements `Add` + ::: $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&u8` implements `Add` + = note: in this macro invocation + --> $SRC_DIR/core/src/internal_macros.rs:LL:COL + | + = note: `&u8` implements `Add` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | = note: `u8` implements `Add<&u8>` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | - = note: `u8` implements `Add` + = note: `&u8` implements `Add` = note: this error originates in the macro `add_impl` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: cannot add `&str` to `f64` @@ -27,13 +33,19 @@ LL | x + "foo" help: the following other types implement trait `Add` --> $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&f64` implements `Add` + = note: `f64` implements `Add` + ::: $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&f64` implements `Add` + = note: in this macro invocation + --> $SRC_DIR/core/src/internal_macros.rs:LL:COL + | + = note: `&f64` implements `Add` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | = note: `f64` implements `Add<&f64>` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | - = note: `f64` implements `Add` + = note: `&f64` implements `Add` = note: this error originates in the macro `add_impl` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: cannot add `{integer}` to `f64` @@ -46,13 +58,19 @@ LL | x + y help: the following other types implement trait `Add` --> $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&f64` implements `Add` + = note: `f64` implements `Add` + ::: $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&f64` implements `Add` + = note: in this macro invocation + --> $SRC_DIR/core/src/internal_macros.rs:LL:COL + | + = note: `&f64` implements `Add` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | = note: `f64` implements `Add<&f64>` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | - = note: `f64` implements `Add` + = note: `&f64` implements `Add` = note: this error originates in the macro `add_impl` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: cannot subtract `{float}` from `u8` @@ -65,13 +83,19 @@ LL | x - 100.0 help: the following other types implement trait `Sub` --> $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&u8` implements `Sub` + = note: `u8` implements `Sub` + ::: $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&u8` implements `Sub` + = note: in this macro invocation + --> $SRC_DIR/core/src/internal_macros.rs:LL:COL + | + = note: `&u8` implements `Sub` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | = note: `u8` implements `Sub<&u8>` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | - = note: `u8` implements `Sub` + = note: `&u8` implements `Sub` = note: this error originates in the macro `sub_impl` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: cannot subtract `&str` from `f64` @@ -84,13 +108,19 @@ LL | x - "foo" help: the following other types implement trait `Sub` --> $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&f64` implements `Sub` + = note: `f64` implements `Sub` + ::: $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&f64` implements `Sub` + = note: in this macro invocation + --> $SRC_DIR/core/src/internal_macros.rs:LL:COL + | + = note: `&f64` implements `Sub` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | = note: `f64` implements `Sub<&f64>` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | - = note: `f64` implements `Sub` + = note: `&f64` implements `Sub` = note: this error originates in the macro `sub_impl` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: cannot subtract `{integer}` from `f64` @@ -103,13 +133,19 @@ LL | x - y help: the following other types implement trait `Sub` --> $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&f64` implements `Sub` + = note: `f64` implements `Sub` + ::: $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&f64` implements `Sub` + = note: in this macro invocation + --> $SRC_DIR/core/src/internal_macros.rs:LL:COL + | + = note: `&f64` implements `Sub` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | = note: `f64` implements `Sub<&f64>` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | - = note: `f64` implements `Sub` + = note: `&f64` implements `Sub` = note: this error originates in the macro `sub_impl` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: cannot multiply `u8` by `{float}` @@ -122,13 +158,19 @@ LL | x * 100.0 help: the following other types implement trait `Mul` --> $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&u8` implements `Mul` + = note: `u8` implements `Mul` + ::: $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&u8` implements `Mul` + = note: in this macro invocation + --> $SRC_DIR/core/src/internal_macros.rs:LL:COL + | + = note: `&u8` implements `Mul` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | = note: `u8` implements `Mul<&u8>` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | - = note: `u8` implements `Mul` + = note: `&u8` implements `Mul` = note: this error originates in the macro `mul_impl` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: cannot multiply `f64` by `&str` @@ -141,13 +183,19 @@ LL | x * "foo" help: the following other types implement trait `Mul` --> $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&f64` implements `Mul` + = note: `f64` implements `Mul` + ::: $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&f64` implements `Mul` + = note: in this macro invocation + --> $SRC_DIR/core/src/internal_macros.rs:LL:COL + | + = note: `&f64` implements `Mul` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | = note: `f64` implements `Mul<&f64>` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | - = note: `f64` implements `Mul` + = note: `&f64` implements `Mul` = note: this error originates in the macro `mul_impl` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: cannot multiply `f64` by `{integer}` @@ -160,13 +208,19 @@ LL | x * y help: the following other types implement trait `Mul` --> $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&f64` implements `Mul` + = note: `f64` implements `Mul` + ::: $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&f64` implements `Mul` + = note: in this macro invocation + --> $SRC_DIR/core/src/internal_macros.rs:LL:COL + | + = note: `&f64` implements `Mul` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | = note: `f64` implements `Mul<&f64>` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | - = note: `f64` implements `Mul` + = note: `&f64` implements `Mul` = note: this error originates in the macro `mul_impl` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: cannot divide `u8` by `{float}` @@ -193,13 +247,19 @@ LL | x / "foo" help: the following other types implement trait `Div` --> $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&f64` implements `Div` + = note: `f64` implements `Div` + ::: $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&f64` implements `Div` + = note: in this macro invocation + --> $SRC_DIR/core/src/internal_macros.rs:LL:COL + | + = note: `&f64` implements `Div` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | = note: `f64` implements `Div<&f64>` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | - = note: `f64` implements `Div` + = note: `&f64` implements `Div` = note: this error originates in the macro `div_impl_float` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: cannot divide `f64` by `{integer}` @@ -212,13 +272,19 @@ LL | x / y help: the following other types implement trait `Div` --> $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&f64` implements `Div` + = note: `f64` implements `Div` + ::: $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&f64` implements `Div` + = note: in this macro invocation + --> $SRC_DIR/core/src/internal_macros.rs:LL:COL + | + = note: `&f64` implements `Div` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | = note: `f64` implements `Div<&f64>` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | - = note: `f64` implements `Div` + = note: `&f64` implements `Div` = note: this error originates in the macro `div_impl_float` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 12 previous errors diff --git a/tests/ui/numbers-arithmetic/suggest-float-literal.stderr b/tests/ui/numbers-arithmetic/suggest-float-literal.stderr index a31ed6154746..65881ca7a82f 100644 --- a/tests/ui/numbers-arithmetic/suggest-float-literal.stderr +++ b/tests/ui/numbers-arithmetic/suggest-float-literal.stderr @@ -8,13 +8,19 @@ LL | x + 100 help: the following other types implement trait `Add` --> $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&f32` implements `Add` + = note: `f32` implements `Add` + ::: $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&f32` implements `Add` + = note: in this macro invocation + --> $SRC_DIR/core/src/internal_macros.rs:LL:COL + | + = note: `&f32` implements `Add` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | = note: `f32` implements `Add<&f32>` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | - = note: `f32` implements `Add` + = note: `&f32` implements `Add` = note: this error originates in the macro `add_impl` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider using a floating-point literal by writing it with `.0` | @@ -31,13 +37,19 @@ LL | x + 100 help: the following other types implement trait `Add` --> $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&f64` implements `Add` + = note: `f64` implements `Add` + ::: $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&f64` implements `Add` + = note: in this macro invocation + --> $SRC_DIR/core/src/internal_macros.rs:LL:COL + | + = note: `&f64` implements `Add` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | = note: `f64` implements `Add<&f64>` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | - = note: `f64` implements `Add` + = note: `&f64` implements `Add` = note: this error originates in the macro `add_impl` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider using a floating-point literal by writing it with `.0` | @@ -54,13 +66,19 @@ LL | x - 100 help: the following other types implement trait `Sub` --> $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&f32` implements `Sub` + = note: `f32` implements `Sub` + ::: $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&f32` implements `Sub` + = note: in this macro invocation + --> $SRC_DIR/core/src/internal_macros.rs:LL:COL + | + = note: `&f32` implements `Sub` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | = note: `f32` implements `Sub<&f32>` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | - = note: `f32` implements `Sub` + = note: `&f32` implements `Sub` = note: this error originates in the macro `sub_impl` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider using a floating-point literal by writing it with `.0` | @@ -77,13 +95,19 @@ LL | x - 100 help: the following other types implement trait `Sub` --> $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&f64` implements `Sub` + = note: `f64` implements `Sub` + ::: $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&f64` implements `Sub` + = note: in this macro invocation + --> $SRC_DIR/core/src/internal_macros.rs:LL:COL + | + = note: `&f64` implements `Sub` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | = note: `f64` implements `Sub<&f64>` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | - = note: `f64` implements `Sub` + = note: `&f64` implements `Sub` = note: this error originates in the macro `sub_impl` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider using a floating-point literal by writing it with `.0` | @@ -100,13 +124,19 @@ LL | x * 100 help: the following other types implement trait `Mul` --> $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&f32` implements `Mul` + = note: `f32` implements `Mul` + ::: $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&f32` implements `Mul` + = note: in this macro invocation + --> $SRC_DIR/core/src/internal_macros.rs:LL:COL + | + = note: `&f32` implements `Mul` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | = note: `f32` implements `Mul<&f32>` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | - = note: `f32` implements `Mul` + = note: `&f32` implements `Mul` = note: this error originates in the macro `mul_impl` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider using a floating-point literal by writing it with `.0` | @@ -123,13 +153,19 @@ LL | x * 100 help: the following other types implement trait `Mul` --> $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&f64` implements `Mul` + = note: `f64` implements `Mul` + ::: $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&f64` implements `Mul` + = note: in this macro invocation + --> $SRC_DIR/core/src/internal_macros.rs:LL:COL + | + = note: `&f64` implements `Mul` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | = note: `f64` implements `Mul<&f64>` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | - = note: `f64` implements `Mul` + = note: `&f64` implements `Mul` = note: this error originates in the macro `mul_impl` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider using a floating-point literal by writing it with `.0` | @@ -146,13 +182,19 @@ LL | x / 100 help: the following other types implement trait `Div` --> $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&f32` implements `Div` + = note: `f32` implements `Div` + ::: $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&f32` implements `Div` + = note: in this macro invocation + --> $SRC_DIR/core/src/internal_macros.rs:LL:COL + | + = note: `&f32` implements `Div` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | = note: `f32` implements `Div<&f32>` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | - = note: `f32` implements `Div` + = note: `&f32` implements `Div` = note: this error originates in the macro `div_impl_float` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider using a floating-point literal by writing it with `.0` | @@ -169,13 +211,19 @@ LL | x / 100 help: the following other types implement trait `Div` --> $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&f64` implements `Div` + = note: `f64` implements `Div` + ::: $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&f64` implements `Div` + = note: in this macro invocation + --> $SRC_DIR/core/src/internal_macros.rs:LL:COL + | + = note: `&f64` implements `Div` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | = note: `f64` implements `Div<&f64>` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | - = note: `f64` implements `Div` + = note: `&f64` implements `Div` = note: this error originates in the macro `div_impl_float` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider using a floating-point literal by writing it with `.0` | diff --git a/tests/ui/on-unimplemented/slice-index.stderr b/tests/ui/on-unimplemented/slice-index.stderr index baf821c45c5e..67b72bd038d8 100644 --- a/tests/ui/on-unimplemented/slice-index.stderr +++ b/tests/ui/on-unimplemented/slice-index.stderr @@ -28,6 +28,9 @@ help: the following other types implement trait `SliceIndex` --> $SRC_DIR/core/src/bstr/traits.rs:LL:COL | = note: `RangeTo` implements `SliceIndex` + ::: $SRC_DIR/core/src/bstr/traits.rs:LL:COL + | + = note: in this macro invocation --> $SRC_DIR/core/src/str/traits.rs:LL:COL | = note: `RangeTo` implements `SliceIndex` diff --git a/tests/ui/on-unimplemented/sum.stderr b/tests/ui/on-unimplemented/sum.stderr index c4650e9f5278..5e82948352f7 100644 --- a/tests/ui/on-unimplemented/sum.stderr +++ b/tests/ui/on-unimplemented/sum.stderr @@ -9,10 +9,14 @@ LL | vec![(), ()].iter().sum::(); = help: the trait `Sum<&()>` is not implemented for `i32` help: the following other types implement trait `Sum` --> $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL - | - = note: `i32` implements `Sum<&i32>` | = note: `i32` implements `Sum` + ::: $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL + | + = note: `i32` implements `Sum<&i32>` + ::: $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL + | + = note: in this macro invocation note: the method call chain might not have had the expected associated types --> $DIR/sum.rs:4:18 | @@ -35,10 +39,14 @@ LL | vec![(), ()].iter().product::(); = help: the trait `Product<&()>` is not implemented for `i32` help: the following other types implement trait `Product` --> $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL - | - = note: `i32` implements `Product<&i32>` | = note: `i32` implements `Product` + ::: $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL + | + = note: `i32` implements `Product<&i32>` + ::: $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL + | + = note: in this macro invocation note: the method call chain might not have had the expected associated types --> $DIR/sum.rs:7:18 | diff --git a/tests/ui/proc-macro/mixed-site-span.stderr b/tests/ui/proc-macro/mixed-site-span.stderr index 2cc7ff8a8867..fd941f65b788 100644 --- a/tests/ui/proc-macro/mixed-site-span.stderr +++ b/tests/ui/proc-macro/mixed-site-span.stderr @@ -112,10 +112,13 @@ LL | test!(); = note: this error originates in the macro `with_crate` which comes from the expansion of the macro `test` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0432]: unresolved import `$crate` - --> $DIR/mixed-site-span.rs:69:5 + --> $DIR/mixed-site-span.rs:67:9 | +LL | invoke_with_ident!{$crate call proc_macro_item} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no `proc_macro_item` in the root +LL | }} LL | test!(); - | ^^^^^^^ no `proc_macro_item` in the root + | ------- in this macro invocation | = note: this error originates in the macro `with_crate` which comes from the expansion of the macro `test` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -262,10 +265,13 @@ LL + token_site_span::TokenItem as _ | error[E0432]: unresolved import `$crate` - --> $DIR/mixed-site-span.rs:110:5 + --> $DIR/mixed-site-span.rs:106:9 | +LL | invoke_with_ident!{$crate mixed TokenItem} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no `TokenItem` in the root +... LL | test!(); - | ^^^^^^^ no `TokenItem` in the root + | ------- in this macro invocation | = note: this error originates in the macro `with_crate` which comes from the expansion of the macro `test` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider importing this struct instead @@ -417,10 +423,13 @@ LL + ($m:ident $s:ident $i:ident) => { ItemUse as _ }; | error[E0432]: unresolved import `$crate` - --> $DIR/mixed-site-span.rs:150:5 + --> $DIR/mixed-site-span.rs:145:9 | +LL | invoke_with_ident!{$crate mixed ItemUse} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no `ItemUse` in the root +... LL | test!(); - | ^^^^^^^ no `ItemUse` in the root + | ------- in this macro invocation | = note: this error originates in the macro `with_crate` which comes from the expansion of the macro `test` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider importing this struct instead @@ -447,10 +456,13 @@ LL + ItemUse as _ | error[E0432]: unresolved import `$crate` - --> $DIR/mixed-site-span.rs:150:5 + --> $DIR/mixed-site-span.rs:148:9 | +LL | invoke_with_ident!{$crate call ItemUse} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no `ItemUse` in the root +LL | }} LL | test!(); - | ^^^^^^^ no `ItemUse` in the root + | ------- in this macro invocation | = note: this error originates in the macro `with_crate` which comes from the expansion of the macro `test` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider importing this struct instead diff --git a/tests/ui/span/macro-span-caller-replacement.rs b/tests/ui/span/macro-span-caller-replacement.rs index 45af729beb1a..8e7239699cd1 100644 --- a/tests/ui/span/macro-span-caller-replacement.rs +++ b/tests/ui/span/macro-span-caller-replacement.rs @@ -2,7 +2,7 @@ macro_rules! macro_with_format { () => { fn check_5(arg : usize) -> String { let s : &str; if arg < 5 { - s = format!("{arg}"); + s = format!("{arg}"); //~ ERROR mismatched types } else { s = String::new(); //~ ERROR mismatched types } @@ -11,6 +11,6 @@ macro_rules! macro_with_format { () => { }} fn main() { - macro_with_format!(); //~ ERROR mismatched types - println!( "{}", check_5(6) ); + macro_with_format!(); + println!( "{}", check_5(6) ); } diff --git a/tests/ui/span/macro-span-caller-replacement.stderr b/tests/ui/span/macro-span-caller-replacement.stderr index 1c831f96ec0c..43be48a9e362 100644 --- a/tests/ui/span/macro-span-caller-replacement.stderr +++ b/tests/ui/span/macro-span-caller-replacement.stderr @@ -1,8 +1,11 @@ error[E0308]: mismatched types --> $DIR/macro-span-caller-replacement.rs:5:17 | +LL | s = format!("{arg}"); + | ^^^^^^^^^^^^^^^^ expected `&str`, found `String` +... LL | macro_with_format!(); - | ^^^^^^^^^^^^^^^^^^^^ expected `&str`, found `String` + | -------------------- in this macro invocation | = note: this error originates in the macro `format` which comes from the expansion of the macro `macro_with_format` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/span/multiline-span-simple.stderr b/tests/ui/span/multiline-span-simple.stderr index af04ceaf8097..e013b3c06bc1 100644 --- a/tests/ui/span/multiline-span-simple.stderr +++ b/tests/ui/span/multiline-span-simple.stderr @@ -8,13 +8,19 @@ LL | foo(1 as u32 + help: the following other types implement trait `Add` --> $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&u32` implements `Add` + = note: `u32` implements `Add` + ::: $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&u32` implements `Add` + = note: in this macro invocation + --> $SRC_DIR/core/src/internal_macros.rs:LL:COL + | + = note: `&u32` implements `Add` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | = note: `u32` implements `Add<&u32>` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | - = note: `u32` implements `Add` + = note: `&u32` implements `Add` = note: this error originates in the macro `add_impl` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 1 previous error diff --git a/tests/ui/stdlib-unit-tests/atomic-from-mut-not-available.alignment_mismatch.stderr b/tests/ui/stdlib-unit-tests/atomic-from-mut-not-available.alignment_mismatch.stderr index 6a8a7b152c54..93e189ffa0d3 100644 --- a/tests/ui/stdlib-unit-tests/atomic-from-mut-not-available.alignment_mismatch.stderr +++ b/tests/ui/stdlib-unit-tests/atomic-from-mut-not-available.alignment_mismatch.stderr @@ -6,6 +6,9 @@ LL | core::sync::atomic::AtomicU64::from_mut(&mut 0u64); | note: if you're trying to build a new `AtomicU64`, consider using `AtomicU64::new` which returns `AtomicU64` --> $SRC_DIR/core/src/sync/atomic.rs:LL:COL + ::: $SRC_DIR/core/src/sync/atomic.rs:LL:COL + | + = note: in this macro invocation = note: this error originates in the macro `atomic_int` (in Nightly builds, run with -Z macro-backtrace for more info) help: there is an associated function `from` with a similar name | diff --git a/tests/ui/suggestions/dont-suggest-deref-inside-macro-issue-58298.stderr b/tests/ui/suggestions/dont-suggest-deref-inside-macro-issue-58298.stderr index 46613e8e1b48..0ed657c7fa99 100644 --- a/tests/ui/suggestions/dont-suggest-deref-inside-macro-issue-58298.stderr +++ b/tests/ui/suggestions/dont-suggest-deref-inside-macro-issue-58298.stderr @@ -1,10 +1,13 @@ error[E0308]: mismatched types - --> $DIR/dont-suggest-deref-inside-macro-issue-58298.rs:11:5 + --> $DIR/dont-suggest-deref-inside-macro-issue-58298.rs:5:14 | +LL | warn(format!("unsupported intrinsic {}", $intrinsic)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `&str`, found `String` +... LL | / intrinsic_match! { LL | | "abc" LL | | }; - | |_____^ expected `&str`, found `String` + | |_____- in this macro invocation | = note: this error originates in the macro `format` which comes from the expansion of the macro `intrinsic_match` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/traits/suggest-dereferences/invalid-suggest-deref-issue-127590.stderr b/tests/ui/traits/suggest-dereferences/invalid-suggest-deref-issue-127590.stderr index 07a54d574df4..3bae5798d047 100644 --- a/tests/ui/traits/suggest-dereferences/invalid-suggest-deref-issue-127590.stderr +++ b/tests/ui/traits/suggest-dereferences/invalid-suggest-deref-issue-127590.stderr @@ -24,7 +24,11 @@ LL | for (src, dest) in std::iter::zip(fields.iter(), &variant.iter()) { | = help: the trait `Iterator` is not implemented for `&std::slice::Iter<'_, {integer}>` help: the trait `Iterator` is implemented for `std::slice::Iter<'_, T>` + --> $SRC_DIR/core/src/slice/iter/macros.rs:LL:COL --> $SRC_DIR/core/src/slice/iter.rs:LL:COL + ::: $SRC_DIR/core/src/slice/iter.rs:LL:COL + | + = note: in this macro invocation = note: required for `Zip, &std::slice::Iter<'_, {integer}>>` to implement `Iterator` = note: required for `Zip, &std::slice::Iter<'_, {integer}>>` to implement `IntoIterator` = note: this error originates in the macro `iterator` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -55,7 +59,11 @@ LL | for (src, dest) in std::iter::zip(fields.iter(), &variant.iter().clone( | = help: the trait `Iterator` is not implemented for `&std::slice::Iter<'_, {integer}>` help: the trait `Iterator` is implemented for `std::slice::Iter<'_, T>` + --> $SRC_DIR/core/src/slice/iter/macros.rs:LL:COL --> $SRC_DIR/core/src/slice/iter.rs:LL:COL + ::: $SRC_DIR/core/src/slice/iter.rs:LL:COL + | + = note: in this macro invocation = note: required for `Zip, &std::slice::Iter<'_, {integer}>>` to implement `Iterator` = note: required for `Zip, &std::slice::Iter<'_, {integer}>>` to implement `IntoIterator` = note: this error originates in the macro `iterator` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -68,7 +76,11 @@ LL | for (src, dest) in std::iter::zip(fields.iter(), &variant.iter()) { | = help: the trait `Iterator` is not implemented for `&std::slice::Iter<'_, {integer}>` help: the trait `Iterator` is implemented for `std::slice::Iter<'_, T>` + --> $SRC_DIR/core/src/slice/iter/macros.rs:LL:COL --> $SRC_DIR/core/src/slice/iter.rs:LL:COL + ::: $SRC_DIR/core/src/slice/iter.rs:LL:COL + | + = note: in this macro invocation = note: required for `&std::slice::Iter<'_, {integer}>` to implement `IntoIterator` = note: this error originates in the macro `iterator` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -80,7 +92,11 @@ LL | for (src, dest) in std::iter::zip(fields.iter(), &variant.iter().clone( | = help: the trait `Iterator` is not implemented for `&std::slice::Iter<'_, {integer}>` help: the trait `Iterator` is implemented for `std::slice::Iter<'_, T>` + --> $SRC_DIR/core/src/slice/iter/macros.rs:LL:COL --> $SRC_DIR/core/src/slice/iter.rs:LL:COL + ::: $SRC_DIR/core/src/slice/iter.rs:LL:COL + | + = note: in this macro invocation = note: required for `&std::slice::Iter<'_, {integer}>` to implement `IntoIterator` = note: this error originates in the macro `iterator` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/try-trait/bad-interconversion.stderr b/tests/ui/try-trait/bad-interconversion.stderr index da5c4d03dccb..61fecaf89917 100644 --- a/tests/ui/try-trait/bad-interconversion.stderr +++ b/tests/ui/try-trait/bad-interconversion.stderr @@ -13,9 +13,15 @@ help: the following other types implement trait `From` --> $SRC_DIR/core/src/convert/num.rs:LL:COL | = note: `u8` implements `From` + ::: $SRC_DIR/core/src/convert/num.rs:LL:COL + | + = note: in this macro invocation --> $SRC_DIR/core/src/ascii/ascii_char.rs:LL:COL | = note: `u8` implements `From` + ::: $SRC_DIR/core/src/ascii/ascii_char.rs:LL:COL + | + = note: in this macro invocation = note: this error originates in the macro `impl_from` which comes from the expansion of the macro `into_int_impl` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the `?` operator can only be used on `Result`s, not `Option`s, in a function that returns `Result` diff --git a/tests/ui/type-alias-impl-trait/self-referential-2.current.stderr b/tests/ui/type-alias-impl-trait/self-referential-2.current.stderr index 2855c90234d2..ca26e3dd03f3 100644 --- a/tests/ui/type-alias-impl-trait/self-referential-2.current.stderr +++ b/tests/ui/type-alias-impl-trait/self-referential-2.current.stderr @@ -9,6 +9,9 @@ LL | 42_i32 help: the trait `PartialEq` is not implemented for `i32` but trait `PartialEq` is implemented for it --> $SRC_DIR/core/src/cmp.rs:LL:COL + ::: $SRC_DIR/core/src/cmp.rs:LL:COL + | + = note: in this macro invocation = note: this error originates in the macro `partial_eq_impl` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 1 previous error diff --git a/tests/ui/type-alias-impl-trait/self-referential-3.stderr b/tests/ui/type-alias-impl-trait/self-referential-3.stderr index 83fed16c0a17..8592de243ada 100644 --- a/tests/ui/type-alias-impl-trait/self-referential-3.stderr +++ b/tests/ui/type-alias-impl-trait/self-referential-3.stderr @@ -10,6 +10,9 @@ LL | i = help: the trait `PartialEq>` is not implemented for `&i32` help: the trait `PartialEq` is implemented for `i32` --> $SRC_DIR/core/src/cmp.rs:LL:COL + ::: $SRC_DIR/core/src/cmp.rs:LL:COL + | + = note: in this macro invocation = note: this error originates in the macro `partial_eq_impl` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 1 previous error diff --git a/tests/ui/type-alias-impl-trait/self-referential-4.stderr b/tests/ui/type-alias-impl-trait/self-referential-4.stderr index 4176bf780294..c6bf1973fcbb 100644 --- a/tests/ui/type-alias-impl-trait/self-referential-4.stderr +++ b/tests/ui/type-alias-impl-trait/self-referential-4.stderr @@ -9,6 +9,9 @@ LL | i = help: the trait `PartialEq>` is not implemented for `&i32` help: the trait `PartialEq` is implemented for `i32` --> $SRC_DIR/core/src/cmp.rs:LL:COL + ::: $SRC_DIR/core/src/cmp.rs:LL:COL + | + = note: in this macro invocation = note: this error originates in the macro `partial_eq_impl` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: can't compare `&i32` with `Foo<'static, 'b>` @@ -22,6 +25,9 @@ LL | i = help: the trait `PartialEq>` is not implemented for `&i32` help: the trait `PartialEq` is implemented for `i32` --> $SRC_DIR/core/src/cmp.rs:LL:COL + ::: $SRC_DIR/core/src/cmp.rs:LL:COL + | + = note: in this macro invocation = note: this error originates in the macro `partial_eq_impl` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: can't compare `&i32` with `Moo<'static, 'a>` @@ -35,6 +41,9 @@ LL | i = help: the trait `PartialEq>` is not implemented for `&i32` help: the trait `PartialEq` is implemented for `i32` --> $SRC_DIR/core/src/cmp.rs:LL:COL + ::: $SRC_DIR/core/src/cmp.rs:LL:COL + | + = note: in this macro invocation = note: this error originates in the macro `partial_eq_impl` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 3 previous errors diff --git a/tests/ui/type-alias-impl-trait/self-referential.stderr b/tests/ui/type-alias-impl-trait/self-referential.stderr index dc5b9ba7b442..7b4e6e9cac52 100644 --- a/tests/ui/type-alias-impl-trait/self-referential.stderr +++ b/tests/ui/type-alias-impl-trait/self-referential.stderr @@ -10,6 +10,9 @@ LL | i = help: the trait `PartialEq>` is not implemented for `&i32` help: the trait `PartialEq` is implemented for `i32` --> $SRC_DIR/core/src/cmp.rs:LL:COL + ::: $SRC_DIR/core/src/cmp.rs:LL:COL + | + = note: in this macro invocation = note: this error originates in the macro `partial_eq_impl` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: can't compare `&i32` with `(i32, Foo<'a, 'b>::{opaque#0}<'a, 'b>)` @@ -24,6 +27,9 @@ LL | (42, i) = help: the trait `PartialEq<(i32, Foo<'a, 'b>::{opaque#0}<'a, 'b>)>` is not implemented for `&i32` help: the trait `PartialEq` is implemented for `i32` --> $SRC_DIR/core/src/cmp.rs:LL:COL + ::: $SRC_DIR/core/src/cmp.rs:LL:COL + | + = note: in this macro invocation = note: this error originates in the macro `partial_eq_impl` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: can't compare `&i32` with `(i32, Moo<'b, 'a>::{opaque#0}<'b, 'a>)` @@ -38,6 +44,9 @@ LL | (42, i) = help: the trait `PartialEq<(i32, Moo<'b, 'a>::{opaque#0}<'b, 'a>)>` is not implemented for `&i32` help: the trait `PartialEq` is implemented for `i32` --> $SRC_DIR/core/src/cmp.rs:LL:COL + ::: $SRC_DIR/core/src/cmp.rs:LL:COL + | + = note: in this macro invocation = note: this error originates in the macro `partial_eq_impl` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 3 previous errors diff --git a/tests/ui/type/type-check-defaults.stderr b/tests/ui/type/type-check-defaults.stderr index 4eab611244a6..a3a2ed5aa725 100644 --- a/tests/ui/type/type-check-defaults.stderr +++ b/tests/ui/type/type-check-defaults.stderr @@ -86,13 +86,19 @@ LL | trait ProjectionPred> where T::Item : Add {} help: the following other types implement trait `Add` --> $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&i32` implements `Add` + = note: `i32` implements `Add` + ::: $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&i32` implements `Add` + = note: in this macro invocation + --> $SRC_DIR/core/src/internal_macros.rs:LL:COL + | + = note: `&i32` implements `Add` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | = note: `i32` implements `Add<&i32>` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | - = note: `i32` implements `Add` + = note: `&i32` implements `Add` note: required by a bound in `ProjectionPred` --> $DIR/type-check-defaults.rs:24:66 | diff --git a/tests/ui/typeck/issue-110017-format-into-help-deletes-macro.stderr b/tests/ui/typeck/issue-110017-format-into-help-deletes-macro.stderr index e4834c0308bc..bc722cdd57a5 100644 --- a/tests/ui/typeck/issue-110017-format-into-help-deletes-macro.stderr +++ b/tests/ui/typeck/issue-110017-format-into-help-deletes-macro.stderr @@ -13,10 +13,13 @@ LL | Err(format!("error: {x}").into()) | +++++++ error[E0308]: mismatched types - --> $DIR/issue-110017-format-into-help-deletes-macro.rs:23:10 + --> $DIR/issue-110017-format-into-help-deletes-macro.rs:17:10 | +LL | format!("error: {}", $x) + | ^^^^^^^^^^^^^^^^^^^^^^^^ expected `Box`, found `String` +... LL | Err(outer!(x)) - | ^^^^^^^^^ expected `Box`, found `String` + | --------- in this macro invocation | = note: expected struct `Box` found struct `String` @@ -27,10 +30,13 @@ LL | format!("error: {}", $x).into() | +++++++ error[E0308]: mismatched types - --> $DIR/issue-110017-format-into-help-deletes-macro.rs:41:2 + --> $DIR/issue-110017-format-into-help-deletes-macro.rs:35:18 | +LL | Err(format!("error: {x}")) + | ^^^^^^^^^^^^^^^^^^^^^ expected `Box`, found `String` +... LL | entire_fn_outer!(); - | ^^^^^^^^^^^^^^^^^^ expected `Box`, found `String` + | ------------------ in this macro invocation | = note: expected struct `Box` found struct `String` @@ -41,10 +47,13 @@ LL | Err(format!("error: {x}").into()) | +++++++ error[E0308]: mismatched types - --> $DIR/issue-110017-format-into-help-deletes-macro.rs:51:5 + --> $DIR/issue-110017-format-into-help-deletes-macro.rs:45:13 | +LL | Err(format!("error: {}", $x)) + | ^^^^^^^^^^^^^^^^^^^^^^^^ expected `Box`, found `String` +... LL | nontrivial!(x) - | ^^^^^^^^^^^^^^ expected `Box`, found `String` + | -------------- in this macro invocation | = note: expected struct `Box` found struct `String` diff --git a/tests/ui/typeck/issue-112007-leaked-writeln-macro-internals.stderr b/tests/ui/typeck/issue-112007-leaked-writeln-macro-internals.stderr index 889d2c94d0cf..30d51420b7cb 100644 --- a/tests/ui/typeck/issue-112007-leaked-writeln-macro-internals.stderr +++ b/tests/ui/typeck/issue-112007-leaked-writeln-macro-internals.stderr @@ -27,13 +27,16 @@ LL | writeln!(w, "but not here")? | + error[E0308]: mismatched types - --> $DIR/issue-112007-leaked-writeln-macro-internals.rs:40:9 + --> $DIR/issue-112007-leaked-writeln-macro-internals.rs:31:9 | +LL | writeln!($w, "but not here") + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found `Result<(), Error>` +... LL | / if true { LL | | writeln!(w, "`;?` here ->")?; LL | | } else { LL | | baz!(w) - | | ^^^^^^^ expected `()`, found `Result<(), Error>` + | | ------- in this macro invocation LL | | } | |_____- expected this to be `()` | diff --git a/tests/ui/typeck/issue-81293.stderr b/tests/ui/typeck/issue-81293.stderr index 8318d31f0946..604f3cca5486 100644 --- a/tests/ui/typeck/issue-81293.stderr +++ b/tests/ui/typeck/issue-81293.stderr @@ -23,13 +23,19 @@ LL | a = c + b * 5; help: the following other types implement trait `Add` --> $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&usize` implements `Add` + = note: `usize` implements `Add` + ::: $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&usize` implements `Add` + = note: in this macro invocation + --> $SRC_DIR/core/src/internal_macros.rs:LL:COL + | + = note: `&usize` implements `Add` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | = note: `usize` implements `Add<&usize>` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | - = note: `usize` implements `Add` + = note: `&usize` implements `Add` = note: this error originates in the macro `add_impl` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 3 previous errors diff --git a/tests/ui/ufcs/ufcs-qpath-self-mismatch.stderr b/tests/ui/ufcs/ufcs-qpath-self-mismatch.stderr index 352638dd0118..dbbee54c185b 100644 --- a/tests/ui/ufcs/ufcs-qpath-self-mismatch.stderr +++ b/tests/ui/ufcs/ufcs-qpath-self-mismatch.stderr @@ -8,13 +8,19 @@ LL | >::add(1, 2); help: the following other types implement trait `Add` --> $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&i32` implements `Add` + = note: `i32` implements `Add` + ::: $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&i32` implements `Add` + = note: in this macro invocation + --> $SRC_DIR/core/src/internal_macros.rs:LL:COL + | + = note: `&i32` implements `Add` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | = note: `i32` implements `Add<&i32>` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | - = note: `i32` implements `Add` + = note: `&i32` implements `Add` = note: this error originates in the macro `add_impl` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0308]: mismatched types @@ -73,13 +79,19 @@ LL | >::add(1, 2); help: the following other types implement trait `Add` --> $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&i32` implements `Add` + = note: `i32` implements `Add` + ::: $SRC_DIR/core/src/ops/arith.rs:LL:COL | - = note: `&i32` implements `Add` + = note: in this macro invocation + --> $SRC_DIR/core/src/internal_macros.rs:LL:COL + | + = note: `&i32` implements `Add` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | = note: `i32` implements `Add<&i32>` + ::: $SRC_DIR/core/src/internal_macros.rs:LL:COL | - = note: `i32` implements `Add` + = note: `&i32` implements `Add` = note: this error originates in the macro `add_impl` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 4 previous errors From c27bcef6f8ca820f9b22a707149485388281a8a8 Mon Sep 17 00:00:00 2001 From: 21aslade Date: Wed, 3 Dec 2025 20:43:27 -0700 Subject: [PATCH 50/64] don't resolve main in lib crates --- compiler/rustc_resolve/src/lib.rs | 7 +++++++ tests/ui/entry-point/imported_main_conflict_lib.rs | 10 ++++++++++ 2 files changed, 17 insertions(+) create mode 100644 tests/ui/entry-point/imported_main_conflict_lib.rs diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 8132bf577d88..0b4ec6956bd1 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -73,6 +73,7 @@ use rustc_middle::ty::{ ResolverGlobalCtxt, TyCtxt, TyCtxtFeed, Visibility, }; use rustc_query_system::ich::StableHashingContext; +use rustc_session::config::CrateType; use rustc_session::lint::builtin::PRIVATE_MACRO_USE; use rustc_span::hygiene::{ExpnId, LocalExpnId, MacroKind, SyntaxContext, Transparency}; use rustc_span::{DUMMY_SP, Ident, Macros20NormalizedIdent, Span, Symbol, kw, sym}; @@ -2430,6 +2431,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } fn resolve_main(&mut self) { + let any_exe = self.tcx.crate_types().contains(&CrateType::Executable); + // Don't try to resolve main unless it's an executable + if !any_exe { + return; + } + let module = self.graph_root; let ident = Ident::with_dummy_span(sym::main); let parent_scope = &ParentScope::module(module, self.arenas); diff --git a/tests/ui/entry-point/imported_main_conflict_lib.rs b/tests/ui/entry-point/imported_main_conflict_lib.rs new file mode 100644 index 000000000000..b50e37951ede --- /dev/null +++ b/tests/ui/entry-point/imported_main_conflict_lib.rs @@ -0,0 +1,10 @@ +// Tests that ambiguously glob importing main doesn't fail to compile in non-executable crates +// Regression test for #149412 +//@ check-pass +#![crate_type = "lib"] + +mod m1 { pub(crate) fn main() {} } +mod m2 { pub(crate) fn main() {} } + +use m1::*; +use m2::*; From c96ff2d42944a2df715115ddeaa6b260695dcca9 Mon Sep 17 00:00:00 2001 From: Jamie Hill-Daniel Date: Wed, 10 Dec 2025 23:41:19 +0000 Subject: [PATCH 51/64] Remove uses of `cfg(any()/all())` --- compiler/rustc_codegen_cranelift/src/base.rs | 2 +- library/core/src/primitive_docs.rs | 2 +- tests/ui/asm/naked-functions-inline.rs | 2 +- tests/ui/asm/naked-functions-inline.stderr | 6 +- .../unsafe/cfg-unsafe-attributes.rs | 2 +- .../unsafe/extraneous-unsafe-attributes.rs | 4 +- .../extraneous-unsafe-attributes.stderr | 4 +- .../ui/attributes/unsafe/unsafe-attributes.rs | 2 +- .../conditional-compilation-struct-11085.rs | 2 +- tests/ui/cfg/conditional-compile.rs | 2 +- ...nested-cfg-attr-conditional-compilation.rs | 6 +- ...ed-cfg-attr-conditional-compilation.stderr | 4 +- tests/ui/coherence/coherence-cow.rs | 2 +- .../cfg-attr-multi-false.rs | 2 +- .../cfg-attr-multi-true.rs | 2 +- .../conditional-compilation/cfg-attr-parse.rs | 22 +-- .../cfg-attr-parse.stderr | 90 ++++++------ ...-attr-unknown-attribute-macro-expansion.rs | 2 +- ...r-unknown-attribute-macro-expansion.stderr | 6 +- .../cfg-empty-any-all.rs | 12 ++ .../cfg-empty-any-all.stderr | 21 +++ .../conditional-compilation/cfg_attr_path.rs | 4 +- .../ui/conditional-compilation/issue-34028.rs | 2 +- .../module_with_cfg.rs | 2 +- .../ui/coroutine/static-closure-unexpanded.rs | 2 +- .../feature-gate-pin_ergonomics.rs | 2 +- .../feature-gates/feature-gate-super-let.rs | 2 +- .../feature-gate-unsafe-binders.rs | 2 +- .../feature-gate-unsafe_fields.rs | 6 +- .../feature-gate-where_clause_attrs.a.stderr | 132 +++++++++--------- .../feature-gate-where_clause_attrs.b.stderr | 132 +++++++++--------- .../feature-gate-where_clause_attrs.rs | 96 ++++++------- tests/ui/issues/issue-24434.rs | 2 +- tests/ui/lint/issue-97094.rs | 18 +-- tests/ui/lint/issue-97094.stderr | 36 ++--- tests/ui/macros/issue-34171.rs | 2 +- tests/ui/parser/attribute-on-empty.rs | 2 +- tests/ui/parser/attribute-on-empty.stderr | 2 +- tests/ui/parser/attribute-on-type.rs | 6 +- tests/ui/parser/attribute-on-type.stderr | 6 +- .../parser/attribute/attr-pat-struct-rest.rs | 2 +- .../attribute/attr-pat-struct-rest.stderr | 2 +- tests/ui/parser/cfg-keyword-lifetime.rs | 2 +- tests/ui/parser/issue-116781.rs | 2 +- tests/ui/parser/raw/raw-idents.rs | 2 +- .../ty-path-followed-by-single-colon.rs | 2 +- .../ui/proc-macro/ambiguous-builtin-attrs.rs | 2 +- .../proc-macro/ambiguous-builtin-attrs.stderr | 6 +- .../proc-macro/auxiliary/derive-attr-cfg.rs | 2 +- tests/ui/proc-macro/cfg-eval.rs | 8 +- tests/ui/proc-macro/cfg-eval.stderr | 4 +- tests/ui/proc-macro/cfg-eval.stdout | 44 +++--- tests/ui/proc-macro/derive-attr-cfg.rs | 2 +- tests/ui/proc-macro/derive-b.rs | 2 +- .../ui/proc-macro/derive-helper-configured.rs | 4 +- ...gest-import-without-clobbering-attrs.fixed | 2 +- ...suggest-import-without-clobbering-attrs.rs | 2 +- .../unsafe-attributes-fix.fixed | 2 +- .../unsafe-attributes-fix.rs | 2 +- .../unsafe-attributes-fix.stderr | 10 +- tests/ui/static/static-align.rs | 2 +- tests/ui/structs/struct-field-cfg.rs | 16 +-- tests/ui/structs/struct-field-cfg.stderr | 22 +-- tests/ui/test-attrs/issue-34932.rs | 2 +- .../ui/typeck/issue-86721-return-expr-ice.rs | 2 +- 65 files changed, 412 insertions(+), 389 deletions(-) create mode 100644 tests/ui/conditional-compilation/cfg-empty-any-all.rs create mode 100644 tests/ui/conditional-compilation/cfg-empty-any-all.stderr diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index a0bee4e18214..ac5b3c240785 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -167,7 +167,7 @@ pub(crate) fn compile_fn( context.clear(); context.func = codegened_func.func; - #[cfg(any())] // This is never true + #[cfg(false)] let _clif_guard = { use std::fmt::Write; diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs index 15ba72bccaa9..3a4e1e657a3d 100644 --- a/library/core/src/primitive_docs.rs +++ b/library/core/src/primitive_docs.rs @@ -591,7 +591,7 @@ impl () {} /// # pub unsafe fn malloc(_size: usize) -> *mut core::ffi::c_void { core::ptr::NonNull::dangling().as_ptr() } /// # pub unsafe fn free(_ptr: *mut core::ffi::c_void) {} /// # } -/// # #[cfg(any())] +/// # #[cfg(false)] /// #[allow(unused_extern_crates)] /// extern crate libc; /// diff --git a/tests/ui/asm/naked-functions-inline.rs b/tests/ui/asm/naked-functions-inline.rs index 93741f26275b..b6fddc88e19b 100644 --- a/tests/ui/asm/naked-functions-inline.rs +++ b/tests/ui/asm/naked-functions-inline.rs @@ -30,7 +30,7 @@ pub extern "C" fn inline_never() { } #[unsafe(naked)] -#[cfg_attr(all(), inline(never))] +#[cfg_attr(true, inline(never))] //~^ ERROR [E0736] pub extern "C" fn conditional_inline_never() { naked_asm!(""); diff --git a/tests/ui/asm/naked-functions-inline.stderr b/tests/ui/asm/naked-functions-inline.stderr index 91140a301edc..785ecf734b9d 100644 --- a/tests/ui/asm/naked-functions-inline.stderr +++ b/tests/ui/asm/naked-functions-inline.stderr @@ -23,12 +23,12 @@ LL | #[inline(never)] | ^^^^^^ the `inline` attribute is incompatible with `#[unsafe(naked)]` error[E0736]: attribute incompatible with `#[unsafe(naked)]` - --> $DIR/naked-functions-inline.rs:33:19 + --> $DIR/naked-functions-inline.rs:33:18 | LL | #[unsafe(naked)] | ---------------- function marked with `#[unsafe(naked)]` here -LL | #[cfg_attr(all(), inline(never))] - | ^^^^^^ the `inline` attribute is incompatible with `#[unsafe(naked)]` +LL | #[cfg_attr(true, inline(never))] + | ^^^^^^ the `inline` attribute is incompatible with `#[unsafe(naked)]` error: aborting due to 4 previous errors diff --git a/tests/ui/attributes/unsafe/cfg-unsafe-attributes.rs b/tests/ui/attributes/unsafe/cfg-unsafe-attributes.rs index 6a9853b2f6fc..7d05e08b2623 100644 --- a/tests/ui/attributes/unsafe/cfg-unsafe-attributes.rs +++ b/tests/ui/attributes/unsafe/cfg-unsafe-attributes.rs @@ -1,6 +1,6 @@ //@ build-pass -#[cfg_attr(all(), unsafe(no_mangle))] +#[cfg_attr(true, unsafe(no_mangle))] fn a() {} fn main() {} diff --git a/tests/ui/attributes/unsafe/extraneous-unsafe-attributes.rs b/tests/ui/attributes/unsafe/extraneous-unsafe-attributes.rs index 19046c08ca8b..a034b7246a34 100644 --- a/tests/ui/attributes/unsafe/extraneous-unsafe-attributes.rs +++ b/tests/ui/attributes/unsafe/extraneous-unsafe-attributes.rs @@ -1,9 +1,9 @@ //@ edition: 2024 -#[unsafe(cfg(any()))] //~ ERROR: is not an unsafe attribute +#[unsafe(cfg(false))] //~ ERROR: is not an unsafe attribute fn a() {} -#[unsafe(cfg_attr(any(), allow(dead_code)))] //~ ERROR: is not an unsafe attribute +#[unsafe(cfg_attr(false, allow(dead_code)))] //~ ERROR: is not an unsafe attribute fn b() {} #[unsafe(test)] //~ ERROR: is not an unsafe attribute diff --git a/tests/ui/attributes/unsafe/extraneous-unsafe-attributes.stderr b/tests/ui/attributes/unsafe/extraneous-unsafe-attributes.stderr index b549a638d5ea..dec8c4d3542b 100644 --- a/tests/ui/attributes/unsafe/extraneous-unsafe-attributes.stderr +++ b/tests/ui/attributes/unsafe/extraneous-unsafe-attributes.stderr @@ -1,7 +1,7 @@ error: `cfg` is not an unsafe attribute --> $DIR/extraneous-unsafe-attributes.rs:3:3 | -LL | #[unsafe(cfg(any()))] +LL | #[unsafe(cfg(false))] | ^^^^^^ this is not an unsafe attribute | = note: extraneous unsafe is not allowed in attributes @@ -9,7 +9,7 @@ LL | #[unsafe(cfg(any()))] error: `cfg_attr` is not an unsafe attribute --> $DIR/extraneous-unsafe-attributes.rs:6:3 | -LL | #[unsafe(cfg_attr(any(), allow(dead_code)))] +LL | #[unsafe(cfg_attr(false, allow(dead_code)))] | ^^^^^^ this is not an unsafe attribute | = note: extraneous unsafe is not allowed in attributes diff --git a/tests/ui/attributes/unsafe/unsafe-attributes.rs b/tests/ui/attributes/unsafe/unsafe-attributes.rs index 5c57767b3b96..c08b0ed995e5 100644 --- a/tests/ui/attributes/unsafe/unsafe-attributes.rs +++ b/tests/ui/attributes/unsafe/unsafe-attributes.rs @@ -6,7 +6,7 @@ fn a() {} #[unsafe(export_name = "foo")] fn b() {} -#[cfg_attr(any(), unsafe(no_mangle))] +#[cfg_attr(false, unsafe(no_mangle))] static VAR2: u32 = 1; fn main() {} diff --git a/tests/ui/cfg/conditional-compilation-struct-11085.rs b/tests/ui/cfg/conditional-compilation-struct-11085.rs index cd6dded54d30..8fdc88be37d2 100644 --- a/tests/ui/cfg/conditional-compilation-struct-11085.rs +++ b/tests/ui/cfg/conditional-compilation-struct-11085.rs @@ -11,7 +11,7 @@ struct Foo { } struct Foo2 { - #[cfg(all())] + #[cfg(true)] foo: isize, } diff --git a/tests/ui/cfg/conditional-compile.rs b/tests/ui/cfg/conditional-compile.rs index 0739e877bfd1..8761197891f5 100644 --- a/tests/ui/cfg/conditional-compile.rs +++ b/tests/ui/cfg/conditional-compile.rs @@ -151,5 +151,5 @@ mod test_methods { } } -#[cfg(any())] +#[cfg(false)] mod nonexistent_file; // Check that unconfigured non-inline modules are not loaded or parsed. diff --git a/tests/ui/cfg/nested-cfg-attr-conditional-compilation.rs b/tests/ui/cfg/nested-cfg-attr-conditional-compilation.rs index c5d86a27d522..8e79ce8d1546 100644 --- a/tests/ui/cfg/nested-cfg-attr-conditional-compilation.rs +++ b/tests/ui/cfg/nested-cfg-attr-conditional-compilation.rs @@ -3,14 +3,14 @@ //! expansion works from outside to inside, eventually applying the innermost //! conditional compilation directive. //! -//! In this test, `cfg_attr(all(), cfg_attr(all(), cfg(false)))` should expand to: -//! 1. `cfg_attr(all(), cfg(false))` (outer cfg_attr applied) +//! In this test, `cfg_attr(true, cfg_attr(true, cfg(false)))` should expand to: +//! 1. `cfg_attr(true, cfg(false))` (outer cfg_attr applied) //! 2. `cfg(false)` (inner cfg_attr applied) //! 3. Function `f` is excluded from compilation //! //! Added in . -#[cfg_attr(all(), cfg_attr(all(), cfg(false)))] //~ NOTE the item is gated here +#[cfg_attr(true, cfg_attr(true, cfg(false)))] //~ NOTE the item is gated here fn f() {} //~ NOTE found an item that was configured out fn main() { diff --git a/tests/ui/cfg/nested-cfg-attr-conditional-compilation.stderr b/tests/ui/cfg/nested-cfg-attr-conditional-compilation.stderr index 3f833bd558b8..e93a5433d979 100644 --- a/tests/ui/cfg/nested-cfg-attr-conditional-compilation.stderr +++ b/tests/ui/cfg/nested-cfg-attr-conditional-compilation.stderr @@ -7,8 +7,8 @@ LL | f() note: found an item that was configured out --> $DIR/nested-cfg-attr-conditional-compilation.rs:14:4 | -LL | #[cfg_attr(all(), cfg_attr(all(), cfg(false)))] - | ----- the item is gated here +LL | #[cfg_attr(true, cfg_attr(true, cfg(false)))] + | ----- the item is gated here LL | fn f() {} | ^ diff --git a/tests/ui/coherence/coherence-cow.rs b/tests/ui/coherence/coherence-cow.rs index af94964762a9..2fc33e3a3e8f 100644 --- a/tests/ui/coherence/coherence-cow.rs +++ b/tests/ui/coherence/coherence-cow.rs @@ -1,6 +1,6 @@ //@ revisions: re_a re_b re_c -#![cfg_attr(any(), re_a, re_b, re_c)] +#![cfg_attr(false, re_a, re_b, re_c)] //@ aux-build:coherence_lib.rs diff --git a/tests/ui/conditional-compilation/cfg-attr-multi-false.rs b/tests/ui/conditional-compilation/cfg-attr-multi-false.rs index cfb430ec5b23..871c1b81acd2 100644 --- a/tests/ui/conditional-compilation/cfg-attr-multi-false.rs +++ b/tests/ui/conditional-compilation/cfg-attr-multi-false.rs @@ -5,7 +5,7 @@ #![warn(unused_must_use)] -#[cfg_attr(any(), deprecated, must_use)] +#[cfg_attr(false, deprecated, must_use)] struct Struct {} impl Struct { diff --git a/tests/ui/conditional-compilation/cfg-attr-multi-true.rs b/tests/ui/conditional-compilation/cfg-attr-multi-true.rs index 424760c2e663..24950c8d4234 100644 --- a/tests/ui/conditional-compilation/cfg-attr-multi-true.rs +++ b/tests/ui/conditional-compilation/cfg-attr-multi-true.rs @@ -6,7 +6,7 @@ #![warn(unused_must_use)] -#[cfg_attr(all(), deprecated, must_use)] +#[cfg_attr(true, deprecated, must_use)] struct MustUseDeprecated {} impl MustUseDeprecated { //~ warning: use of deprecated diff --git a/tests/ui/conditional-compilation/cfg-attr-parse.rs b/tests/ui/conditional-compilation/cfg-attr-parse.rs index b8aaad2685ef..21df51264e2d 100644 --- a/tests/ui/conditional-compilation/cfg-attr-parse.rs +++ b/tests/ui/conditional-compilation/cfg-attr-parse.rs @@ -5,50 +5,50 @@ struct NoConfigurationPredicate; // Zero attributes, zero trailing comma (comma manatory here) -#[cfg_attr(all())] //~ error: expected `,`, found end of `cfg_attr` +#[cfg_attr(true)] //~ error: expected `,`, found end of `cfg_attr` struct A0C0; // Zero attributes, one trailing comma -#[cfg_attr(all(),)] +#[cfg_attr(true,)] //~^ WARN `#[cfg_attr]` does not expand to any attributes struct A0C1; // Zero attributes, two trailing commas -#[cfg_attr(all(),,)] //~ ERROR expected identifier +#[cfg_attr(true,,)] //~ ERROR expected identifier struct A0C2; // One attribute, no trailing comma -#[cfg_attr(all(), must_use)] // Ok +#[cfg_attr(true, must_use)] // Ok struct A1C0; // One attribute, one trailing comma -#[cfg_attr(all(), must_use,)] // Ok +#[cfg_attr(true, must_use,)] // Ok struct A1C1; // One attribute, two trailing commas -#[cfg_attr(all(), must_use,,)] //~ ERROR expected identifier +#[cfg_attr(true, must_use,,)] //~ ERROR expected identifier struct A1C2; // Two attributes, no trailing comma -#[cfg_attr(all(), must_use, deprecated)] // Ok +#[cfg_attr(true, must_use, deprecated)] // Ok struct A2C0; // Two attributes, one trailing comma -#[cfg_attr(all(), must_use, deprecated,)] // Ok +#[cfg_attr(true, must_use, deprecated,)] // Ok struct A2C1; // Two attributes, two trailing commas -#[cfg_attr(all(), must_use, deprecated,,)] //~ ERROR expected identifier +#[cfg_attr(true, must_use, deprecated,,)] //~ ERROR expected identifier struct A2C2; // Wrong delimiter `[` -#[cfg_attr[all(),,]] +#[cfg_attr[true,,]] //~^ ERROR wrong `cfg_attr` delimiters //~| ERROR expected identifier, found `,` struct BracketZero; // Wrong delimiter `{` -#[cfg_attr{all(),,}] +#[cfg_attr{true,,}] //~^ ERROR wrong `cfg_attr` delimiters //~| ERROR expected identifier, found `,` struct BraceZero; diff --git a/tests/ui/conditional-compilation/cfg-attr-parse.stderr b/tests/ui/conditional-compilation/cfg-attr-parse.stderr index 4d4769b05cda..8dbe8969fd1c 100644 --- a/tests/ui/conditional-compilation/cfg-attr-parse.stderr +++ b/tests/ui/conditional-compilation/cfg-attr-parse.stderr @@ -10,45 +10,45 @@ LL | #[cfg_attr()] = note: for more information, visit error: expected `,`, found end of `cfg_attr` input - --> $DIR/cfg-attr-parse.rs:8:17 + --> $DIR/cfg-attr-parse.rs:8:16 | -LL | #[cfg_attr(all())] - | ----------------^- +LL | #[cfg_attr(true)] + | ---------------^- + | | | + | | expected `,` + | help: must be of the form: `#[cfg_attr(predicate, attr1, attr2, ...)]` + | + = note: for more information, visit + +error: expected identifier, found `,` + --> $DIR/cfg-attr-parse.rs:17:17 + | +LL | #[cfg_attr(true,,)] + | ----------------^-- | | | - | | expected `,` + | | expected identifier | help: must be of the form: `#[cfg_attr(predicate, attr1, attr2, ...)]` | = note: for more information, visit error: expected identifier, found `,` - --> $DIR/cfg-attr-parse.rs:17:18 + --> $DIR/cfg-attr-parse.rs:29:27 | -LL | #[cfg_attr(all(),,)] - | -----------------^-- - | | | - | | expected identifier +LL | #[cfg_attr(true, must_use,,)] + | --------------------------^-- + | | | + | | expected identifier | help: must be of the form: `#[cfg_attr(predicate, attr1, attr2, ...)]` | = note: for more information, visit error: expected identifier, found `,` - --> $DIR/cfg-attr-parse.rs:29:28 + --> $DIR/cfg-attr-parse.rs:41:39 | -LL | #[cfg_attr(all(), must_use,,)] - | ---------------------------^-- - | | | - | | expected identifier - | help: must be of the form: `#[cfg_attr(predicate, attr1, attr2, ...)]` - | - = note: for more information, visit - -error: expected identifier, found `,` - --> $DIR/cfg-attr-parse.rs:41:40 - | -LL | #[cfg_attr(all(), must_use, deprecated,,)] - | ---------------------------------------^-- - | | | - | | expected identifier +LL | #[cfg_attr(true, must_use, deprecated,,)] + | --------------------------------------^-- + | | | + | | expected identifier | help: must be of the form: `#[cfg_attr(predicate, attr1, attr2, ...)]` | = note: for more information, visit @@ -56,22 +56,22 @@ LL | #[cfg_attr(all(), must_use, deprecated,,)] error: wrong `cfg_attr` delimiters --> $DIR/cfg-attr-parse.rs:45:11 | -LL | #[cfg_attr[all(),,]] - | ^^^^^^^^^ +LL | #[cfg_attr[true,,]] + | ^^^^^^^^ | help: the delimiters should be `(` and `)` | -LL - #[cfg_attr[all(),,]] -LL + #[cfg_attr(all(),,)] +LL - #[cfg_attr[true,,]] +LL + #[cfg_attr(true,,)] | error: expected identifier, found `,` - --> $DIR/cfg-attr-parse.rs:45:18 + --> $DIR/cfg-attr-parse.rs:45:17 | -LL | #[cfg_attr[all(),,]] - | -----------------^-- - | | | - | | expected identifier +LL | #[cfg_attr[true,,]] + | ----------------^-- + | | | + | | expected identifier | help: must be of the form: `#[cfg_attr(predicate, attr1, attr2, ...)]` | = note: for more information, visit @@ -79,22 +79,22 @@ LL | #[cfg_attr[all(),,]] error: wrong `cfg_attr` delimiters --> $DIR/cfg-attr-parse.rs:51:11 | -LL | #[cfg_attr{all(),,}] - | ^^^^^^^^^ +LL | #[cfg_attr{true,,}] + | ^^^^^^^^ | help: the delimiters should be `(` and `)` | -LL - #[cfg_attr{all(),,}] -LL + #[cfg_attr(all(),,)] +LL - #[cfg_attr{true,,}] +LL + #[cfg_attr(true,,)] | error: expected identifier, found `,` - --> $DIR/cfg-attr-parse.rs:51:18 + --> $DIR/cfg-attr-parse.rs:51:17 | -LL | #[cfg_attr{all(),,}] - | -----------------^-- - | | | - | | expected identifier +LL | #[cfg_attr{true,,}] + | ----------------^-- + | | | + | | expected identifier | help: must be of the form: `#[cfg_attr(predicate, attr1, attr2, ...)]` | = note: for more information, visit @@ -102,8 +102,8 @@ LL | #[cfg_attr{all(),,}] warning: `#[cfg_attr]` does not expand to any attributes --> $DIR/cfg-attr-parse.rs:12:1 | -LL | #[cfg_attr(all(),)] - | ^^^^^^^^^^^^^^^^^^^ +LL | #[cfg_attr(true,)] + | ^^^^^^^^^^^^^^^^^^ | = note: requested on the command line with `-W unused-attributes` diff --git a/tests/ui/conditional-compilation/cfg-attr-unknown-attribute-macro-expansion.rs b/tests/ui/conditional-compilation/cfg-attr-unknown-attribute-macro-expansion.rs index 45b757e92830..0305be5d24e6 100644 --- a/tests/ui/conditional-compilation/cfg-attr-unknown-attribute-macro-expansion.rs +++ b/tests/ui/conditional-compilation/cfg-attr-unknown-attribute-macro-expansion.rs @@ -1,6 +1,6 @@ macro_rules! foo { () => { - #[cfg_attr(all(), unknown)] + #[cfg_attr(true, unknown)] //~^ ERROR cannot find attribute `unknown` in this scope fn foo() {} } diff --git a/tests/ui/conditional-compilation/cfg-attr-unknown-attribute-macro-expansion.stderr b/tests/ui/conditional-compilation/cfg-attr-unknown-attribute-macro-expansion.stderr index c91ad128d6e5..bdddbd68cdaf 100644 --- a/tests/ui/conditional-compilation/cfg-attr-unknown-attribute-macro-expansion.stderr +++ b/tests/ui/conditional-compilation/cfg-attr-unknown-attribute-macro-expansion.stderr @@ -1,8 +1,8 @@ error: cannot find attribute `unknown` in this scope - --> $DIR/cfg-attr-unknown-attribute-macro-expansion.rs:3:27 + --> $DIR/cfg-attr-unknown-attribute-macro-expansion.rs:3:26 | -LL | #[cfg_attr(all(), unknown)] - | ^^^^^^^ +LL | #[cfg_attr(true, unknown)] + | ^^^^^^^ ... LL | foo!(); | ------ in this macro invocation diff --git a/tests/ui/conditional-compilation/cfg-empty-any-all.rs b/tests/ui/conditional-compilation/cfg-empty-any-all.rs new file mode 100644 index 000000000000..48ed4342235c --- /dev/null +++ b/tests/ui/conditional-compilation/cfg-empty-any-all.rs @@ -0,0 +1,12 @@ +//! Test the behaviour of `cfg(any())` and `cfg(all())` + +#[cfg(any())] // Equivalent to cfg(false) +struct Disabled; + +#[cfg(all())] // Equivalent to cfg(true) +struct Enabled; + +fn main() { + let _ = Disabled; //~ ERROR: cannot find value `Disabled` + let _ = Enabled; // ok +} diff --git a/tests/ui/conditional-compilation/cfg-empty-any-all.stderr b/tests/ui/conditional-compilation/cfg-empty-any-all.stderr new file mode 100644 index 000000000000..1674f2def23a --- /dev/null +++ b/tests/ui/conditional-compilation/cfg-empty-any-all.stderr @@ -0,0 +1,21 @@ +error[E0425]: cannot find value `Disabled` in this scope + --> $DIR/cfg-empty-any-all.rs:10:13 + | +LL | let _ = Disabled; + | ^^^^^^^^ not found in this scope + | +note: found an item that was configured out + --> $DIR/cfg-empty-any-all.rs:4:8 + | +LL | #[cfg(any())] // Equivalent to cfg(false) + | -- the item is gated here +LL | struct Disabled; + | ^^^^^^^^ +help: consider importing this unit variant + | +LL + use std::backtrace::BacktraceStatus::Disabled; + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/conditional-compilation/cfg_attr_path.rs b/tests/ui/conditional-compilation/cfg_attr_path.rs index 00e07761977a..f300e02932b7 100644 --- a/tests/ui/conditional-compilation/cfg_attr_path.rs +++ b/tests/ui/conditional-compilation/cfg_attr_path.rs @@ -3,8 +3,8 @@ #![deny(unused_attributes)] // c.f #35584 mod auxiliary { - #[cfg_attr(any(), path = "nonexistent_file.rs")] pub mod namespaced_enums; - #[cfg_attr(all(), path = "namespaced_enums.rs")] pub mod nonexistent_file; + #[cfg_attr(false, path = "nonexistent_file.rs")] pub mod namespaced_enums; + #[cfg_attr(true, path = "namespaced_enums.rs")] pub mod nonexistent_file; } fn main() { diff --git a/tests/ui/conditional-compilation/issue-34028.rs b/tests/ui/conditional-compilation/issue-34028.rs index 3ee43cb4b322..d6f3f7a9abce 100644 --- a/tests/ui/conditional-compilation/issue-34028.rs +++ b/tests/ui/conditional-compilation/issue-34028.rs @@ -1,7 +1,7 @@ //@ check-pass macro_rules! m { - () => { #[cfg(any())] fn f() {} } + () => { #[cfg(false)] fn f() {} } } trait T {} diff --git a/tests/ui/conditional-compilation/module_with_cfg.rs b/tests/ui/conditional-compilation/module_with_cfg.rs index a96f8a3e6e96..32486bdb43d6 100644 --- a/tests/ui/conditional-compilation/module_with_cfg.rs +++ b/tests/ui/conditional-compilation/module_with_cfg.rs @@ -1,3 +1,3 @@ //@ ignore-auxiliary (used by `./inner-cfg-non-inline-mod.rs`) -#![cfg_attr(all(), cfg(false))] +#![cfg_attr(true, cfg(false))] diff --git a/tests/ui/coroutine/static-closure-unexpanded.rs b/tests/ui/coroutine/static-closure-unexpanded.rs index 7cf24774deda..ac7c251c8348 100644 --- a/tests/ui/coroutine/static-closure-unexpanded.rs +++ b/tests/ui/coroutine/static-closure-unexpanded.rs @@ -1,7 +1,7 @@ // Tests that static closures are not stable in the parser grammar unless the // coroutine feature is enabled. -#[cfg(any())] +#[cfg(false)] fn foo() { let _ = static || {}; //~^ ERROR coroutine syntax is experimental diff --git a/tests/ui/feature-gates/feature-gate-pin_ergonomics.rs b/tests/ui/feature-gates/feature-gate-pin_ergonomics.rs index 7f669d0b93e5..6cb4492c3754 100644 --- a/tests/ui/feature-gates/feature-gate-pin_ergonomics.rs +++ b/tests/ui/feature-gates/feature-gate-pin_ergonomics.rs @@ -58,7 +58,7 @@ fn patterns<'a>( ref pin const w: i32, //~ ERROR pinned reference syntax is experimental ) {} -#[cfg(any())] +#[cfg(false)] mod not_compiled { use std::pin::Pin; diff --git a/tests/ui/feature-gates/feature-gate-super-let.rs b/tests/ui/feature-gates/feature-gate-super-let.rs index 7be080039133..19da1c4aa39b 100644 --- a/tests/ui/feature-gates/feature-gate-super-let.rs +++ b/tests/ui/feature-gates/feature-gate-super-let.rs @@ -4,7 +4,7 @@ fn main() { } // Check that it also isn't accepted in cfg'd out code. -#[cfg(any())] +#[cfg(false)] fn a() { super let a = 1; //~^ ERROR `super let` is experimental diff --git a/tests/ui/feature-gates/feature-gate-unsafe-binders.rs b/tests/ui/feature-gates/feature-gate-unsafe-binders.rs index a2997ced4fa1..e1eda7def482 100644 --- a/tests/ui/feature-gates/feature-gate-unsafe-binders.rs +++ b/tests/ui/feature-gates/feature-gate-unsafe-binders.rs @@ -1,4 +1,4 @@ -#[cfg(any())] +#[cfg(false)] fn test() { let x: unsafe<> (); //~^ ERROR unsafe binder types are experimental diff --git a/tests/ui/feature-gates/feature-gate-unsafe_fields.rs b/tests/ui/feature-gates/feature-gate-unsafe_fields.rs index 8f9b411df469..2b0bbaa08357 100644 --- a/tests/ui/feature-gates/feature-gate-unsafe_fields.rs +++ b/tests/ui/feature-gates/feature-gate-unsafe_fields.rs @@ -4,7 +4,7 @@ #![cfg_attr(with_gate, feature(unsafe_fields))] //[with_gate]~ WARNING -#[cfg(any())] +#[cfg(false)] struct Foo { unsafe field: (), //[without_gate]~ ERROR } @@ -12,14 +12,14 @@ struct Foo { // This should not parse as an unsafe field definition. struct FooTuple(unsafe fn()); -#[cfg(any())] +#[cfg(false)] enum Bar { Variant { unsafe field: () }, //[without_gate]~ ERROR // This should not parse as an unsafe field definition. VariantTuple(unsafe fn()), } -#[cfg(any())] +#[cfg(false)] union Baz { unsafe field: (), //[without_gate]~ ERROR } diff --git a/tests/ui/feature-gates/feature-gate-where_clause_attrs.a.stderr b/tests/ui/feature-gates/feature-gate-where_clause_attrs.a.stderr index 6a8f01bbcce1..970763157d18 100644 --- a/tests/ui/feature-gates/feature-gate-where_clause_attrs.a.stderr +++ b/tests/ui/feature-gates/feature-gate-where_clause_attrs.a.stderr @@ -21,8 +21,8 @@ LL | #[cfg(b)] T: TraitB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:35:5 | -LL | #[cfg(all())] T: TraitAll, - | ^^^^^^^^^^^^^ +LL | #[cfg(true)] T: TraitAll, + | ^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -31,7 +31,7 @@ LL | #[cfg(all())] T: TraitAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:36:5 | -LL | #[cfg(any())] T: TraitAny, +LL | #[cfg(false)] T: TraitAny, | ^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -61,8 +61,8 @@ LL | #[cfg_attr(b, cfg(b))] T: TraitBB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:39:5 | -LL | #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[cfg_attr(true, cfg(true))] T: TraitAllAll, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -71,7 +71,7 @@ LL | #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:40:5 | -LL | #[cfg_attr(any(), cfg(any()))] T: TraitAnyAny, +LL | #[cfg_attr(false, cfg(false))] T: TraitAnyAny, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -101,8 +101,8 @@ LL | #[cfg(b)] U: TraitB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:46:9 | -LL | #[cfg(all())] U: TraitAll, - | ^^^^^^^^^^^^^ +LL | #[cfg(true)] U: TraitAll, + | ^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -111,7 +111,7 @@ LL | #[cfg(all())] U: TraitAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:47:9 | -LL | #[cfg(any())] U: TraitAny, +LL | #[cfg(false)] U: TraitAny, | ^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -141,8 +141,8 @@ LL | #[cfg_attr(b, cfg(b))] U: TraitBB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:50:9 | -LL | #[cfg_attr(all(), cfg(all()))] U: TraitAllAll, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[cfg_attr(true, cfg(true))] U: TraitAllAll, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -151,7 +151,7 @@ LL | #[cfg_attr(all(), cfg(all()))] U: TraitAllAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:51:9 | -LL | #[cfg_attr(any(), cfg(any()))] U: TraitAnyAny; +LL | #[cfg_attr(false, cfg(false))] U: TraitAnyAny; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -181,8 +181,8 @@ LL | #[cfg(b)] U: TraitB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:57:9 | -LL | #[cfg(all())] U: TraitAll, - | ^^^^^^^^^^^^^ +LL | #[cfg(true)] U: TraitAll, + | ^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -191,7 +191,7 @@ LL | #[cfg(all())] U: TraitAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:58:9 | -LL | #[cfg(any())] U: TraitAny, +LL | #[cfg(false)] U: TraitAny, | ^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -221,8 +221,8 @@ LL | #[cfg_attr(b, cfg(b))] U: TraitBB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:61:9 | -LL | #[cfg_attr(all(), cfg(all()))] U: TraitAllAll, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[cfg_attr(true, cfg(true))] U: TraitAllAll, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -231,7 +231,7 @@ LL | #[cfg_attr(all(), cfg(all()))] U: TraitAllAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:62:9 | -LL | #[cfg_attr(any(), cfg(any()))] U: TraitAnyAny; +LL | #[cfg_attr(false, cfg(false))] U: TraitAnyAny; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -261,8 +261,8 @@ LL | #[cfg(b)] T: TraitB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:69:5 | -LL | #[cfg(all())] T: TraitAll, - | ^^^^^^^^^^^^^ +LL | #[cfg(true)] T: TraitAll, + | ^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -271,7 +271,7 @@ LL | #[cfg(all())] T: TraitAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:70:5 | -LL | #[cfg(any())] T: TraitAny, +LL | #[cfg(false)] T: TraitAny, | ^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -301,8 +301,8 @@ LL | #[cfg_attr(b, cfg(b))] T: TraitBB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:73:5 | -LL | #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[cfg_attr(true, cfg(true))] T: TraitAllAll, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -311,7 +311,7 @@ LL | #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:74:5 | -LL | #[cfg_attr(any(), cfg(any()))] T: TraitAnyAny, +LL | #[cfg_attr(false, cfg(false))] T: TraitAnyAny, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -341,8 +341,8 @@ LL | #[cfg(b)] U: TraitB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:79:9 | -LL | #[cfg(all())] U: TraitAll, - | ^^^^^^^^^^^^^ +LL | #[cfg(true)] U: TraitAll, + | ^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -351,7 +351,7 @@ LL | #[cfg(all())] U: TraitAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:80:9 | -LL | #[cfg(any())] U: TraitAny, +LL | #[cfg(false)] U: TraitAny, | ^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -381,8 +381,8 @@ LL | #[cfg_attr(b, cfg(b))] U: TraitBB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:83:9 | -LL | #[cfg_attr(all(), cfg(all()))] U: TraitAllAll, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[cfg_attr(true, cfg(true))] U: TraitAllAll, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -391,7 +391,7 @@ LL | #[cfg_attr(all(), cfg(all()))] U: TraitAllAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:84:9 | -LL | #[cfg_attr(any(), cfg(any()))] U: TraitAnyAny; +LL | #[cfg_attr(false, cfg(false))] U: TraitAnyAny; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -421,8 +421,8 @@ LL | #[cfg(b)] U: TraitB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:90:9 | -LL | #[cfg(all())] T: TraitAll, - | ^^^^^^^^^^^^^ +LL | #[cfg(true)] T: TraitAll, + | ^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -431,7 +431,7 @@ LL | #[cfg(all())] T: TraitAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:91:9 | -LL | #[cfg(any())] T: TraitAny, +LL | #[cfg(false)] T: TraitAny, | ^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -461,8 +461,8 @@ LL | #[cfg_attr(b, cfg(b))] U: TraitBB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:94:9 | -LL | #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[cfg_attr(true, cfg(true))] T: TraitAllAll, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -471,7 +471,7 @@ LL | #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:95:9 | -LL | #[cfg_attr(any(), cfg(any()))] T: TraitAnyAny, +LL | #[cfg_attr(false, cfg(false))] T: TraitAnyAny, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -501,8 +501,8 @@ LL | #[cfg(b)] T: TraitB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:103:5 | -LL | #[cfg(all())] T: TraitAll, - | ^^^^^^^^^^^^^ +LL | #[cfg(true)] T: TraitAll, + | ^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -511,7 +511,7 @@ LL | #[cfg(all())] T: TraitAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:104:5 | -LL | #[cfg(any())] T: TraitAny, +LL | #[cfg(false)] T: TraitAny, | ^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -541,8 +541,8 @@ LL | #[cfg_attr(b, cfg(b))] T: TraitBB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:107:5 | -LL | #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[cfg_attr(true, cfg(true))] T: TraitAllAll, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -551,7 +551,7 @@ LL | #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:108:5 | -LL | #[cfg_attr(any(), cfg(any()))] T: TraitAnyAny, +LL | #[cfg_attr(false, cfg(false))] T: TraitAnyAny, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -581,8 +581,8 @@ LL | #[cfg(b)] T: TraitB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:117:5 | -LL | #[cfg(all())] T: TraitAll, - | ^^^^^^^^^^^^^ +LL | #[cfg(true)] T: TraitAll, + | ^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -591,7 +591,7 @@ LL | #[cfg(all())] T: TraitAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:118:5 | -LL | #[cfg(any())] T: TraitAny, +LL | #[cfg(false)] T: TraitAny, | ^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -621,8 +621,8 @@ LL | #[cfg_attr(b, cfg(b))] T: TraitBB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:121:5 | -LL | #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[cfg_attr(true, cfg(true))] T: TraitAllAll, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -631,7 +631,7 @@ LL | #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:122:5 | -LL | #[cfg_attr(any(), cfg(any()))] T: TraitAnyAny, +LL | #[cfg_attr(false, cfg(false))] T: TraitAnyAny, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -661,8 +661,8 @@ LL | #[cfg(b)] T: TraitB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:132:5 | -LL | #[cfg(all())] T: TraitAll, - | ^^^^^^^^^^^^^ +LL | #[cfg(true)] T: TraitAll, + | ^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -671,7 +671,7 @@ LL | #[cfg(all())] T: TraitAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:133:5 | -LL | #[cfg(any())] T: TraitAny, +LL | #[cfg(false)] T: TraitAny, | ^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -701,8 +701,8 @@ LL | #[cfg_attr(b, cfg(b))] T: TraitBB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:136:5 | -LL | #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[cfg_attr(true, cfg(true))] T: TraitAllAll, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -711,7 +711,7 @@ LL | #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:137:5 | -LL | #[cfg_attr(any(), cfg(any()))] T: TraitAnyAny, +LL | #[cfg_attr(false, cfg(false))] T: TraitAnyAny, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -741,8 +741,8 @@ LL | #[cfg(b)] T: TraitB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:145:5 | -LL | #[cfg(all())] T: TraitAll, - | ^^^^^^^^^^^^^ +LL | #[cfg(true)] T: TraitAll, + | ^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -751,7 +751,7 @@ LL | #[cfg(all())] T: TraitAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:146:5 | -LL | #[cfg(any())] T: TraitAny, +LL | #[cfg(false)] T: TraitAny, | ^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -781,8 +781,8 @@ LL | #[cfg_attr(b, cfg(b))] T: TraitBB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:149:5 | -LL | #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[cfg_attr(true, cfg(true))] T: TraitAllAll, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -791,7 +791,7 @@ LL | #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:150:5 | -LL | #[cfg_attr(any(), cfg(any()))] T: TraitAnyAny, +LL | #[cfg_attr(false, cfg(false))] T: TraitAnyAny, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -821,8 +821,8 @@ LL | #[cfg(b)] U: TraitB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:155:9 | -LL | #[cfg(all())] U: TraitAll, - | ^^^^^^^^^^^^^ +LL | #[cfg(true)] U: TraitAll, + | ^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -831,7 +831,7 @@ LL | #[cfg(all())] U: TraitAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:156:9 | -LL | #[cfg(any())] U: TraitAny, +LL | #[cfg(false)] U: TraitAny, | ^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -861,8 +861,8 @@ LL | #[cfg_attr(b, cfg(b))] U: TraitBB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:159:9 | -LL | #[cfg_attr(all(), cfg(all()))] U: TraitAllAll, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[cfg_attr(true, cfg(true))] U: TraitAllAll, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -871,7 +871,7 @@ LL | #[cfg_attr(all(), cfg(all()))] U: TraitAllAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:160:9 | -LL | #[cfg_attr(any(), cfg(any()))] U: TraitAnyAny, +LL | #[cfg_attr(false, cfg(false))] U: TraitAnyAny, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information diff --git a/tests/ui/feature-gates/feature-gate-where_clause_attrs.b.stderr b/tests/ui/feature-gates/feature-gate-where_clause_attrs.b.stderr index 6a8f01bbcce1..970763157d18 100644 --- a/tests/ui/feature-gates/feature-gate-where_clause_attrs.b.stderr +++ b/tests/ui/feature-gates/feature-gate-where_clause_attrs.b.stderr @@ -21,8 +21,8 @@ LL | #[cfg(b)] T: TraitB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:35:5 | -LL | #[cfg(all())] T: TraitAll, - | ^^^^^^^^^^^^^ +LL | #[cfg(true)] T: TraitAll, + | ^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -31,7 +31,7 @@ LL | #[cfg(all())] T: TraitAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:36:5 | -LL | #[cfg(any())] T: TraitAny, +LL | #[cfg(false)] T: TraitAny, | ^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -61,8 +61,8 @@ LL | #[cfg_attr(b, cfg(b))] T: TraitBB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:39:5 | -LL | #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[cfg_attr(true, cfg(true))] T: TraitAllAll, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -71,7 +71,7 @@ LL | #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:40:5 | -LL | #[cfg_attr(any(), cfg(any()))] T: TraitAnyAny, +LL | #[cfg_attr(false, cfg(false))] T: TraitAnyAny, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -101,8 +101,8 @@ LL | #[cfg(b)] U: TraitB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:46:9 | -LL | #[cfg(all())] U: TraitAll, - | ^^^^^^^^^^^^^ +LL | #[cfg(true)] U: TraitAll, + | ^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -111,7 +111,7 @@ LL | #[cfg(all())] U: TraitAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:47:9 | -LL | #[cfg(any())] U: TraitAny, +LL | #[cfg(false)] U: TraitAny, | ^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -141,8 +141,8 @@ LL | #[cfg_attr(b, cfg(b))] U: TraitBB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:50:9 | -LL | #[cfg_attr(all(), cfg(all()))] U: TraitAllAll, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[cfg_attr(true, cfg(true))] U: TraitAllAll, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -151,7 +151,7 @@ LL | #[cfg_attr(all(), cfg(all()))] U: TraitAllAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:51:9 | -LL | #[cfg_attr(any(), cfg(any()))] U: TraitAnyAny; +LL | #[cfg_attr(false, cfg(false))] U: TraitAnyAny; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -181,8 +181,8 @@ LL | #[cfg(b)] U: TraitB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:57:9 | -LL | #[cfg(all())] U: TraitAll, - | ^^^^^^^^^^^^^ +LL | #[cfg(true)] U: TraitAll, + | ^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -191,7 +191,7 @@ LL | #[cfg(all())] U: TraitAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:58:9 | -LL | #[cfg(any())] U: TraitAny, +LL | #[cfg(false)] U: TraitAny, | ^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -221,8 +221,8 @@ LL | #[cfg_attr(b, cfg(b))] U: TraitBB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:61:9 | -LL | #[cfg_attr(all(), cfg(all()))] U: TraitAllAll, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[cfg_attr(true, cfg(true))] U: TraitAllAll, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -231,7 +231,7 @@ LL | #[cfg_attr(all(), cfg(all()))] U: TraitAllAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:62:9 | -LL | #[cfg_attr(any(), cfg(any()))] U: TraitAnyAny; +LL | #[cfg_attr(false, cfg(false))] U: TraitAnyAny; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -261,8 +261,8 @@ LL | #[cfg(b)] T: TraitB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:69:5 | -LL | #[cfg(all())] T: TraitAll, - | ^^^^^^^^^^^^^ +LL | #[cfg(true)] T: TraitAll, + | ^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -271,7 +271,7 @@ LL | #[cfg(all())] T: TraitAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:70:5 | -LL | #[cfg(any())] T: TraitAny, +LL | #[cfg(false)] T: TraitAny, | ^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -301,8 +301,8 @@ LL | #[cfg_attr(b, cfg(b))] T: TraitBB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:73:5 | -LL | #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[cfg_attr(true, cfg(true))] T: TraitAllAll, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -311,7 +311,7 @@ LL | #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:74:5 | -LL | #[cfg_attr(any(), cfg(any()))] T: TraitAnyAny, +LL | #[cfg_attr(false, cfg(false))] T: TraitAnyAny, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -341,8 +341,8 @@ LL | #[cfg(b)] U: TraitB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:79:9 | -LL | #[cfg(all())] U: TraitAll, - | ^^^^^^^^^^^^^ +LL | #[cfg(true)] U: TraitAll, + | ^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -351,7 +351,7 @@ LL | #[cfg(all())] U: TraitAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:80:9 | -LL | #[cfg(any())] U: TraitAny, +LL | #[cfg(false)] U: TraitAny, | ^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -381,8 +381,8 @@ LL | #[cfg_attr(b, cfg(b))] U: TraitBB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:83:9 | -LL | #[cfg_attr(all(), cfg(all()))] U: TraitAllAll, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[cfg_attr(true, cfg(true))] U: TraitAllAll, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -391,7 +391,7 @@ LL | #[cfg_attr(all(), cfg(all()))] U: TraitAllAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:84:9 | -LL | #[cfg_attr(any(), cfg(any()))] U: TraitAnyAny; +LL | #[cfg_attr(false, cfg(false))] U: TraitAnyAny; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -421,8 +421,8 @@ LL | #[cfg(b)] U: TraitB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:90:9 | -LL | #[cfg(all())] T: TraitAll, - | ^^^^^^^^^^^^^ +LL | #[cfg(true)] T: TraitAll, + | ^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -431,7 +431,7 @@ LL | #[cfg(all())] T: TraitAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:91:9 | -LL | #[cfg(any())] T: TraitAny, +LL | #[cfg(false)] T: TraitAny, | ^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -461,8 +461,8 @@ LL | #[cfg_attr(b, cfg(b))] U: TraitBB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:94:9 | -LL | #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[cfg_attr(true, cfg(true))] T: TraitAllAll, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -471,7 +471,7 @@ LL | #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:95:9 | -LL | #[cfg_attr(any(), cfg(any()))] T: TraitAnyAny, +LL | #[cfg_attr(false, cfg(false))] T: TraitAnyAny, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -501,8 +501,8 @@ LL | #[cfg(b)] T: TraitB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:103:5 | -LL | #[cfg(all())] T: TraitAll, - | ^^^^^^^^^^^^^ +LL | #[cfg(true)] T: TraitAll, + | ^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -511,7 +511,7 @@ LL | #[cfg(all())] T: TraitAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:104:5 | -LL | #[cfg(any())] T: TraitAny, +LL | #[cfg(false)] T: TraitAny, | ^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -541,8 +541,8 @@ LL | #[cfg_attr(b, cfg(b))] T: TraitBB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:107:5 | -LL | #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[cfg_attr(true, cfg(true))] T: TraitAllAll, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -551,7 +551,7 @@ LL | #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:108:5 | -LL | #[cfg_attr(any(), cfg(any()))] T: TraitAnyAny, +LL | #[cfg_attr(false, cfg(false))] T: TraitAnyAny, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -581,8 +581,8 @@ LL | #[cfg(b)] T: TraitB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:117:5 | -LL | #[cfg(all())] T: TraitAll, - | ^^^^^^^^^^^^^ +LL | #[cfg(true)] T: TraitAll, + | ^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -591,7 +591,7 @@ LL | #[cfg(all())] T: TraitAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:118:5 | -LL | #[cfg(any())] T: TraitAny, +LL | #[cfg(false)] T: TraitAny, | ^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -621,8 +621,8 @@ LL | #[cfg_attr(b, cfg(b))] T: TraitBB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:121:5 | -LL | #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[cfg_attr(true, cfg(true))] T: TraitAllAll, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -631,7 +631,7 @@ LL | #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:122:5 | -LL | #[cfg_attr(any(), cfg(any()))] T: TraitAnyAny, +LL | #[cfg_attr(false, cfg(false))] T: TraitAnyAny, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -661,8 +661,8 @@ LL | #[cfg(b)] T: TraitB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:132:5 | -LL | #[cfg(all())] T: TraitAll, - | ^^^^^^^^^^^^^ +LL | #[cfg(true)] T: TraitAll, + | ^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -671,7 +671,7 @@ LL | #[cfg(all())] T: TraitAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:133:5 | -LL | #[cfg(any())] T: TraitAny, +LL | #[cfg(false)] T: TraitAny, | ^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -701,8 +701,8 @@ LL | #[cfg_attr(b, cfg(b))] T: TraitBB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:136:5 | -LL | #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[cfg_attr(true, cfg(true))] T: TraitAllAll, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -711,7 +711,7 @@ LL | #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:137:5 | -LL | #[cfg_attr(any(), cfg(any()))] T: TraitAnyAny, +LL | #[cfg_attr(false, cfg(false))] T: TraitAnyAny, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -741,8 +741,8 @@ LL | #[cfg(b)] T: TraitB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:145:5 | -LL | #[cfg(all())] T: TraitAll, - | ^^^^^^^^^^^^^ +LL | #[cfg(true)] T: TraitAll, + | ^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -751,7 +751,7 @@ LL | #[cfg(all())] T: TraitAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:146:5 | -LL | #[cfg(any())] T: TraitAny, +LL | #[cfg(false)] T: TraitAny, | ^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -781,8 +781,8 @@ LL | #[cfg_attr(b, cfg(b))] T: TraitBB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:149:5 | -LL | #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[cfg_attr(true, cfg(true))] T: TraitAllAll, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -791,7 +791,7 @@ LL | #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:150:5 | -LL | #[cfg_attr(any(), cfg(any()))] T: TraitAnyAny, +LL | #[cfg_attr(false, cfg(false))] T: TraitAnyAny, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -821,8 +821,8 @@ LL | #[cfg(b)] U: TraitB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:155:9 | -LL | #[cfg(all())] U: TraitAll, - | ^^^^^^^^^^^^^ +LL | #[cfg(true)] U: TraitAll, + | ^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -831,7 +831,7 @@ LL | #[cfg(all())] U: TraitAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:156:9 | -LL | #[cfg(any())] U: TraitAny, +LL | #[cfg(false)] U: TraitAny, | ^^^^^^^^^^^^^ | = note: see issue #115590 for more information @@ -861,8 +861,8 @@ LL | #[cfg_attr(b, cfg(b))] U: TraitBB, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:159:9 | -LL | #[cfg_attr(all(), cfg(all()))] U: TraitAllAll, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[cfg_attr(true, cfg(true))] U: TraitAllAll, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information = help: add `#![feature(where_clause_attrs)]` to the crate attributes to enable @@ -871,7 +871,7 @@ LL | #[cfg_attr(all(), cfg(all()))] U: TraitAllAll, error[E0658]: attributes in `where` clause are unstable --> $DIR/feature-gate-where_clause_attrs.rs:160:9 | -LL | #[cfg_attr(any(), cfg(any()))] U: TraitAnyAny, +LL | #[cfg_attr(false, cfg(false))] U: TraitAnyAny, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #115590 for more information diff --git a/tests/ui/feature-gates/feature-gate-where_clause_attrs.rs b/tests/ui/feature-gates/feature-gate-where_clause_attrs.rs index 09c734a52de0..b87a1d56ea06 100644 --- a/tests/ui/feature-gates/feature-gate-where_clause_attrs.rs +++ b/tests/ui/feature-gates/feature-gate-where_clause_attrs.rs @@ -15,16 +15,16 @@ trait TraitAA {} #[cfg_attr(b, cfg(b))] trait TraitBB {} -#[cfg(all())] +#[cfg(true)] trait TraitAll {} -#[cfg(any())] +#[cfg(false)] trait TraitAny {} -#[cfg_attr(all(), cfg(all()))] +#[cfg_attr(true, cfg(true))] trait TraitAllAll {} -#[cfg_attr(any(), cfg(any()))] +#[cfg_attr(false, cfg(false))] trait TraitAnyAny {} @@ -32,67 +32,67 @@ trait A where #[cfg(a)] T: TraitA, //~ ERROR attributes in `where` clause are unstable #[cfg(b)] T: TraitB, //~ ERROR attributes in `where` clause are unstable - #[cfg(all())] T: TraitAll, //~ ERROR attributes in `where` clause are unstable - #[cfg(any())] T: TraitAny, //~ ERROR attributes in `where` clause are unstable + #[cfg(true)] T: TraitAll, //~ ERROR attributes in `where` clause are unstable + #[cfg(false)] T: TraitAny, //~ ERROR attributes in `where` clause are unstable #[cfg_attr(a, cfg(a))] T: TraitAA, //~ ERROR attributes in `where` clause are unstable #[cfg_attr(b, cfg(b))] T: TraitBB, //~ ERROR attributes in `where` clause are unstable - #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, //~ ERROR attributes in `where` clause are unstable - #[cfg_attr(any(), cfg(any()))] T: TraitAnyAny, //~ ERROR attributes in `where` clause are unstable + #[cfg_attr(true, cfg(true))] T: TraitAllAll, //~ ERROR attributes in `where` clause are unstable + #[cfg_attr(false, cfg(false))] T: TraitAnyAny, //~ ERROR attributes in `where` clause are unstable { type B where #[cfg(a)] U: TraitA, //~ ERROR attributes in `where` clause are unstable #[cfg(b)] U: TraitB, //~ ERROR attributes in `where` clause are unstable - #[cfg(all())] U: TraitAll, //~ ERROR attributes in `where` clause are unstable - #[cfg(any())] U: TraitAny, //~ ERROR attributes in `where` clause are unstable + #[cfg(true)] U: TraitAll, //~ ERROR attributes in `where` clause are unstable + #[cfg(false)] U: TraitAny, //~ ERROR attributes in `where` clause are unstable #[cfg_attr(a, cfg(a))] U: TraitAA, //~ ERROR attributes in `where` clause are unstable #[cfg_attr(b, cfg(b))] U: TraitBB, //~ ERROR attributes in `where` clause are unstable - #[cfg_attr(all(), cfg(all()))] U: TraitAllAll, //~ ERROR attributes in `where` clause are unstable - #[cfg_attr(any(), cfg(any()))] U: TraitAnyAny; //~ ERROR attributes in `where` clause are unstable + #[cfg_attr(true, cfg(true))] U: TraitAllAll, //~ ERROR attributes in `where` clause are unstable + #[cfg_attr(false, cfg(false))] U: TraitAnyAny; //~ ERROR attributes in `where` clause are unstable fn foo(&self) where #[cfg(a)] U: TraitA, //~ ERROR attributes in `where` clause are unstable #[cfg(b)] U: TraitB, //~ ERROR attributes in `where` clause are unstable - #[cfg(all())] U: TraitAll, //~ ERROR attributes in `where` clause are unstable - #[cfg(any())] U: TraitAny, //~ ERROR attributes in `where` clause are unstable + #[cfg(true)] U: TraitAll, //~ ERROR attributes in `where` clause are unstable + #[cfg(false)] U: TraitAny, //~ ERROR attributes in `where` clause are unstable #[cfg_attr(a, cfg(a))] U: TraitAA, //~ ERROR attributes in `where` clause are unstable #[cfg_attr(b, cfg(b))] U: TraitBB, //~ ERROR attributes in `where` clause are unstable - #[cfg_attr(all(), cfg(all()))] U: TraitAllAll, //~ ERROR attributes in `where` clause are unstable - #[cfg_attr(any(), cfg(any()))] U: TraitAnyAny; //~ ERROR attributes in `where` clause are unstable + #[cfg_attr(true, cfg(true))] U: TraitAllAll, //~ ERROR attributes in `where` clause are unstable + #[cfg_attr(false, cfg(false))] U: TraitAnyAny; //~ ERROR attributes in `where` clause are unstable } impl A for T where #[cfg(a)] T: TraitA, //~ ERROR attributes in `where` clause are unstable #[cfg(b)] T: TraitB, //~ ERROR attributes in `where` clause are unstable - #[cfg(all())] T: TraitAll, //~ ERROR attributes in `where` clause are unstable - #[cfg(any())] T: TraitAny, //~ ERROR attributes in `where` clause are unstable + #[cfg(true)] T: TraitAll, //~ ERROR attributes in `where` clause are unstable + #[cfg(false)] T: TraitAny, //~ ERROR attributes in `where` clause are unstable #[cfg_attr(a, cfg(a))] T: TraitAA, //~ ERROR attributes in `where` clause are unstable #[cfg_attr(b, cfg(b))] T: TraitBB, //~ ERROR attributes in `where` clause are unstable - #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, //~ ERROR attributes in `where` clause are unstable - #[cfg_attr(any(), cfg(any()))] T: TraitAnyAny, //~ ERROR attributes in `where` clause are unstable + #[cfg_attr(true, cfg(true))] T: TraitAllAll, //~ ERROR attributes in `where` clause are unstable + #[cfg_attr(false, cfg(false))] T: TraitAnyAny, //~ ERROR attributes in `where` clause are unstable { type B = () where #[cfg(a)] U: TraitA, //~ ERROR attributes in `where` clause are unstable #[cfg(b)] U: TraitB, //~ ERROR attributes in `where` clause are unstable - #[cfg(all())] U: TraitAll, //~ ERROR attributes in `where` clause are unstable - #[cfg(any())] U: TraitAny, //~ ERROR attributes in `where` clause are unstable + #[cfg(true)] U: TraitAll, //~ ERROR attributes in `where` clause are unstable + #[cfg(false)] U: TraitAny, //~ ERROR attributes in `where` clause are unstable #[cfg_attr(a, cfg(a))] U: TraitAA, //~ ERROR attributes in `where` clause are unstable #[cfg_attr(b, cfg(b))] U: TraitBB, //~ ERROR attributes in `where` clause are unstable - #[cfg_attr(all(), cfg(all()))] U: TraitAllAll, //~ ERROR attributes in `where` clause are unstable - #[cfg_attr(any(), cfg(any()))] U: TraitAnyAny; //~ ERROR attributes in `where` clause are unstable + #[cfg_attr(true, cfg(true))] U: TraitAllAll, //~ ERROR attributes in `where` clause are unstable + #[cfg_attr(false, cfg(false))] U: TraitAnyAny; //~ ERROR attributes in `where` clause are unstable fn foo(&self) where #[cfg(a)] U: TraitA, //~ ERROR attributes in `where` clause are unstable #[cfg(b)] U: TraitB, //~ ERROR attributes in `where` clause are unstable - #[cfg(all())] T: TraitAll, //~ ERROR attributes in `where` clause are unstable - #[cfg(any())] T: TraitAny, //~ ERROR attributes in `where` clause are unstable + #[cfg(true)] T: TraitAll, //~ ERROR attributes in `where` clause are unstable + #[cfg(false)] T: TraitAny, //~ ERROR attributes in `where` clause are unstable #[cfg_attr(a, cfg(a))] U: TraitAA, //~ ERROR attributes in `where` clause are unstable #[cfg_attr(b, cfg(b))] U: TraitBB, //~ ERROR attributes in `where` clause are unstable - #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, //~ ERROR attributes in `where` clause are unstable - #[cfg_attr(any(), cfg(any()))] T: TraitAnyAny, //~ ERROR attributes in `where` clause are unstable + #[cfg_attr(true, cfg(true))] T: TraitAllAll, //~ ERROR attributes in `where` clause are unstable + #[cfg_attr(false, cfg(false))] T: TraitAnyAny, //~ ERROR attributes in `where` clause are unstable {} } @@ -100,12 +100,12 @@ struct C where #[cfg(a)] T: TraitA, //~ ERROR attributes in `where` clause are unstable #[cfg(b)] T: TraitB, //~ ERROR attributes in `where` clause are unstable - #[cfg(all())] T: TraitAll, //~ ERROR attributes in `where` clause are unstable - #[cfg(any())] T: TraitAny, //~ ERROR attributes in `where` clause are unstable + #[cfg(true)] T: TraitAll, //~ ERROR attributes in `where` clause are unstable + #[cfg(false)] T: TraitAny, //~ ERROR attributes in `where` clause are unstable #[cfg_attr(a, cfg(a))] T: TraitAA, //~ ERROR attributes in `where` clause are unstable #[cfg_attr(b, cfg(b))] T: TraitBB, //~ ERROR attributes in `where` clause are unstable - #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, //~ ERROR attributes in `where` clause are unstable - #[cfg_attr(any(), cfg(any()))] T: TraitAnyAny, //~ ERROR attributes in `where` clause are unstable + #[cfg_attr(true, cfg(true))] T: TraitAllAll, //~ ERROR attributes in `where` clause are unstable + #[cfg_attr(false, cfg(false))] T: TraitAnyAny, //~ ERROR attributes in `where` clause are unstable { _t: PhantomData, } @@ -114,12 +114,12 @@ union D where #[cfg(a)] T: TraitA, //~ ERROR attributes in `where` clause are unstable #[cfg(b)] T: TraitB, //~ ERROR attributes in `where` clause are unstable - #[cfg(all())] T: TraitAll, //~ ERROR attributes in `where` clause are unstable - #[cfg(any())] T: TraitAny, //~ ERROR attributes in `where` clause are unstable + #[cfg(true)] T: TraitAll, //~ ERROR attributes in `where` clause are unstable + #[cfg(false)] T: TraitAny, //~ ERROR attributes in `where` clause are unstable #[cfg_attr(a, cfg(a))] T: TraitAA, //~ ERROR attributes in `where` clause are unstable #[cfg_attr(b, cfg(b))] T: TraitBB, //~ ERROR attributes in `where` clause are unstable - #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, //~ ERROR attributes in `where` clause are unstable - #[cfg_attr(any(), cfg(any()))] T: TraitAnyAny, //~ ERROR attributes in `where` clause are unstable + #[cfg_attr(true, cfg(true))] T: TraitAllAll, //~ ERROR attributes in `where` clause are unstable + #[cfg_attr(false, cfg(false))] T: TraitAnyAny, //~ ERROR attributes in `where` clause are unstable { _t: PhantomData, @@ -129,12 +129,12 @@ enum E where #[cfg(a)] T: TraitA, //~ ERROR attributes in `where` clause are unstable #[cfg(b)] T: TraitB, //~ ERROR attributes in `where` clause are unstable - #[cfg(all())] T: TraitAll, //~ ERROR attributes in `where` clause are unstable - #[cfg(any())] T: TraitAny, //~ ERROR attributes in `where` clause are unstable + #[cfg(true)] T: TraitAll, //~ ERROR attributes in `where` clause are unstable + #[cfg(false)] T: TraitAny, //~ ERROR attributes in `where` clause are unstable #[cfg_attr(a, cfg(a))] T: TraitAA, //~ ERROR attributes in `where` clause are unstable #[cfg_attr(b, cfg(b))] T: TraitBB, //~ ERROR attributes in `where` clause are unstable - #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, //~ ERROR attributes in `where` clause are unstable - #[cfg_attr(any(), cfg(any()))] T: TraitAnyAny, //~ ERROR attributes in `where` clause are unstable + #[cfg_attr(true, cfg(true))] T: TraitAllAll, //~ ERROR attributes in `where` clause are unstable + #[cfg_attr(false, cfg(false))] T: TraitAnyAny, //~ ERROR attributes in `where` clause are unstable { E(PhantomData), } @@ -142,21 +142,21 @@ where impl C where #[cfg(a)] T: TraitA, //~ ERROR attributes in `where` clause are unstable #[cfg(b)] T: TraitB, //~ ERROR attributes in `where` clause are unstable - #[cfg(all())] T: TraitAll, //~ ERROR attributes in `where` clause are unstable - #[cfg(any())] T: TraitAny, //~ ERROR attributes in `where` clause are unstable + #[cfg(true)] T: TraitAll, //~ ERROR attributes in `where` clause are unstable + #[cfg(false)] T: TraitAny, //~ ERROR attributes in `where` clause are unstable #[cfg_attr(a, cfg(a))] T: TraitAA, //~ ERROR attributes in `where` clause are unstable #[cfg_attr(b, cfg(b))] T: TraitBB, //~ ERROR attributes in `where` clause are unstable - #[cfg_attr(all(), cfg(all()))] T: TraitAllAll, //~ ERROR attributes in `where` clause are unstable - #[cfg_attr(any(), cfg(any()))] T: TraitAnyAny, //~ ERROR attributes in `where` clause are unstable + #[cfg_attr(true, cfg(true))] T: TraitAllAll, //~ ERROR attributes in `where` clause are unstable + #[cfg_attr(false, cfg(false))] T: TraitAnyAny, //~ ERROR attributes in `where` clause are unstable { fn new() where #[cfg(a)] U: TraitA, //~ ERROR attributes in `where` clause are unstable #[cfg(b)] U: TraitB, //~ ERROR attributes in `where` clause are unstable - #[cfg(all())] U: TraitAll, //~ ERROR attributes in `where` clause are unstable - #[cfg(any())] U: TraitAny, //~ ERROR attributes in `where` clause are unstable + #[cfg(true)] U: TraitAll, //~ ERROR attributes in `where` clause are unstable + #[cfg(false)] U: TraitAny, //~ ERROR attributes in `where` clause are unstable #[cfg_attr(a, cfg(a))] U: TraitAA, //~ ERROR attributes in `where` clause are unstable #[cfg_attr(b, cfg(b))] U: TraitBB, //~ ERROR attributes in `where` clause are unstable - #[cfg_attr(all(), cfg(all()))] U: TraitAllAll, //~ ERROR attributes in `where` clause are unstable - #[cfg_attr(any(), cfg(any()))] U: TraitAnyAny, //~ ERROR attributes in `where` clause are unstable + #[cfg_attr(true, cfg(true))] U: TraitAllAll, //~ ERROR attributes in `where` clause are unstable + #[cfg_attr(false, cfg(false))] U: TraitAnyAny, //~ ERROR attributes in `where` clause are unstable {} } diff --git a/tests/ui/issues/issue-24434.rs b/tests/ui/issues/issue-24434.rs index 991084c27409..429bcf4a8d87 100644 --- a/tests/ui/issues/issue-24434.rs +++ b/tests/ui/issues/issue-24434.rs @@ -1,6 +1,6 @@ //@ check-pass -#![cfg_attr(all(), feature(rustc_attrs))] +#![cfg_attr(true, feature(rustc_attrs))] #![rustc_dummy] fn main() {} diff --git a/tests/ui/lint/issue-97094.rs b/tests/ui/lint/issue-97094.rs index 22525ca11ae0..737f2827b67a 100644 --- a/tests/ui/lint/issue-97094.rs +++ b/tests/ui/lint/issue-97094.rs @@ -2,19 +2,19 @@ // Ensure that unknown lints inside cfg-attr's are linted for -#![cfg_attr(all(), allow(nonex_lint_top_level))] +#![cfg_attr(true, allow(nonex_lint_top_level))] //~^ ERROR unknown lint -#![cfg_attr(all(), allow(bare_trait_object))] +#![cfg_attr(true, allow(bare_trait_object))] //~^ ERROR has been renamed -#[cfg_attr(all(), allow(nonex_lint_mod))] +#[cfg_attr(true, allow(nonex_lint_mod))] //~^ ERROR unknown lint mod baz { - #![cfg_attr(all(), allow(nonex_lint_mod_inner))] + #![cfg_attr(true, allow(nonex_lint_mod_inner))] //~^ ERROR unknown lint } -#[cfg_attr(all(), allow(nonex_lint_fn))] +#[cfg_attr(true, allow(nonex_lint_fn))] //~^ ERROR unknown lint pub fn main() {} @@ -25,24 +25,24 @@ macro_rules! bar { } bar!( - #[cfg_attr(all(), allow(nonex_lint_in_macro))] + #[cfg_attr(true, allow(nonex_lint_in_macro))] //~^ ERROR unknown lint pub fn _bar() {} ); // No warning for non-applying cfg -#[cfg_attr(any(), allow(nonex_lint_fn))] +#[cfg_attr(false, allow(nonex_lint_fn))] pub fn _foo() {} // Allowing unknown lints works if inside cfg_attr -#[cfg_attr(all(), allow(unknown_lints))] +#[cfg_attr(true, allow(unknown_lints))] mod bar_allowed { #[allow(nonex_lint_fn)] fn _foo() {} } // ... but not if the cfg_attr doesn't evaluate -#[cfg_attr(any(), allow(unknown_lints))] +#[cfg_attr(false, allow(unknown_lints))] mod bar_not_allowed { #[allow(nonex_lint_fn)] //~^ ERROR unknown lint diff --git a/tests/ui/lint/issue-97094.stderr b/tests/ui/lint/issue-97094.stderr index 1a0a3eaf2507..e12250aa7542 100644 --- a/tests/ui/lint/issue-97094.stderr +++ b/tests/ui/lint/issue-97094.stderr @@ -1,8 +1,8 @@ error: unknown lint: `nonex_lint_top_level` - --> $DIR/issue-97094.rs:5:26 + --> $DIR/issue-97094.rs:5:25 | -LL | #![cfg_attr(all(), allow(nonex_lint_top_level))] - | ^^^^^^^^^^^^^^^^^^^^ +LL | #![cfg_attr(true, allow(nonex_lint_top_level))] + | ^^^^^^^^^^^^^^^^^^^^ | note: the lint level is defined here --> $DIR/issue-97094.rs:1:9 @@ -12,36 +12,36 @@ LL | #![deny(warnings)] = note: `#[deny(unknown_lints)]` implied by `#[deny(warnings)]` error: lint `bare_trait_object` has been renamed to `bare_trait_objects` - --> $DIR/issue-97094.rs:7:26 + --> $DIR/issue-97094.rs:7:25 | -LL | #![cfg_attr(all(), allow(bare_trait_object))] - | ^^^^^^^^^^^^^^^^^ help: use the new name: `bare_trait_objects` +LL | #![cfg_attr(true, allow(bare_trait_object))] + | ^^^^^^^^^^^^^^^^^ help: use the new name: `bare_trait_objects` | = note: `#[deny(renamed_and_removed_lints)]` implied by `#[deny(warnings)]` error: unknown lint: `nonex_lint_mod` - --> $DIR/issue-97094.rs:10:25 + --> $DIR/issue-97094.rs:10:24 | -LL | #[cfg_attr(all(), allow(nonex_lint_mod))] - | ^^^^^^^^^^^^^^ +LL | #[cfg_attr(true, allow(nonex_lint_mod))] + | ^^^^^^^^^^^^^^ error: unknown lint: `nonex_lint_mod_inner` - --> $DIR/issue-97094.rs:13:30 + --> $DIR/issue-97094.rs:13:29 | -LL | #![cfg_attr(all(), allow(nonex_lint_mod_inner))] - | ^^^^^^^^^^^^^^^^^^^^ +LL | #![cfg_attr(true, allow(nonex_lint_mod_inner))] + | ^^^^^^^^^^^^^^^^^^^^ error: unknown lint: `nonex_lint_fn` - --> $DIR/issue-97094.rs:17:25 + --> $DIR/issue-97094.rs:17:24 | -LL | #[cfg_attr(all(), allow(nonex_lint_fn))] - | ^^^^^^^^^^^^^ +LL | #[cfg_attr(true, allow(nonex_lint_fn))] + | ^^^^^^^^^^^^^ error: unknown lint: `nonex_lint_in_macro` - --> $DIR/issue-97094.rs:28:29 + --> $DIR/issue-97094.rs:28:28 | -LL | #[cfg_attr(all(), allow(nonex_lint_in_macro))] - | ^^^^^^^^^^^^^^^^^^^ +LL | #[cfg_attr(true, allow(nonex_lint_in_macro))] + | ^^^^^^^^^^^^^^^^^^^ error: unknown lint: `nonex_lint_fn` --> $DIR/issue-97094.rs:47:13 diff --git a/tests/ui/macros/issue-34171.rs b/tests/ui/macros/issue-34171.rs index fbc2ea50097d..3f13341230fa 100644 --- a/tests/ui/macros/issue-34171.rs +++ b/tests/ui/macros/issue-34171.rs @@ -6,5 +6,5 @@ macro_rules! apply_null { } fn main() { - apply_null!(#[cfg(all())] fn f() {}); + apply_null!(#[cfg(true)] fn f() {}); } diff --git a/tests/ui/parser/attribute-on-empty.rs b/tests/ui/parser/attribute-on-empty.rs index 5932377f73ec..0177e6c1b59d 100644 --- a/tests/ui/parser/attribute-on-empty.rs +++ b/tests/ui/parser/attribute-on-empty.rs @@ -4,7 +4,7 @@ struct Baz(i32); fn main() { - let _: Baz<#[cfg(any())]> = todo!(); + let _: Baz<#[cfg(false)]> = todo!(); //~^ ERROR attributes cannot be applied here } diff --git a/tests/ui/parser/attribute-on-empty.stderr b/tests/ui/parser/attribute-on-empty.stderr index 7c4806c8704a..6bcbf1ceb8d1 100644 --- a/tests/ui/parser/attribute-on-empty.stderr +++ b/tests/ui/parser/attribute-on-empty.stderr @@ -1,7 +1,7 @@ error: attributes cannot be applied here --> $DIR/attribute-on-empty.rs:7:16 | -LL | let _: Baz<#[cfg(any())]> = todo!(); +LL | let _: Baz<#[cfg(false)]> = todo!(); | - ^^^^^^^^^^^^^ attributes are not allowed here | | | while parsing the type for `_` diff --git a/tests/ui/parser/attribute-on-type.rs b/tests/ui/parser/attribute-on-type.rs index 196d322bdf8f..b400bd1c173f 100644 --- a/tests/ui/parser/attribute-on-type.rs +++ b/tests/ui/parser/attribute-on-type.rs @@ -16,16 +16,16 @@ fn main() { let _: #[attr] &'static str = "123"; //~^ ERROR attributes cannot be applied to types - let _: Bar<#[cfg(any())] 'static> = Bar(&123); + let _: Bar<#[cfg(false)] 'static> = Bar(&123); //~^ ERROR attributes cannot be applied to generic arguments - let _: Baz<#[cfg(any())] 42> = Baz(42); + let _: Baz<#[cfg(false)] 42> = Baz(42); //~^ ERROR attributes cannot be applied to generic arguments let _: Foo<#[cfg(not(wrong))]String> = Foo(String::new()); //~^ ERROR attributes cannot be applied to generic arguments - let _: Bar<#[cfg(any())] 'static> = Bar(&456); + let _: Bar<#[cfg(false)] 'static> = Bar(&456); //~^ ERROR attributes cannot be applied to generic arguments let _generic: Box<#[attr] i32> = Box::new(1); diff --git a/tests/ui/parser/attribute-on-type.stderr b/tests/ui/parser/attribute-on-type.stderr index 603c7e2be51a..316620325c04 100644 --- a/tests/ui/parser/attribute-on-type.stderr +++ b/tests/ui/parser/attribute-on-type.stderr @@ -13,13 +13,13 @@ LL | let _: #[attr] &'static str = "123"; error: attributes cannot be applied to generic arguments --> $DIR/attribute-on-type.rs:19:16 | -LL | let _: Bar<#[cfg(any())] 'static> = Bar(&123); +LL | let _: Bar<#[cfg(false)] 'static> = Bar(&123); | ^^^^^^^^^^^^^ attributes are not allowed here error: attributes cannot be applied to generic arguments --> $DIR/attribute-on-type.rs:22:16 | -LL | let _: Baz<#[cfg(any())] 42> = Baz(42); +LL | let _: Baz<#[cfg(false)] 42> = Baz(42); | ^^^^^^^^^^^^^ attributes are not allowed here error: attributes cannot be applied to generic arguments @@ -31,7 +31,7 @@ LL | let _: Foo<#[cfg(not(wrong))]String> = Foo(String::new()); error: attributes cannot be applied to generic arguments --> $DIR/attribute-on-type.rs:28:16 | -LL | let _: Bar<#[cfg(any())] 'static> = Bar(&456); +LL | let _: Bar<#[cfg(false)] 'static> = Bar(&456); | ^^^^^^^^^^^^^ attributes are not allowed here error: attributes cannot be applied to generic arguments diff --git a/tests/ui/parser/attribute/attr-pat-struct-rest.rs b/tests/ui/parser/attribute/attr-pat-struct-rest.rs index b2bfcf82df8d..8f0e4cd827e0 100644 --- a/tests/ui/parser/attribute/attr-pat-struct-rest.rs +++ b/tests/ui/parser/attribute/attr-pat-struct-rest.rs @@ -3,6 +3,6 @@ struct S {} fn main() { - let S { #[cfg(any())] .. } = S {}; + let S { #[cfg(false)] .. } = S {}; //~^ ERROR expected identifier, found `..` } diff --git a/tests/ui/parser/attribute/attr-pat-struct-rest.stderr b/tests/ui/parser/attribute/attr-pat-struct-rest.stderr index f72c54973fce..94ad7d571101 100644 --- a/tests/ui/parser/attribute/attr-pat-struct-rest.stderr +++ b/tests/ui/parser/attribute/attr-pat-struct-rest.stderr @@ -1,7 +1,7 @@ error: expected identifier, found `..` --> $DIR/attr-pat-struct-rest.rs:6:27 | -LL | let S { #[cfg(any())] .. } = S {}; +LL | let S { #[cfg(false)] .. } = S {}; | - ^^ expected identifier | | | while parsing the fields for this pattern diff --git a/tests/ui/parser/cfg-keyword-lifetime.rs b/tests/ui/parser/cfg-keyword-lifetime.rs index a1588eddc074..c61b69175c88 100644 --- a/tests/ui/parser/cfg-keyword-lifetime.rs +++ b/tests/ui/parser/cfg-keyword-lifetime.rs @@ -1,6 +1,6 @@ // Disallow `'keyword` even in cfg'd code. -#[cfg(any())] +#[cfg(false)] fn hello() -> &'ref () {} //~^ ERROR lifetimes cannot use keyword names diff --git a/tests/ui/parser/issue-116781.rs b/tests/ui/parser/issue-116781.rs index 0e951d2eaa44..176350fe2eec 100644 --- a/tests/ui/parser/issue-116781.rs +++ b/tests/ui/parser/issue-116781.rs @@ -1,6 +1,6 @@ #[derive(Debug)] struct Foo { - #[cfg(all())] + #[cfg(true)] field: fn(($),), //~ ERROR expected pattern, found `$` //~^ ERROR expected pattern, found `$` } diff --git a/tests/ui/parser/raw/raw-idents.rs b/tests/ui/parser/raw/raw-idents.rs index 93015ee6c494..4e1e6b124c31 100644 --- a/tests/ui/parser/raw/raw-idents.rs +++ b/tests/ui/parser/raw/raw-idents.rs @@ -62,7 +62,7 @@ macro_rules! tests { impl<$kw> B<$kw> {} } mod extern_crate { - #[cfg(any())] + #[cfg(false)] extern crate $kw; } mod body { diff --git a/tests/ui/parser/ty-path-followed-by-single-colon.rs b/tests/ui/parser/ty-path-followed-by-single-colon.rs index a9082ea317a7..588fec3f2fc8 100644 --- a/tests/ui/parser/ty-path-followed-by-single-colon.rs +++ b/tests/ui/parser/ty-path-followed-by-single-colon.rs @@ -12,7 +12,7 @@ mod garden { fn g(_: impl Take) {} // OK! - #[cfg(any())] fn h() where a::path:to::nowhere {} // OK! + #[cfg(false)] fn h() where a::path:to::nowhere {} // OK! fn i(_: impl Take:to::somewhere>) {} // OK! diff --git a/tests/ui/proc-macro/ambiguous-builtin-attrs.rs b/tests/ui/proc-macro/ambiguous-builtin-attrs.rs index 63d3c79055ca..e36a12beb818 100644 --- a/tests/ui/proc-macro/ambiguous-builtin-attrs.rs +++ b/tests/ui/proc-macro/ambiguous-builtin-attrs.rs @@ -9,7 +9,7 @@ use builtin_attrs::{bench, test}; #[repr(C)] //~ ERROR `repr` is ambiguous struct S; -#[cfg_attr(all(), repr(C))] //~ ERROR `repr` is ambiguous +#[cfg_attr(true, repr(C))] //~ ERROR `repr` is ambiguous struct SCond; #[test] // OK, shadowed diff --git a/tests/ui/proc-macro/ambiguous-builtin-attrs.stderr b/tests/ui/proc-macro/ambiguous-builtin-attrs.stderr index ff7894a41eab..d05701986260 100644 --- a/tests/ui/proc-macro/ambiguous-builtin-attrs.stderr +++ b/tests/ui/proc-macro/ambiguous-builtin-attrs.stderr @@ -20,10 +20,10 @@ LL | use builtin_attrs::*; = help: use `crate::repr` to refer to this attribute macro unambiguously error[E0659]: `repr` is ambiguous - --> $DIR/ambiguous-builtin-attrs.rs:12:19 + --> $DIR/ambiguous-builtin-attrs.rs:12:18 | -LL | #[cfg_attr(all(), repr(C))] - | ^^^^ ambiguous name +LL | #[cfg_attr(true, repr(C))] + | ^^^^ ambiguous name | = note: ambiguous because of a name conflict with a builtin attribute = note: `repr` could refer to a built-in attribute diff --git a/tests/ui/proc-macro/auxiliary/derive-attr-cfg.rs b/tests/ui/proc-macro/auxiliary/derive-attr-cfg.rs index cb60c182a43c..b1da93de2a6e 100644 --- a/tests/ui/proc-macro/auxiliary/derive-attr-cfg.rs +++ b/tests/ui/proc-macro/auxiliary/derive-attr-cfg.rs @@ -4,6 +4,6 @@ use proc_macro::TokenStream; #[proc_macro_derive(Foo, attributes(foo))] pub fn derive(input: TokenStream) -> TokenStream { - assert!(!input.to_string().contains("#[cfg(any())]")); + assert!(!input.to_string().contains("#[cfg(false)]")); "".parse().unwrap() } diff --git a/tests/ui/proc-macro/cfg-eval.rs b/tests/ui/proc-macro/cfg-eval.rs index 9e9e46912588..60c94ad2a752 100644 --- a/tests/ui/proc-macro/cfg-eval.rs +++ b/tests/ui/proc-macro/cfg-eval.rs @@ -17,9 +17,9 @@ extern crate test_macros; struct S1 { #[cfg(false)] field_false: u8, - #[cfg(all(/*true*/))] + #[cfg(true)] #[cfg_attr(FALSE, unknown_attr)] - #[cfg_attr(all(/*true*/), allow())] //~ WARN unused attribute + #[cfg_attr(true, allow())] //~ WARN unused attribute field_true: u8, } @@ -29,9 +29,9 @@ struct S2 {} fn main() { // Subtle - we need a trailing comma after the '1' - otherwise, `#[cfg_eval]` will - // turn this into `(#[cfg(all())] 1)`, which is a parenthesized expression, not a tuple + // turn this into `(#[cfg(true)] 1)`, which is a parenthesized expression, not a tuple // expression. `#[cfg]` is not supported inside parenthesized expressions, so this will // produce an error when attribute collection runs. let _ = #[cfg_eval] #[print_attr] #[cfg_attr(not(FALSE), rustc_dummy)] - (#[cfg(false)] 0, #[cfg(all(/*true*/))] 1,); + (#[cfg(false)] 0, #[cfg(true)] 1,); } diff --git a/tests/ui/proc-macro/cfg-eval.stderr b/tests/ui/proc-macro/cfg-eval.stderr index 1429dbde7bfc..72c452c7a08a 100644 --- a/tests/ui/proc-macro/cfg-eval.stderr +++ b/tests/ui/proc-macro/cfg-eval.stderr @@ -1,8 +1,8 @@ warning: unused attribute --> $DIR/cfg-eval.rs:22:5 | -LL | #[cfg_attr(all(/*true*/), allow())] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute +LL | #[cfg_attr(true, allow())] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute | = note: attribute `allow` with an empty list has no effect = note: requested on the command line with `-W unused-attributes` diff --git a/tests/ui/proc-macro/cfg-eval.stdout b/tests/ui/proc-macro/cfg-eval.stdout index 5d88297ad688..6493eee46547 100644 --- a/tests/ui/proc-macro/cfg-eval.stdout +++ b/tests/ui/proc-macro/cfg-eval.stdout @@ -1,5 +1,5 @@ -PRINT-ATTR INPUT (DISPLAY): struct S1 { #[cfg(all())] #[allow()] field_true: u8, } -PRINT-ATTR DEEP-RE-COLLECTED (DISPLAY): struct S1 { #[cfg(all())] #[allow()] field_true : u8, } +PRINT-ATTR INPUT (DISPLAY): struct S1 { #[cfg(true)] #[allow()] field_true: u8, } +PRINT-ATTR DEEP-RE-COLLECTED (DISPLAY): struct S1 { #[cfg(true)] #[allow()] field_true : u8, } PRINT-ATTR INPUT (DEBUG): TokenStream [ Ident { ident: "struct", @@ -28,19 +28,14 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ delimiter: Parenthesis, stream: TokenStream [ Ident { - ident: "all", - span: $DIR/cfg-eval.rs:20:11: 20:14 (#0), - }, - Group { - delimiter: Parenthesis, - stream: TokenStream [], - span: $DIR/cfg-eval.rs:20:14: 20:24 (#0), + ident: "true", + span: $DIR/cfg-eval.rs:20:11: 20:15 (#0), }, ], - span: $DIR/cfg-eval.rs:20:10: 20:25 (#0), + span: $DIR/cfg-eval.rs:20:10: 20:16 (#0), }, ], - span: $DIR/cfg-eval.rs:20:6: 20:26 (#0), + span: $DIR/cfg-eval.rs:20:6: 20:17 (#0), }, Punct { ch: '#', @@ -52,15 +47,15 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ stream: TokenStream [ Ident { ident: "allow", - span: $DIR/cfg-eval.rs:22:31: 22:36 (#0), + span: $DIR/cfg-eval.rs:22:22: 22:27 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [], - span: $DIR/cfg-eval.rs:22:36: 22:38 (#0), + span: $DIR/cfg-eval.rs:22:27: 22:29 (#0), }, ], - span: $DIR/cfg-eval.rs:22:6: 22:40 (#0), + span: $DIR/cfg-eval.rs:22:6: 22:31 (#0), }, Ident { ident: "field_true", @@ -84,7 +79,7 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ span: $DIR/cfg-eval.rs:17:11: 24:2 (#0), }, ] -PRINT-ATTR INPUT (DISPLAY): #[rustc_dummy] (#[cfg(all())] 1,) +PRINT-ATTR INPUT (DISPLAY): #[rustc_dummy] (#[cfg(true)] 1,) PRINT-ATTR INPUT (DEBUG): TokenStream [ Punct { ch: '#', @@ -120,32 +115,27 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ delimiter: Parenthesis, stream: TokenStream [ Ident { - ident: "all", - span: $DIR/cfg-eval.rs:36:29: 36:32 (#0), - }, - Group { - delimiter: Parenthesis, - stream: TokenStream [], - span: $DIR/cfg-eval.rs:36:32: 36:42 (#0), + ident: "true", + span: $DIR/cfg-eval.rs:36:29: 36:33 (#0), }, ], - span: $DIR/cfg-eval.rs:36:28: 36:43 (#0), + span: $DIR/cfg-eval.rs:36:28: 36:34 (#0), }, ], - span: $DIR/cfg-eval.rs:36:24: 36:44 (#0), + span: $DIR/cfg-eval.rs:36:24: 36:35 (#0), }, Literal { kind: Integer, symbol: "1", suffix: None, - span: $DIR/cfg-eval.rs:36:45: 36:46 (#0), + span: $DIR/cfg-eval.rs:36:36: 36:37 (#0), }, Punct { ch: ',', spacing: Alone, - span: $DIR/cfg-eval.rs:36:46: 36:47 (#0), + span: $DIR/cfg-eval.rs:36:37: 36:38 (#0), }, ], - span: $DIR/cfg-eval.rs:36:5: 36:48 (#0), + span: $DIR/cfg-eval.rs:36:5: 36:39 (#0), }, ] diff --git a/tests/ui/proc-macro/derive-attr-cfg.rs b/tests/ui/proc-macro/derive-attr-cfg.rs index 2f3516cabae9..21d3a93ffa6c 100644 --- a/tests/ui/proc-macro/derive-attr-cfg.rs +++ b/tests/ui/proc-macro/derive-attr-cfg.rs @@ -9,7 +9,7 @@ use derive_attr_cfg::Foo; #[derive(Foo)] #[foo] struct S { - #[cfg(any())] + #[cfg(false)] x: i32 } diff --git a/tests/ui/proc-macro/derive-b.rs b/tests/ui/proc-macro/derive-b.rs index 68d341478f18..c04152f629ca 100644 --- a/tests/ui/proc-macro/derive-b.rs +++ b/tests/ui/proc-macro/derive-b.rs @@ -4,7 +4,7 @@ extern crate derive_b_rpass as derive_b; #[derive(Debug, PartialEq, derive_b::B, Eq, Copy, Clone)] -#[cfg_attr(all(), B[arbitrary tokens])] +#[cfg_attr(true, B[arbitrary tokens])] struct B { #[C] a: u64 diff --git a/tests/ui/proc-macro/derive-helper-configured.rs b/tests/ui/proc-macro/derive-helper-configured.rs index b753e29b8bf3..b96ebdebaebb 100644 --- a/tests/ui/proc-macro/derive-helper-configured.rs +++ b/tests/ui/proc-macro/derive-helper-configured.rs @@ -7,9 +7,9 @@ extern crate test_macros; #[derive(Empty)] -#[cfg_attr(all(), empty_helper)] +#[cfg_attr(true, empty_helper)] struct S { - #[cfg_attr(all(), empty_helper)] + #[cfg_attr(true, empty_helper)] field: u8, } diff --git a/tests/ui/resolve/suggestions/suggest-import-without-clobbering-attrs.fixed b/tests/ui/resolve/suggestions/suggest-import-without-clobbering-attrs.fixed index cfbf9ef38684..f6fbff175a99 100644 --- a/tests/ui/resolve/suggestions/suggest-import-without-clobbering-attrs.fixed +++ b/tests/ui/resolve/suggestions/suggest-import-without-clobbering-attrs.fixed @@ -3,7 +3,7 @@ //@ compile-flags: -Aunused use y::z; -#[cfg(all())] +#[cfg(true)] use y::Whatever; mod y { diff --git a/tests/ui/resolve/suggestions/suggest-import-without-clobbering-attrs.rs b/tests/ui/resolve/suggestions/suggest-import-without-clobbering-attrs.rs index 98be104d8fde..73f263e19aa4 100644 --- a/tests/ui/resolve/suggestions/suggest-import-without-clobbering-attrs.rs +++ b/tests/ui/resolve/suggestions/suggest-import-without-clobbering-attrs.rs @@ -2,7 +2,7 @@ //@ run-rustfix //@ compile-flags: -Aunused -#[cfg(all())] +#[cfg(true)] use y::Whatever; mod y { diff --git a/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.fixed b/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.fixed index a2f04daa4b85..c1adc90161a4 100644 --- a/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.fixed +++ b/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.fixed @@ -43,7 +43,7 @@ macro_rules! meta2 { macro_rules! with_cfg_attr { () => { - #[cfg_attr(all(), unsafe(link_section = ".custom_section"))] + #[cfg_attr(true, unsafe(link_section = ".custom_section"))] //~^ ERROR: unsafe attribute used without unsafe //~| WARN this is accepted in the current edition pub extern "C" fn abc() {} diff --git a/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.rs b/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.rs index 88c9328fd9cd..9fdf37904634 100644 --- a/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.rs +++ b/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.rs @@ -43,7 +43,7 @@ macro_rules! meta2 { macro_rules! with_cfg_attr { () => { - #[cfg_attr(all(), link_section = ".custom_section")] + #[cfg_attr(true, link_section = ".custom_section")] //~^ ERROR: unsafe attribute used without unsafe //~| WARN this is accepted in the current edition pub extern "C" fn abc() {} diff --git a/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.stderr b/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.stderr index 55df60c51d9c..279e61a9cb67 100644 --- a/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.stderr +++ b/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.stderr @@ -77,10 +77,10 @@ LL | #[unsafe($e = $l)] | +++++++ + error: unsafe attribute used without unsafe - --> $DIR/unsafe-attributes-fix.rs:46:27 + --> $DIR/unsafe-attributes-fix.rs:46:26 | -LL | #[cfg_attr(all(), link_section = ".custom_section")] - | ^^^^^^^^^^^^ usage of unsafe attribute +LL | #[cfg_attr(true, link_section = ".custom_section")] + | ^^^^^^^^^^^^ usage of unsafe attribute ... LL | with_cfg_attr!(); | ---------------- in this macro invocation @@ -90,8 +90,8 @@ LL | with_cfg_attr!(); = note: this error originates in the macro `with_cfg_attr` (in Nightly builds, run with -Z macro-backtrace for more info) help: wrap the attribute in `unsafe(...)` | -LL | #[cfg_attr(all(), unsafe(link_section = ".custom_section"))] - | +++++++ + +LL | #[cfg_attr(true, unsafe(link_section = ".custom_section"))] + | +++++++ + error: unsafe attribute used without unsafe --> $DIR/unsafe-attributes-fix.rs:67:3 diff --git a/tests/ui/static/static-align.rs b/tests/ui/static/static-align.rs index e2db7c01adf2..c1c9f79996ed 100644 --- a/tests/ui/static/static-align.rs +++ b/tests/ui/static/static-align.rs @@ -53,7 +53,7 @@ thread_local! { #[allow(unused_mut, reason = "test attribute handling")] #[cfg_attr(TRUE, cfg_attr(FOURTY_TWO = "42", - cfg_attr(all(), + cfg_attr(true, cfg_attr(any(true), cfg_attr(true, rustc_align_static(4096))))))] #[allow(unused_mut, reason = "test attribute handling")] diff --git a/tests/ui/structs/struct-field-cfg.rs b/tests/ui/structs/struct-field-cfg.rs index 42cab8ab916b..84f913927dab 100644 --- a/tests/ui/structs/struct-field-cfg.rs +++ b/tests/ui/structs/struct-field-cfg.rs @@ -3,16 +3,16 @@ struct Foo { } fn main() { - let foo = Foo { #[cfg(all())] present: () }; - let _ = Foo { #[cfg(any())] present: () }; + let foo = Foo { #[cfg(true)] present: () }; + let _ = Foo { #[cfg(false)] present: () }; //~^ ERROR missing field `present` in initializer of `Foo` - let _ = Foo { present: (), #[cfg(any())] absent: () }; - let _ = Foo { present: (), #[cfg(all())] absent: () }; + let _ = Foo { present: (), #[cfg(false)] absent: () }; + let _ = Foo { present: (), #[cfg(true)] absent: () }; //~^ ERROR struct `Foo` has no field named `absent` - let Foo { #[cfg(all())] present: () } = foo; - let Foo { #[cfg(any())] present: () } = foo; + let Foo { #[cfg(true)] present: () } = foo; + let Foo { #[cfg(false)] present: () } = foo; //~^ ERROR pattern does not mention field `present` - let Foo { present: (), #[cfg(any())] absent: () } = foo; - let Foo { present: (), #[cfg(all())] absent: () } = foo; + let Foo { present: (), #[cfg(false)] absent: () } = foo; + let Foo { present: (), #[cfg(true)] absent: () } = foo; //~^ ERROR struct `Foo` does not have a field named `absent` } diff --git a/tests/ui/structs/struct-field-cfg.stderr b/tests/ui/structs/struct-field-cfg.stderr index 2bca6f302db7..db280a632d63 100644 --- a/tests/ui/structs/struct-field-cfg.stderr +++ b/tests/ui/structs/struct-field-cfg.stderr @@ -1,44 +1,44 @@ error[E0063]: missing field `present` in initializer of `Foo` --> $DIR/struct-field-cfg.rs:7:13 | -LL | let _ = Foo { #[cfg(any())] present: () }; +LL | let _ = Foo { #[cfg(false)] present: () }; | ^^^ missing `present` error[E0560]: struct `Foo` has no field named `absent` - --> $DIR/struct-field-cfg.rs:10:46 + --> $DIR/struct-field-cfg.rs:10:45 | -LL | let _ = Foo { present: (), #[cfg(all())] absent: () }; - | ^^^^^^ `Foo` does not have this field +LL | let _ = Foo { present: (), #[cfg(true)] absent: () }; + | ^^^^^^ `Foo` does not have this field | = note: all struct fields are already assigned error[E0027]: pattern does not mention field `present` --> $DIR/struct-field-cfg.rs:13:9 | -LL | let Foo { #[cfg(any())] present: () } = foo; +LL | let Foo { #[cfg(false)] present: () } = foo; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing field `present` | help: include the missing field in the pattern | -LL - let Foo { #[cfg(any())] present: () } = foo; +LL - let Foo { #[cfg(false)] present: () } = foo; LL + let Foo { present } = foo; | help: if you don't care about this missing field, you can explicitly ignore it | -LL - let Foo { #[cfg(any())] present: () } = foo; +LL - let Foo { #[cfg(false)] present: () } = foo; LL + let Foo { present: _ } = foo; | help: or always ignore missing fields here | -LL - let Foo { #[cfg(any())] present: () } = foo; +LL - let Foo { #[cfg(false)] present: () } = foo; LL + let Foo { .. } = foo; | error[E0026]: struct `Foo` does not have a field named `absent` - --> $DIR/struct-field-cfg.rs:16:42 + --> $DIR/struct-field-cfg.rs:16:41 | -LL | let Foo { present: (), #[cfg(all())] absent: () } = foo; - | ^^^^^^ struct `Foo` does not have this field +LL | let Foo { present: (), #[cfg(true)] absent: () } = foo; + | ^^^^^^ struct `Foo` does not have this field error: aborting due to 4 previous errors diff --git a/tests/ui/test-attrs/issue-34932.rs b/tests/ui/test-attrs/issue-34932.rs index feb6556b60a1..f0cbdd07df84 100644 --- a/tests/ui/test-attrs/issue-34932.rs +++ b/tests/ui/test-attrs/issue-34932.rs @@ -1,6 +1,6 @@ //@ run-pass //@ compile-flags:--test -#![cfg(any())] // This test should be configured away +#![cfg(false)] // This test should be configured away #![feature(rustc_attrs)] // Test that this is allowed on stable/beta #![feature(iter_arith_traits)] // Test that this is not unused #![deny(unused_features)] diff --git a/tests/ui/typeck/issue-86721-return-expr-ice.rs b/tests/ui/typeck/issue-86721-return-expr-ice.rs index ea3a2f2fbfe6..ed36164aea60 100644 --- a/tests/ui/typeck/issue-86721-return-expr-ice.rs +++ b/tests/ui/typeck/issue-86721-return-expr-ice.rs @@ -1,7 +1,7 @@ // Regression test for the ICE described in #86721. //@ revisions: rev1 rev2 -#![cfg_attr(any(), rev1, rev2)] +#![cfg_attr(false, rev1, rev2)] #![crate_type = "lib"] #[cfg(any(rev1))] From 51806323f9288e9cdab756a6b528823bcadcaa7a Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 11 Dec 2025 01:35:28 +0100 Subject: [PATCH 52/64] Do not error if there are duplicated doc attributes --- compiler/rustc_attr_parsing/src/attributes/doc.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/doc.rs b/compiler/rustc_attr_parsing/src/attributes/doc.rs index 2fe1b4ad174c..547f00d14041 100644 --- a/compiler/rustc_attr_parsing/src/attributes/doc.rs +++ b/compiler/rustc_attr_parsing/src/attributes/doc.rs @@ -358,10 +358,14 @@ impl DocParser { return; } - if self.attribute.$ident.is_some() { - cx.duplicate_key(path.span(), path.word_sym().unwrap()); - return; - } + // FIXME: It's errorring when the attribute is passed multiple times on the command + // line. + // The right fix for this would be to only check this rule if the attribute is + // not set on the command line but directly in the code. + // if self.attribute.$ident.is_some() { + // cx.duplicate_key(path.span(), path.word_sym().unwrap()); + // return; + // } self.attribute.$ident = Some(path.span()); }}; From a96d486cbd96c5f6819bec25e1f23a71b23233a7 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Thu, 11 Dec 2025 14:01:00 +0100 Subject: [PATCH 53/64] Update snapshot --- src/bootstrap/src/core/builder/tests.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index b8ba1b4c2c34..28659f4c6fa5 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -2912,6 +2912,7 @@ mod snapshot { [build] rustc 1 -> rust-analyzer-proc-macro-srv 2 [build] rustc 0 -> GenerateCopyright 1 [dist] rustc + [dist] rustc 1 -> rustc-dev 2 [build] rustc 1 -> cargo 2 [dist] rustc 1 -> cargo 2 [build] rustc 1 -> rust-analyzer 2 From c60ed211d1a7216fd422f99da158e853e3eca2d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 10 Dec 2025 20:20:22 +0000 Subject: [PATCH 54/64] Do not suggest moving expression out of for loop when hitting `break` from desugaring --- .../src/diagnostics/conflict_errors.rs | 4 +- .../closure/spawn-thread.edition2018.stderr | 10 ----- .../moves/arc-consumed-in-looped-closure.rs | 37 +++++++++++++++++++ .../arc-consumed-in-looped-closure.stderr | 27 ++++++++++++++ .../nested-loop-moved-value-wrong-continue.rs | 6 +-- ...ted-loop-moved-value-wrong-continue.stderr | 30 +++------------ 6 files changed, 74 insertions(+), 40 deletions(-) create mode 100644 tests/ui/moves/arc-consumed-in-looped-closure.rs create mode 100644 tests/ui/moves/arc-consumed-in-looped-closure.stderr diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index f8a6fafbe78a..2999d1f2926c 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -4521,7 +4521,9 @@ struct BreakFinder { impl<'hir> Visitor<'hir> for BreakFinder { fn visit_expr(&mut self, ex: &'hir hir::Expr<'hir>) { match ex.kind { - hir::ExprKind::Break(destination, _) => { + hir::ExprKind::Break(destination, _) + if !ex.span.is_desugaring(DesugaringKind::ForLoop) => + { self.found_breaks.push((destination, ex.span)); } hir::ExprKind::Continue(destination) => { diff --git a/tests/ui/ergonomic-clones/closure/spawn-thread.edition2018.stderr b/tests/ui/ergonomic-clones/closure/spawn-thread.edition2018.stderr index ac8e1c5fa858..4ac5dfb8d228 100644 --- a/tests/ui/ergonomic-clones/closure/spawn-thread.edition2018.stderr +++ b/tests/ui/ergonomic-clones/closure/spawn-thread.edition2018.stderr @@ -12,16 +12,6 @@ LL | | drop((x.0, x.1, x.2)); | | --- use occurs due to use in closure LL | | }); | |_________- value moved here, in previous iteration of loop - | -help: consider moving the expression out of the loop so it is only moved once - | -LL ~ let mut value = std::thread::spawn(use || { -LL + -LL + drop((x.0, x.1, x.2)); -LL + }); -LL ~ for _ in 0..10 { -LL ~ let handler = value; - | error: aborting due to 1 previous error diff --git a/tests/ui/moves/arc-consumed-in-looped-closure.rs b/tests/ui/moves/arc-consumed-in-looped-closure.rs new file mode 100644 index 000000000000..8700c7850847 --- /dev/null +++ b/tests/ui/moves/arc-consumed-in-looped-closure.rs @@ -0,0 +1,37 @@ +use std::thread; +use std::sync::{Arc, Mutex, Condvar}; +use std::collections::VecDeque; + +type Job = Box; + +struct ThreadPool { + workers: Vec>, + queue: Arc<()>, +} + +impl ThreadPool { + fn execute(&self, f: F) + where + F: FnOnce() + Send + 'static, + { + panic!() + } +} + +fn main() { + let results = Arc::new(Mutex::new(Vec::new())); //~ NOTE move occurs because + let pool = ThreadPool { + workers: vec![], + queue: Arc::new(()), + }; + + for i in 0..20 { //~ NOTE inside of this loop + // let results = Arc::clone(&results); // Forgot this. + pool.execute(move || { //~ ERROR E0382 + //~^ NOTE value moved into closure here, in previous iteration of loop + //~| HELP consider cloning the value before moving it into the closure + let mut r = results.lock().unwrap(); //~ NOTE use occurs due to use in closure + r.push(i); + }); + } +} diff --git a/tests/ui/moves/arc-consumed-in-looped-closure.stderr b/tests/ui/moves/arc-consumed-in-looped-closure.stderr new file mode 100644 index 000000000000..47d6fd6cbad3 --- /dev/null +++ b/tests/ui/moves/arc-consumed-in-looped-closure.stderr @@ -0,0 +1,27 @@ +error[E0382]: use of moved value: `results` + --> $DIR/arc-consumed-in-looped-closure.rs:30:22 + | +LL | let results = Arc::new(Mutex::new(Vec::new())); + | ------- move occurs because `results` has type `Arc>>`, which does not implement the `Copy` trait +... +LL | for i in 0..20 { + | -------------- inside of this loop +LL | // let results = Arc::clone(&results); // Forgot this. +LL | pool.execute(move || { + | ^^^^^^^ value moved into closure here, in previous iteration of loop +... +LL | let mut r = results.lock().unwrap(); + | ------- use occurs due to use in closure + | +help: consider cloning the value before moving it into the closure + | +LL ~ let value = results.clone(); +LL ~ pool.execute(move || { +LL | +LL | +LL ~ let mut r = value.lock().unwrap(); + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/moves/nested-loop-moved-value-wrong-continue.rs b/tests/ui/moves/nested-loop-moved-value-wrong-continue.rs index 87800d314ed5..0cbb501a5764 100644 --- a/tests/ui/moves/nested-loop-moved-value-wrong-continue.rs +++ b/tests/ui/moves/nested-loop-moved-value-wrong-continue.rs @@ -7,8 +7,6 @@ fn foo() { //~^ NOTE this reinitialization might get skipped //~| NOTE move occurs because `foo` has type `String` //~| NOTE inside of this loop - //~| HELP consider moving the expression out of the loop - //~| NOTE in this expansion of desugaring of `for` loop //~| NOTE //~| NOTE baz.push(foo); @@ -35,8 +33,6 @@ fn main() { //~| NOTE for bar in &bars { //~^ NOTE inside of this loop - //~| HELP consider moving the expression out of the loop - //~| NOTE in this expansion of desugaring of `for` loop //~| NOTE if foo == *bar { baz.push(foo); @@ -44,7 +40,7 @@ fn main() { //~| HELP consider cloning the value continue; //~^ NOTE verify that your loop breaking logic is correct - //~| NOTE this `continue` advances the loop at line 36 + //~| NOTE this `continue` advances the loop at line 34 } } qux.push(foo); diff --git a/tests/ui/moves/nested-loop-moved-value-wrong-continue.stderr b/tests/ui/moves/nested-loop-moved-value-wrong-continue.stderr index 6ef1a4193b1a..60be70007fbe 100644 --- a/tests/ui/moves/nested-loop-moved-value-wrong-continue.stderr +++ b/tests/ui/moves/nested-loop-moved-value-wrong-continue.stderr @@ -1,5 +1,5 @@ error[E0382]: use of moved value: `foo` - --> $DIR/nested-loop-moved-value-wrong-continue.rs:21:14 + --> $DIR/nested-loop-moved-value-wrong-continue.rs:19:14 | LL | for foo in foos { for bar in &bars { if foo == *bar { | --- ---------------- inside of this loop @@ -14,29 +14,20 @@ LL | qux.push(foo); | ^^^ value used here after move | note: verify that your loop breaking logic is correct - --> $DIR/nested-loop-moved-value-wrong-continue.rs:17:9 + --> $DIR/nested-loop-moved-value-wrong-continue.rs:15:9 | LL | for foo in foos { for bar in &bars { if foo == *bar { | --------------- ---------------- ... LL | continue; - | ^^^^^^^^ this `continue` advances the loop at $DIR/nested-loop-moved-value-wrong-continue.rs:6:23: 20:8 -help: consider moving the expression out of the loop so it is only moved once - | -LL ~ for foo in foos { let mut value = baz.push(foo); -LL ~ for bar in &bars { if foo == *bar { -LL | -... -LL | -LL ~ value; - | + | ^^^^^^^^ this `continue` advances the loop at $DIR/nested-loop-moved-value-wrong-continue.rs:6:23: 18:8 help: consider cloning the value if the performance cost is acceptable | LL | baz.push(foo.clone()); | ++++++++ error[E0382]: use of moved value: `foo` - --> $DIR/nested-loop-moved-value-wrong-continue.rs:50:18 + --> $DIR/nested-loop-moved-value-wrong-continue.rs:46:18 | LL | for foo in foos { | --- @@ -54,7 +45,7 @@ LL | qux.push(foo); | ^^^ value used here after move | note: verify that your loop breaking logic is correct - --> $DIR/nested-loop-moved-value-wrong-continue.rs:45:17 + --> $DIR/nested-loop-moved-value-wrong-continue.rs:41:17 | LL | for foo in foos { | --------------- @@ -63,16 +54,7 @@ LL | for bar in &bars { | ---------------- ... LL | continue; - | ^^^^^^^^ this `continue` advances the loop at line 36 -help: consider moving the expression out of the loop so it is only moved once - | -LL ~ let mut value = baz.push(foo); -LL ~ for bar in &bars { -LL | -... -LL | if foo == *bar { -LL ~ value; - | + | ^^^^^^^^ this `continue` advances the loop at line 34 help: consider cloning the value if the performance cost is acceptable | LL | baz.push(foo.clone()); From 43fa2a95c90d7ac4bb98d87e62630e9f549d00c2 Mon Sep 17 00:00:00 2001 From: cyrgani Date: Thu, 11 Dec 2025 18:15:15 +0000 Subject: [PATCH 55/64] add regression test for `proc_macro` error subdiagnostics --- tests/ui/proc-macro/auxiliary/sub-error-diag.rs | 17 +++++++++++++++++ tests/ui/proc-macro/sub-error-diag.rs | 13 +++++++++++++ tests/ui/proc-macro/sub-error-diag.stderr | 11 +++++++++++ 3 files changed, 41 insertions(+) create mode 100644 tests/ui/proc-macro/auxiliary/sub-error-diag.rs create mode 100644 tests/ui/proc-macro/sub-error-diag.rs create mode 100644 tests/ui/proc-macro/sub-error-diag.stderr diff --git a/tests/ui/proc-macro/auxiliary/sub-error-diag.rs b/tests/ui/proc-macro/auxiliary/sub-error-diag.rs new file mode 100644 index 000000000000..5ce8c5d90304 --- /dev/null +++ b/tests/ui/proc-macro/auxiliary/sub-error-diag.rs @@ -0,0 +1,17 @@ +#![feature(proc_macro_diagnostic)] + +extern crate proc_macro; + +use proc_macro::{Diagnostic, Level, Span}; + +#[proc_macro_attribute] +pub fn proc_emit_err( + _: proc_macro::TokenStream, + input: proc_macro::TokenStream, +) -> proc_macro::TokenStream { + Diagnostic::new(Level::Error, "Parent message") + .span_error(Span::call_site(), "Child message") + .emit(); + + input +} diff --git a/tests/ui/proc-macro/sub-error-diag.rs b/tests/ui/proc-macro/sub-error-diag.rs new file mode 100644 index 000000000000..11218fc66a37 --- /dev/null +++ b/tests/ui/proc-macro/sub-error-diag.rs @@ -0,0 +1,13 @@ +//@ proc-macro: sub-error-diag.rs + +// Regression test for issue https://github.com/rust-lang/rust/issues/145305, which used to cause an ICE +// due to an assertion in the compiler that errors could not be subdiagnostics. + +extern crate sub_error_diag; + +//~? ERROR: Parent message +#[sub_error_diag::proc_emit_err] +//~^ ERROR: Child message +fn foo() {} + +fn main() {} diff --git a/tests/ui/proc-macro/sub-error-diag.stderr b/tests/ui/proc-macro/sub-error-diag.stderr new file mode 100644 index 000000000000..b5d83e4d52ae --- /dev/null +++ b/tests/ui/proc-macro/sub-error-diag.stderr @@ -0,0 +1,11 @@ +error: Parent message + | +error: Child message + --> $DIR/sub-error-diag.rs:9:1 + | +LL | #[sub_error_diag::proc_emit_err] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: this error originates in the attribute macro `sub_error_diag::proc_emit_err` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 1 previous error + From 03493597922f6d1527955b1d7558dd369126f1d9 Mon Sep 17 00:00:00 2001 From: Jamie Hill-Daniel Date: Mon, 8 Dec 2025 21:39:59 +0000 Subject: [PATCH 56/64] Suggest `cfg(false)` instead of `cfg(FALSE)` --- compiler/rustc_lint/messages.ftl | 1 + .../src/early/diagnostics/check_cfg.rs | 25 +++++ compiler/rustc_lint/src/lints.rs | 11 +++ tests/ui/check-cfg/false.rs | 61 ++++++++++++ tests/ui/check-cfg/false.stderr | 95 +++++++++++++++++++ 5 files changed, 193 insertions(+) create mode 100644 tests/ui/check-cfg/false.rs create mode 100644 tests/ui/check-cfg/false.stderr diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index bc1c246b8f03..846c83aff2d3 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -829,6 +829,7 @@ lint_unexpected_cfg_add_build_rs_println = or consider adding `{$build_rs_printl lint_unexpected_cfg_add_cargo_feature = consider using a Cargo feature instead lint_unexpected_cfg_add_cargo_toml_lint_cfg = or consider adding in `Cargo.toml` the `check-cfg` lint config for the lint:{$cargo_toml_lint_cfg} lint_unexpected_cfg_add_cmdline_arg = to expect this configuration use `{$cmdline_arg}` +lint_unexpected_cfg_boolean = you may have meant to use `{$literal}` (notice the capitalization). Doing so makes this predicate evaluate to `{$literal}` unconditionally lint_unexpected_cfg_cargo_update = the {$macro_kind} `{$macro_name}` may come from an old version of the `{$crate_name}` crate, try updating your dependency with `cargo update -p {$crate_name}` lint_unexpected_cfg_define_features = consider defining some features in `Cargo.toml` diff --git a/compiler/rustc_lint/src/early/diagnostics/check_cfg.rs b/compiler/rustc_lint/src/early/diagnostics/check_cfg.rs index e2f5dd315d57..0c8d7523a9dc 100644 --- a/compiler/rustc_lint/src/early/diagnostics/check_cfg.rs +++ b/compiler/rustc_lint/src/early/diagnostics/check_cfg.rs @@ -138,6 +138,16 @@ pub(super) fn unexpected_cfg_name( let is_from_external_macro = name_span.in_external_macro(sess.source_map()); let mut is_feature_cfg = name == sym::feature; + fn miscapitalized_boolean(name: Symbol) -> Option { + if name.as_str().eq_ignore_ascii_case("false") { + Some(false) + } else if name.as_str().eq_ignore_ascii_case("true") { + Some(true) + } else { + None + } + } + let code_sugg = if is_feature_cfg && is_from_cargo { lints::unexpected_cfg_name::CodeSuggestion::DefineFeatures // Suggest correct `version("..")` predicate syntax @@ -148,6 +158,21 @@ pub(super) fn unexpected_cfg_name( between_name_and_value: name_span.between(value_span), after_value: value_span.shrink_to_hi(), } + // Suggest a literal `false` instead + // Detect miscapitalized `False`/`FALSE` etc, ensuring that this isn't `r#false` + } else if value.is_none() + // If this is a miscapitalized False/FALSE, suggest the boolean literal instead + && let Some(boolean) = miscapitalized_boolean(name) + // Check this isn't a raw identifier + && sess + .source_map() + .span_to_snippet(name_span) + .map_or(true, |snippet| !snippet.contains("r#")) + { + lints::unexpected_cfg_name::CodeSuggestion::BooleanLiteral { + span: name_span, + literal: boolean, + } // Suggest the most probable if we found one } else if let Some(best_match) = find_best_match_for_name(&possibilities, name, None) { is_feature_cfg |= best_match == sym::feature; diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 1bec316ce45a..3f853e09c72d 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -2401,6 +2401,17 @@ pub(crate) mod unexpected_cfg_name { #[subdiagnostic] expected_names: Option, }, + #[suggestion( + lint_unexpected_cfg_boolean, + applicability = "machine-applicable", + style = "verbose", + code = "{literal}" + )] + BooleanLiteral { + #[primary_span] + span: Span, + literal: bool, + }, } #[derive(Subdiagnostic)] diff --git a/tests/ui/check-cfg/false.rs b/tests/ui/check-cfg/false.rs new file mode 100644 index 000000000000..f7ed43ccfa95 --- /dev/null +++ b/tests/ui/check-cfg/false.rs @@ -0,0 +1,61 @@ +//! Check that `cfg(false)` is suggested instead of cfg(FALSE) +// +//@ check-pass +//@ no-auto-check-cfg +//@ compile-flags: --check-cfg=cfg() + +#[cfg(FALSE)] +//~^ WARNING unexpected `cfg` condition name: `FALSE` +//~| HELP: to expect this configuration use +//~| HELP: you may have meant to use `false` (notice the capitalization). +pub fn a() {} + +#[cfg(False)] +//~^ WARNING unexpected `cfg` condition name: `False` +//~| HELP: to expect this configuration use +//~| HELP: you may have meant to use `false` (notice the capitalization). +pub fn b() {} + +#[cfg(r#false)] +//~^ WARNING unexpected `cfg` condition name: `r#false` +//~| HELP: to expect this configuration use +// No capitalization help for r#false +pub fn c() {} + +#[cfg(r#False)] +//~^ WARNING unexpected `cfg` condition name: `False` +//~| HELP: to expect this configuration use +// No capitalization help for r#False +pub fn d() {} + +#[cfg(false)] +pub fn e() {} + +#[cfg(TRUE)] +//~^ WARNING unexpected `cfg` condition name: `TRUE` +//~| HELP: to expect this configuration use +//~| HELP: you may have meant to use `true` (notice the capitalization). +pub fn f() {} + +#[cfg(True)] +//~^ WARNING unexpected `cfg` condition name: `True` +//~| HELP: to expect this configuration use +//~| HELP: you may have meant to use `true` (notice the capitalization). +pub fn g() {} + +#[cfg(r#true)] +//~^ WARNING unexpected `cfg` condition name: `r#true` +//~| HELP: to expect this configuration use +// No capitalization help for r#true +pub fn h() {} + +#[cfg(r#True)] +//~^ WARNING unexpected `cfg` condition name: `True` +//~| HELP: to expect this configuration use +// No capitalization help for r#True +pub fn i() {} + +#[cfg(true)] +pub fn j() {} + +pub fn main() {} diff --git a/tests/ui/check-cfg/false.stderr b/tests/ui/check-cfg/false.stderr new file mode 100644 index 000000000000..f4480a3dc67e --- /dev/null +++ b/tests/ui/check-cfg/false.stderr @@ -0,0 +1,95 @@ +warning: unexpected `cfg` condition name: `FALSE` + --> $DIR/false.rs:7:7 + | +LL | #[cfg(FALSE)] + | ^^^^^ + | + = help: to expect this configuration use `--check-cfg=cfg(FALSE)` + = note: see for more information about checking conditional configuration + = note: `#[warn(unexpected_cfgs)]` on by default +help: you may have meant to use `false` (notice the capitalization). Doing so makes this predicate evaluate to `false` unconditionally + | +LL - #[cfg(FALSE)] +LL + #[cfg(false)] + | + +warning: unexpected `cfg` condition name: `False` + --> $DIR/false.rs:13:7 + | +LL | #[cfg(False)] + | ^^^^^ + | + = help: to expect this configuration use `--check-cfg=cfg(False)` + = note: see for more information about checking conditional configuration +help: you may have meant to use `false` (notice the capitalization). Doing so makes this predicate evaluate to `false` unconditionally (notice the capitalization) + | +LL - #[cfg(False)] +LL + #[cfg(false)] + | + +warning: unexpected `cfg` condition name: `r#false` + --> $DIR/false.rs:19:7 + | +LL | #[cfg(r#false)] + | ^^^^^^^ + | + = help: to expect this configuration use `--check-cfg=cfg(r#false)` + = note: see for more information about checking conditional configuration + +warning: unexpected `cfg` condition name: `False` + --> $DIR/false.rs:25:7 + | +LL | #[cfg(r#False)] + | ^^^^^^^ + | + = help: to expect this configuration use `--check-cfg=cfg(False)` + = note: see for more information about checking conditional configuration + +warning: unexpected `cfg` condition name: `TRUE` + --> $DIR/false.rs:34:7 + | +LL | #[cfg(TRUE)] + | ^^^^ + | + = help: to expect this configuration use `--check-cfg=cfg(TRUE)` + = note: see for more information about checking conditional configuration +help: you may have meant to use `true` (notice the capitalization). Doing so makes this predicate evaluate to `true` unconditionally + | +LL - #[cfg(TRUE)] +LL + #[cfg(true)] + | + +warning: unexpected `cfg` condition name: `True` + --> $DIR/false.rs:40:7 + | +LL | #[cfg(True)] + | ^^^^ + | + = help: to expect this configuration use `--check-cfg=cfg(True)` + = note: see for more information about checking conditional configuration +help: you may have meant to use `true` (notice the capitalization). Doing so makes this predicate evaluate to `true` unconditionally + | +LL - #[cfg(True)] +LL + #[cfg(true)] + | + +warning: unexpected `cfg` condition name: `r#true` + --> $DIR/false.rs:46:7 + | +LL | #[cfg(r#true)] + | ^^^^^^ + | + = help: to expect this configuration use `--check-cfg=cfg(r#true)` + = note: see for more information about checking conditional configuration + +warning: unexpected `cfg` condition name: `True` + --> $DIR/false.rs:52:7 + | +LL | #[cfg(r#True)] + | ^^^^^^ + | + = help: to expect this configuration use `--check-cfg=cfg(True)` + = note: see for more information about checking conditional configuration + +warning: 8 warnings emitted + From de0d961eb3cf26c73b2d03464845ab465a5484e5 Mon Sep 17 00:00:00 2001 From: Makai Date: Fri, 12 Dec 2025 10:25:23 +0800 Subject: [PATCH 57/64] triagebot: ping makai410 for rustc_public --- triagebot.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/triagebot.toml b/triagebot.toml index 397e6875eef9..00e2d4c787ab 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -1154,7 +1154,7 @@ cc = ["@davidtwco", "@compiler-errors", "@TaKO8Ki"] [mentions."compiler/rustc_public"] message = "This PR changes rustc_public" -cc = ["@oli-obk", "@celinval", "@ouz-a"] +cc = ["@oli-obk", "@celinval", "@ouz-a", "@makai410"] [mentions."compiler/rustc_target/src/spec"] message = """ From 24302fd95f026197304b4814cab668553b4b345c Mon Sep 17 00:00:00 2001 From: Makai Date: Fri, 12 Dec 2025 10:26:03 +0800 Subject: [PATCH 58/64] triagebot: add myself(makai410) to the review rotation --- triagebot.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/triagebot.toml b/triagebot.toml index 00e2d4c787ab..3182122bdeb0 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -1542,6 +1542,7 @@ project-stable-mir = [ "@celinval", "@oli-obk", "@scottmcm", + "@makai410", ] project-exploit-mitigations = [ "@cuviper", From 5aa2c14aebc731f54e737231e6f57cc7fc47a659 Mon Sep 17 00:00:00 2001 From: Makai Date: Fri, 12 Dec 2025 10:35:13 +0800 Subject: [PATCH 59/64] mailmap: add makai410 --- .mailmap | 1 + 1 file changed, 1 insertion(+) diff --git a/.mailmap b/.mailmap index a586e7047769..4c254b396b53 100644 --- a/.mailmap +++ b/.mailmap @@ -431,6 +431,7 @@ Lzu Tao Maik Klein Maja Kądziołka Maja Kądziołka +Makai Malo Jaffré Manish Goregaokar Mara Bos From 97252d3747161635253ec7fefa413c2843be5321 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Mon, 8 Dec 2025 22:31:55 +0100 Subject: [PATCH 60/64] Remove from `MetaItemParser::from_attr` --- compiler/rustc_attr_parsing/src/interface.rs | 21 ++++++++++---------- compiler/rustc_attr_parsing/src/parser.rs | 18 +---------------- 2 files changed, 12 insertions(+), 27 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/interface.rs b/compiler/rustc_attr_parsing/src/interface.rs index 5eefce75ace2..45b46803419d 100644 --- a/compiler/rustc_attr_parsing/src/interface.rs +++ b/compiler/rustc_attr_parsing/src/interface.rs @@ -1,4 +1,5 @@ use std::borrow::Cow; +use std::convert::identity; use rustc_ast as ast; use rustc_ast::token::DocFragmentKind; @@ -13,7 +14,7 @@ use rustc_session::lint::BuiltinLintDiag; use rustc_span::{DUMMY_SP, Span, Symbol, sym}; use crate::context::{AcceptContext, FinalizeContext, SharedContext, Stage}; -use crate::parser::{ArgParser, MetaItemParser, PathParser}; +use crate::parser::{ArgParser, PathParser}; use crate::session_diagnostics::ParsedDescription; use crate::{Early, Late, OmitDoc, ShouldEmit}; @@ -144,22 +145,23 @@ impl<'sess> AttributeParser<'sess, Early> { }; let parts = normal_attr.item.path.segments.iter().map(|seg| seg.ident.name).collect::>(); - let meta_parser = MetaItemParser::from_attr(normal_attr, &parts, &sess.psess, emit_errors)?; - let path = meta_parser.path(); - let args = meta_parser.args(); + + let path = AttrPath::from_ast(&normal_attr.item.path, identity); + let args = + ArgParser::from_attr_args(&normal_attr.item.args, &parts, &sess.psess, emit_errors)?; Self::parse_single_args( sess, attr.span, normal_attr.item.span(), attr.style, - path.get_attribute_path(), + path, Some(normal_attr.item.unsafety), ParsedDescription::Attribute, target_span, target_node_id, features, emit_errors, - args, + &args, parse_fn, template, ) @@ -316,15 +318,14 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { n.item.path.segments.iter().map(|seg| seg.ident.name).collect::>(); if let Some(accepts) = S::parsers().accepters.get(parts.as_slice()) { - let Some(parser) = MetaItemParser::from_attr( - n, + let Some(args) = ArgParser::from_attr_args( + &n.item.args, &parts, &self.sess.psess, self.stage.should_emit(), ) else { continue; }; - let args = parser.args(); // Special-case handling for `#[doc = "..."]`: if we go through with // `DocParser`, the order of doc comments will be messed up because `///` @@ -373,7 +374,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { attr_path: attr_path.clone(), }; - (accept.accept_fn)(&mut cx, args); + (accept.accept_fn)(&mut cx, &args); if !matches!(cx.stage.should_emit(), ShouldEmit::Nothing) { Self::check_target(&accept.allowed_targets, target, &mut cx); } diff --git a/compiler/rustc_attr_parsing/src/parser.rs b/compiler/rustc_attr_parsing/src/parser.rs index 819e5630561d..2304fb0ca63c 100644 --- a/compiler/rustc_attr_parsing/src/parser.rs +++ b/compiler/rustc_attr_parsing/src/parser.rs @@ -8,7 +8,7 @@ use std::fmt::{Debug, Display}; use rustc_ast::token::{self, Delimiter, MetaVarKind}; use rustc_ast::tokenstream::TokenStream; -use rustc_ast::{AttrArgs, Expr, ExprKind, LitKind, MetaItemLit, NormalAttr, Path, StmtKind, UnOp}; +use rustc_ast::{AttrArgs, Expr, ExprKind, LitKind, MetaItemLit, Path, StmtKind, UnOp}; use rustc_ast_pretty::pprust; use rustc_errors::{Diag, PResult}; use rustc_hir::{self as hir, AttrPath}; @@ -252,22 +252,6 @@ impl<'a> Debug for MetaItemParser<'a> { } } -impl<'a> MetaItemParser<'a> { - /// Create a new parser from a [`NormalAttr`], which is stored inside of any - /// [`ast::Attribute`](rustc_ast::Attribute) - pub fn from_attr<'sess>( - attr: &'a NormalAttr, - parts: &[Symbol], - psess: &'sess ParseSess, - should_emit: ShouldEmit, - ) -> Option { - Some(Self { - path: PathParser(Cow::Borrowed(&attr.item.path)), - args: ArgParser::from_attr_args(&attr.item.args, parts, psess, should_emit)?, - }) - } -} - impl<'a> MetaItemParser<'a> { pub fn span(&self) -> Span { if let Some(other) = self.args.span() { From 86a97c41cbfae596cad6e6e9191c414e7a77a520 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Mon, 8 Dec 2025 22:48:13 +0100 Subject: [PATCH 61/64] Remove lifetime param from parser types --- .../src/attributes/allow_unstable.rs | 8 +- .../rustc_attr_parsing/src/attributes/cfg.rs | 8 +- .../src/attributes/codegen_attrs.rs | 18 ++-- .../src/attributes/crate_level.rs | 12 +-- .../src/attributes/debugger.rs | 2 +- .../src/attributes/deprecation.rs | 4 +- .../src/attributes/dummy.rs | 2 +- .../src/attributes/inline.rs | 4 +- .../src/attributes/link_attrs.rs | 22 ++--- .../src/attributes/macro_attrs.rs | 2 +- .../rustc_attr_parsing/src/attributes/mod.rs | 8 +- .../src/attributes/must_use.rs | 2 +- .../rustc_attr_parsing/src/attributes/path.rs | 2 +- .../src/attributes/proc_macro_attrs.rs | 6 +- .../src/attributes/prototype.rs | 4 +- .../rustc_attr_parsing/src/attributes/repr.rs | 21 ++--- .../src/attributes/rustc_internal.rs | 8 +- .../src/attributes/stability.rs | 6 +- .../src/attributes/test_attrs.rs | 4 +- .../src/attributes/traits.rs | 2 +- .../src/attributes/transparency.rs | 2 +- .../rustc_attr_parsing/src/attributes/util.rs | 2 +- compiler/rustc_attr_parsing/src/context.rs | 6 +- compiler/rustc_attr_parsing/src/interface.rs | 9 +- compiler/rustc_attr_parsing/src/parser.rs | 83 ++++++++++--------- 25 files changed, 119 insertions(+), 128 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs index 088fa73d7427..faa366a62831 100644 --- a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs +++ b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs @@ -19,7 +19,7 @@ impl CombineAttributeParser for AllowInternalUnstableParser { fn extend<'c>( cx: &'c mut AcceptContext<'_, '_, S>, - args: &'c ArgParser<'_>, + args: &'c ArgParser, ) -> impl IntoIterator { parse_unstable(cx, args, >::PATH[0]) .into_iter() @@ -41,7 +41,7 @@ impl CombineAttributeParser for UnstableFeatureBoundParser { fn extend<'c>( cx: &'c mut AcceptContext<'_, '_, S>, - args: &'c ArgParser<'_>, + args: &'c ArgParser, ) -> impl IntoIterator { if !cx.features().staged_api() { cx.emit_err(session_diagnostics::StabilityOutsideStd { span: cx.attr_span }); @@ -69,7 +69,7 @@ impl CombineAttributeParser for AllowConstFnUnstableParser { fn extend<'c>( cx: &'c mut AcceptContext<'_, '_, S>, - args: &'c ArgParser<'_>, + args: &'c ArgParser, ) -> impl IntoIterator + 'c { parse_unstable(cx, args, >::PATH[0]) } @@ -77,7 +77,7 @@ impl CombineAttributeParser for AllowConstFnUnstableParser { fn parse_unstable( cx: &AcceptContext<'_, '_, S>, - args: &ArgParser<'_>, + args: &ArgParser, symbol: Symbol, ) -> impl IntoIterator { let mut res = Vec::new(); diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg.rs b/compiler/rustc_attr_parsing/src/attributes/cfg.rs index 6ffe25098308..61c314b41b65 100644 --- a/compiler/rustc_attr_parsing/src/attributes/cfg.rs +++ b/compiler/rustc_attr_parsing/src/attributes/cfg.rs @@ -37,7 +37,7 @@ const CFG_ATTR_TEMPLATE: AttributeTemplate = template!( pub fn parse_cfg<'c, S: Stage>( cx: &'c mut AcceptContext<'_, '_, S>, - args: &'c ArgParser<'_>, + args: &'c ArgParser, ) -> Option { let ArgParser::List(list) = args else { cx.expected_list(cx.attr_span); @@ -52,7 +52,7 @@ pub fn parse_cfg<'c, S: Stage>( pub fn parse_cfg_entry( cx: &mut AcceptContext<'_, '_, S>, - item: &MetaItemOrLitParser<'_>, + item: &MetaItemOrLitParser, ) -> Result { Ok(match item { MetaItemOrLitParser::MetaItemParser(meta) => match meta.args() { @@ -98,7 +98,7 @@ pub fn parse_cfg_entry( fn parse_cfg_entry_version( cx: &mut AcceptContext<'_, '_, S>, - list: &MetaItemListParser<'_>, + list: &MetaItemListParser, meta_span: Span, ) -> Result { try_gate_cfg(sym::version, meta_span, cx.sess(), cx.features_option()); @@ -130,7 +130,7 @@ fn parse_cfg_entry_version( fn parse_cfg_entry_target( cx: &mut AcceptContext<'_, '_, S>, - list: &MetaItemListParser<'_>, + list: &MetaItemListParser, meta_span: Span, ) -> Result { if let Some(features) = cx.features_option() diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs index b4ecbe6e4de6..ce208203ec5e 100644 --- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs @@ -23,7 +23,7 @@ impl SingleAttributeParser for OptimizeParser { ]); const TEMPLATE: AttributeTemplate = template!(List: &["size", "speed", "none"]); - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let Some(list) = args.list() else { cx.expected_list(cx.attr_span); return None; @@ -84,7 +84,7 @@ impl SingleAttributeParser for CoverageParser { ]); const TEMPLATE: AttributeTemplate = template!(OneOf: &[sym::off, sym::on]); - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let Some(args) = args.list() else { cx.expected_specific_argument_and_list(cx.attr_span, &[sym::on, sym::off]); return None; @@ -135,7 +135,7 @@ impl SingleAttributeParser for ExportNameParser { ]); const TEMPLATE: AttributeTemplate = template!(NameValueStr: "name"); - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let Some(nv) = args.name_value() else { cx.expected_name_value(cx.attr_span, None); return None; @@ -164,7 +164,7 @@ impl SingleAttributeParser for ObjcClassParser { AllowedTargets::AllowList(&[Allow(Target::ForeignStatic)]); const TEMPLATE: AttributeTemplate = template!(NameValueStr: "ClassName"); - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let Some(nv) = args.name_value() else { cx.expected_name_value(cx.attr_span, None); return None; @@ -196,7 +196,7 @@ impl SingleAttributeParser for ObjcSelectorParser { AllowedTargets::AllowList(&[Allow(Target::ForeignStatic)]); const TEMPLATE: AttributeTemplate = template!(NameValueStr: "methodName"); - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let Some(nv) = args.name_value() else { cx.expected_name_value(cx.attr_span, None); return None; @@ -474,7 +474,7 @@ impl AttributeParser for UsedParser { fn parse_tf_attribute<'c, S: Stage>( cx: &'c mut AcceptContext<'_, '_, S>, - args: &'c ArgParser<'_>, + args: &'c ArgParser, ) -> impl IntoIterator + 'c { let mut features = Vec::new(); let ArgParser::List(list) = args else { @@ -531,7 +531,7 @@ impl CombineAttributeParser for TargetFeatureParser { fn extend<'c>( cx: &'c mut AcceptContext<'_, '_, S>, - args: &'c ArgParser<'_>, + args: &'c ArgParser, ) -> impl IntoIterator + 'c { parse_tf_attribute(cx, args) } @@ -569,7 +569,7 @@ impl CombineAttributeParser for ForceTargetFeatureParser { fn extend<'c>( cx: &'c mut AcceptContext<'_, '_, S>, - args: &'c ArgParser<'_>, + args: &'c ArgParser, ) -> impl IntoIterator + 'c { parse_tf_attribute(cx, args) } @@ -599,7 +599,7 @@ impl SingleAttributeParser for SanitizeParser { const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let Some(list) = args.list() else { cx.expected_list(cx.attr_span); return None; diff --git a/compiler/rustc_attr_parsing/src/attributes/crate_level.rs b/compiler/rustc_attr_parsing/src/attributes/crate_level.rs index 480a32658bc5..01c503357fc7 100644 --- a/compiler/rustc_attr_parsing/src/attributes/crate_level.rs +++ b/compiler/rustc_attr_parsing/src/attributes/crate_level.rs @@ -11,7 +11,7 @@ impl SingleAttributeParser for CrateNameParser { const TEMPLATE: AttributeTemplate = template!(NameValueStr: "name"); const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel; - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let ArgParser::NameValue(n) = args else { cx.expected_name_value(cx.attr_span, None); return None; @@ -35,7 +35,7 @@ impl SingleAttributeParser for RecursionLimitParser { const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N", "https://doc.rust-lang.org/reference/attributes/limits.html#the-recursion_limit-attribute"); const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel; - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let ArgParser::NameValue(nv) = args else { cx.expected_name_value(cx.attr_span, None); return None; @@ -58,7 +58,7 @@ impl SingleAttributeParser for MoveSizeLimitParser { const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N"); const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel; - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let ArgParser::NameValue(nv) = args else { cx.expected_name_value(cx.attr_span, None); return None; @@ -81,7 +81,7 @@ impl SingleAttributeParser for TypeLengthLimitParser { const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N"); const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel; - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let ArgParser::NameValue(nv) = args else { cx.expected_name_value(cx.attr_span, None); return None; @@ -104,7 +104,7 @@ impl SingleAttributeParser for PatternComplexityLimitParser { const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N"); const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel; - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let ArgParser::NameValue(nv) = args else { cx.expected_name_value(cx.attr_span, None); return None; @@ -154,7 +154,7 @@ impl SingleAttributeParser for WindowsSubsystemParser { const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel; const TEMPLATE: AttributeTemplate = template!(NameValueStr: ["windows", "console"], "https://doc.rust-lang.org/reference/runtime.html#the-windows_subsystem-attribute"); - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let Some(nv) = args.name_value() else { cx.expected_name_value( args.span().unwrap_or(cx.inner_span), diff --git a/compiler/rustc_attr_parsing/src/attributes/debugger.rs b/compiler/rustc_attr_parsing/src/attributes/debugger.rs index 56ff10be4264..dfb3b914e189 100644 --- a/compiler/rustc_attr_parsing/src/attributes/debugger.rs +++ b/compiler/rustc_attr_parsing/src/attributes/debugger.rs @@ -18,7 +18,7 @@ impl CombineAttributeParser for DebuggerViualizerParser { fn extend<'c>( cx: &'c mut AcceptContext<'_, '_, S>, - args: &'c ArgParser<'_>, + args: &'c ArgParser, ) -> impl IntoIterator + 'c { let Some(l) = args.list() else { cx.expected_list(args.span().unwrap_or(cx.attr_span)); diff --git a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs index f96477e28cd0..ad3e2ced60c7 100644 --- a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs +++ b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs @@ -12,7 +12,7 @@ fn get( cx: &AcceptContext<'_, '_, S>, name: Symbol, param_span: Span, - arg: &ArgParser<'_>, + arg: &ArgParser, item: &Option, ) -> Option { if item.is_some() { @@ -68,7 +68,7 @@ impl SingleAttributeParser for DeprecationParser { NameValueStr: "reason" ); - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let features = cx.features(); let mut since = None; diff --git a/compiler/rustc_attr_parsing/src/attributes/dummy.rs b/compiler/rustc_attr_parsing/src/attributes/dummy.rs index 7293cee842c2..0a7d95f31799 100644 --- a/compiler/rustc_attr_parsing/src/attributes/dummy.rs +++ b/compiler/rustc_attr_parsing/src/attributes/dummy.rs @@ -15,7 +15,7 @@ impl SingleAttributeParser for DummyParser { const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); const TEMPLATE: AttributeTemplate = template!(Word); // Anything, really - fn convert(_: &mut AcceptContext<'_, '_, S>, _: &ArgParser<'_>) -> Option { + fn convert(_: &mut AcceptContext<'_, '_, S>, _: &ArgParser) -> Option { Some(AttributeKind::Dummy) } } diff --git a/compiler/rustc_attr_parsing/src/attributes/inline.rs b/compiler/rustc_attr_parsing/src/attributes/inline.rs index fba1a663c057..f6aab9ea0ee2 100644 --- a/compiler/rustc_attr_parsing/src/attributes/inline.rs +++ b/compiler/rustc_attr_parsing/src/attributes/inline.rs @@ -34,7 +34,7 @@ impl SingleAttributeParser for InlineParser { "https://doc.rust-lang.org/reference/attributes/codegen.html#the-inline-attribute" ); - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { match args { ArgParser::NoArgs => Some(AttributeKind::Inline(InlineAttr::Hint, cx.attr_span)), ArgParser::List(list) => { @@ -77,7 +77,7 @@ impl SingleAttributeParser for RustcForceInlineParser { const TEMPLATE: AttributeTemplate = template!(Word, List: &["reason"], NameValueStr: "reason"); - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let reason = match args { ArgParser::NoArgs => None, ArgParser::List(list) => { diff --git a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs index 46fa8ee71343..67471e31b105 100644 --- a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs @@ -33,7 +33,7 @@ impl SingleAttributeParser for LinkNameParser { "https://doc.rust-lang.org/reference/items/external-blocks.html#the-link_name-attribute" ); - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let Some(nv) = args.name_value() else { cx.expected_name_value(cx.attr_span, None); return None; @@ -64,7 +64,7 @@ impl CombineAttributeParser for LinkParser { fn extend<'c>( cx: &'c mut AcceptContext<'_, '_, S>, - args: &'c ArgParser<'_>, + args: &'c ArgParser, ) -> impl IntoIterator + 'c { let items = match args { ArgParser::List(list) => list, @@ -242,7 +242,7 @@ impl CombineAttributeParser for LinkParser { impl LinkParser { fn parse_link_name( - item: &MetaItemParser<'_>, + item: &MetaItemParser, name: &mut Option<(Symbol, Span)>, cx: &mut AcceptContext<'_, '_, S>, ) -> bool { @@ -267,7 +267,7 @@ impl LinkParser { } fn parse_link_kind( - item: &MetaItemParser<'_>, + item: &MetaItemParser, kind: &mut Option, cx: &mut AcceptContext<'_, '_, S>, sess: &Session, @@ -347,7 +347,7 @@ impl LinkParser { } fn parse_link_modifiers( - item: &MetaItemParser<'_>, + item: &MetaItemParser, modifiers: &mut Option<(Symbol, Span)>, cx: &mut AcceptContext<'_, '_, S>, ) -> bool { @@ -368,7 +368,7 @@ impl LinkParser { } fn parse_link_cfg( - item: &MetaItemParser<'_>, + item: &MetaItemParser, cfg: &mut Option, cx: &mut AcceptContext<'_, '_, S>, sess: &Session, @@ -400,7 +400,7 @@ impl LinkParser { } fn parse_link_wasm_import_module( - item: &MetaItemParser<'_>, + item: &MetaItemParser, wasm_import_module: &mut Option<(Symbol, Span)>, cx: &mut AcceptContext<'_, '_, S>, ) -> bool { @@ -421,7 +421,7 @@ impl LinkParser { } fn parse_link_import_name_type( - item: &MetaItemParser<'_>, + item: &MetaItemParser, import_name_type: &mut Option<(PeImportNameType, Span)>, cx: &mut AcceptContext<'_, '_, S>, ) -> bool { @@ -478,7 +478,7 @@ impl SingleAttributeParser for LinkSectionParser { "https://doc.rust-lang.org/reference/abi.html#the-link_section-attribute" ); - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let Some(nv) = args.name_value() else { cx.expected_name_value(cx.attr_span, None); return None; @@ -551,7 +551,7 @@ impl SingleAttributeParser for LinkOrdinalParser { "https://doc.rust-lang.org/reference/items/external-blocks.html#the-link_ordinal-attribute" ); - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let ordinal = parse_single_integer(cx, args)?; // According to the table at @@ -607,7 +607,7 @@ impl SingleAttributeParser for LinkageParser { "weak_odr", ]); - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let Some(name_value) = args.name_value() else { cx.expected_name_value(cx.attr_span, Some(sym::linkage)); return None; diff --git a/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs index d2fa1d440f40..e4209c3edd85 100644 --- a/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs @@ -148,7 +148,7 @@ impl SingleAttributeParser for MacroExportParser { Error(Target::Crate), ]); - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let local_inner_macros = match args { ArgParser::NoArgs => false, ArgParser::List(list) => { diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs index 64bcb02b0b74..a26159cb09e7 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs @@ -62,7 +62,7 @@ pub(crate) mod traits; pub(crate) mod transparency; pub(crate) mod util; -type AcceptFn = for<'sess> fn(&mut T, &mut AcceptContext<'_, 'sess, S>, &ArgParser<'_>); +type AcceptFn = for<'sess> fn(&mut T, &mut AcceptContext<'_, 'sess, S>, &ArgParser); type AcceptMapping = &'static [(&'static [Symbol], AttributeTemplate, AcceptFn)]; /// An [`AttributeParser`] is a type which searches for syntactic attributes. @@ -133,7 +133,7 @@ pub(crate) trait SingleAttributeParser: 'static { const TEMPLATE: AttributeTemplate; /// Converts a single syntactical attribute to a single semantic attribute, or [`AttributeKind`] - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option; + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option; } /// Use in combination with [`SingleAttributeParser`]. @@ -282,7 +282,7 @@ impl, S: Stage> SingleAttributeParser for Without const ALLOWED_TARGETS: AllowedTargets = T::ALLOWED_TARGETS; const TEMPLATE: AttributeTemplate = template!(Word); - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { if let Err(span) = args.no_args() { cx.expected_no_args(span); } @@ -317,7 +317,7 @@ pub(crate) trait CombineAttributeParser: 'static { /// Converts a single syntactical attribute to a number of elements of the semantic attribute, or [`AttributeKind`] fn extend<'c>( cx: &'c mut AcceptContext<'_, '_, S>, - args: &'c ArgParser<'_>, + args: &'c ArgParser, ) -> impl IntoIterator + 'c; } diff --git a/compiler/rustc_attr_parsing/src/attributes/must_use.rs b/compiler/rustc_attr_parsing/src/attributes/must_use.rs index 51b43e96adf9..a27e1ecb707e 100644 --- a/compiler/rustc_attr_parsing/src/attributes/must_use.rs +++ b/compiler/rustc_attr_parsing/src/attributes/must_use.rs @@ -29,7 +29,7 @@ impl SingleAttributeParser for MustUseParser { "https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-must_use-attribute" ); - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { Some(AttributeKind::MustUse { span: cx.attr_span, reason: match args { diff --git a/compiler/rustc_attr_parsing/src/attributes/path.rs b/compiler/rustc_attr_parsing/src/attributes/path.rs index e4cb806bb427..b60f8e315e5e 100644 --- a/compiler/rustc_attr_parsing/src/attributes/path.rs +++ b/compiler/rustc_attr_parsing/src/attributes/path.rs @@ -13,7 +13,7 @@ impl SingleAttributeParser for PathParser { "https://doc.rust-lang.org/reference/items/modules.html#the-path-attribute" ); - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let Some(nv) = args.name_value() else { cx.expected_name_value(cx.attr_span, None); return None; diff --git a/compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs index b9929d6f1f8e..e1762005d4c4 100644 --- a/compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs @@ -30,7 +30,7 @@ impl SingleAttributeParser for ProcMacroDeriveParser { "https://doc.rust-lang.org/reference/procedural-macros.html#derive-macros" ); - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let (trait_name, helper_attrs) = parse_derive_like(cx, args, true)?; Some(AttributeKind::ProcMacroDerive { trait_name: trait_name.expect("Trait name is mandatory, so it is present"), @@ -49,7 +49,7 @@ impl SingleAttributeParser for RustcBuiltinMacroParser { const TEMPLATE: AttributeTemplate = template!(List: &["TraitName", "TraitName, attributes(name1, name2, ...)"]); - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let (builtin_name, helper_attrs) = parse_derive_like(cx, args, false)?; Some(AttributeKind::RustcBuiltinMacro { builtin_name, helper_attrs, span: cx.attr_span }) } @@ -57,7 +57,7 @@ impl SingleAttributeParser for RustcBuiltinMacroParser { fn parse_derive_like( cx: &mut AcceptContext<'_, '_, S>, - args: &ArgParser<'_>, + args: &ArgParser, trait_name_mandatory: bool, ) -> Option<(Option, ThinVec)> { let Some(list) = args.list() else { diff --git a/compiler/rustc_attr_parsing/src/attributes/prototype.rs b/compiler/rustc_attr_parsing/src/attributes/prototype.rs index 80fe82bf5429..cd7c84f45fe5 100644 --- a/compiler/rustc_attr_parsing/src/attributes/prototype.rs +++ b/compiler/rustc_attr_parsing/src/attributes/prototype.rs @@ -25,7 +25,7 @@ impl SingleAttributeParser for CustomMirParser { const TEMPLATE: AttributeTemplate = template!(List: &[r#"dialect = "...", phase = "...""#]); - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let Some(list) = args.list() else { cx.expected_list(cx.attr_span); return None; @@ -70,7 +70,7 @@ impl SingleAttributeParser for CustomMirParser { fn extract_value( cx: &mut AcceptContext<'_, '_, S>, key: Symbol, - arg: &ArgParser<'_>, + arg: &ArgParser, span: Span, out_val: &mut Option<(Symbol, Span)>, failed: &mut bool, diff --git a/compiler/rustc_attr_parsing/src/attributes/repr.rs b/compiler/rustc_attr_parsing/src/attributes/repr.rs index 0330e2515c7d..c7320bf5d96f 100644 --- a/compiler/rustc_attr_parsing/src/attributes/repr.rs +++ b/compiler/rustc_attr_parsing/src/attributes/repr.rs @@ -28,7 +28,7 @@ impl CombineAttributeParser for ReprParser { fn extend<'c>( cx: &'c mut AcceptContext<'_, '_, S>, - args: &'c ArgParser<'_>, + args: &'c ArgParser, ) -> impl IntoIterator + 'c { let mut reprs = Vec::new(); @@ -98,10 +98,7 @@ fn int_type_of_word(s: Symbol) -> Option { } } -fn parse_repr( - cx: &AcceptContext<'_, '_, S>, - param: &MetaItemParser<'_>, -) -> Option { +fn parse_repr(cx: &AcceptContext<'_, '_, S>, param: &MetaItemParser) -> Option { use ReprAttr::*; // FIXME(jdonszelmann): invert the parsing here to match on the word first and then the @@ -192,7 +189,7 @@ enum AlignKind { fn parse_repr_align( cx: &AcceptContext<'_, '_, S>, - list: &MetaItemListParser<'_>, + list: &MetaItemListParser, param_span: Span, align_kind: AlignKind, ) -> Option { @@ -278,11 +275,7 @@ impl AlignParser { const PATH: &'static [Symbol] = &[sym::rustc_align]; const TEMPLATE: AttributeTemplate = template!(List: &[""]); - fn parse<'c, S: Stage>( - &mut self, - cx: &'c mut AcceptContext<'_, '_, S>, - args: &'c ArgParser<'_>, - ) { + fn parse<'c, S: Stage>(&mut self, cx: &'c mut AcceptContext<'_, '_, S>, args: &'c ArgParser) { match args { ArgParser::NoArgs | ArgParser::NameValue(_) => { cx.expected_list(cx.attr_span); @@ -339,11 +332,7 @@ impl AlignStaticParser { const PATH: &'static [Symbol] = &[sym::rustc_align_static]; const TEMPLATE: AttributeTemplate = AlignParser::TEMPLATE; - fn parse<'c, S: Stage>( - &mut self, - cx: &'c mut AcceptContext<'_, '_, S>, - args: &'c ArgParser<'_>, - ) { + fn parse<'c, S: Stage>(&mut self, cx: &'c mut AcceptContext<'_, '_, S>, args: &'c ArgParser) { self.0.parse(cx, args) } } diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs index 455c61097d78..d51fa2510b93 100644 --- a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs +++ b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs @@ -19,7 +19,7 @@ impl SingleAttributeParser for RustcLayoutScalarValidRangeStartPars const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]); const TEMPLATE: AttributeTemplate = template!(List: &["start"]); - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { parse_single_integer(cx, args) .map(|n| AttributeKind::RustcLayoutScalarValidRangeStart(Box::new(n), cx.attr_span)) } @@ -34,7 +34,7 @@ impl SingleAttributeParser for RustcLayoutScalarValidRangeEndParser const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]); const TEMPLATE: AttributeTemplate = template!(List: &["end"]); - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { parse_single_integer(cx, args) .map(|n| AttributeKind::RustcLayoutScalarValidRangeEnd(Box::new(n), cx.attr_span)) } @@ -49,7 +49,7 @@ impl SingleAttributeParser for RustcObjectLifetimeDefaultParser { const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]); const TEMPLATE: AttributeTemplate = template!(Word); - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { if let Err(span) = args.no_args() { cx.expected_no_args(span); return None; @@ -68,7 +68,7 @@ impl SingleAttributeParser for RustcSimdMonomorphizeLaneLimitParser const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]); const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N"); - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let ArgParser::NameValue(nv) = args else { cx.expected_name_value(cx.attr_span, None); return None; diff --git a/compiler/rustc_attr_parsing/src/attributes/stability.rs b/compiler/rustc_attr_parsing/src/attributes/stability.rs index b94e23477ffe..b3ebb0f4fec1 100644 --- a/compiler/rustc_attr_parsing/src/attributes/stability.rs +++ b/compiler/rustc_attr_parsing/src/attributes/stability.rs @@ -267,7 +267,7 @@ impl AttributeParser for ConstStabilityParser { /// `name = value` fn insert_value_into_option_or_error( cx: &AcceptContext<'_, '_, S>, - param: &MetaItemParser<'_>, + param: &MetaItemParser, item: &mut Option, name: Ident, ) -> Option<()> { @@ -289,7 +289,7 @@ fn insert_value_into_option_or_error( /// its stability information. pub(crate) fn parse_stability( cx: &AcceptContext<'_, '_, S>, - args: &ArgParser<'_>, + args: &ArgParser, ) -> Option<(Symbol, StabilityLevel)> { let mut feature = None; let mut since = None; @@ -365,7 +365,7 @@ pub(crate) fn parse_stability( /// attribute, and return the feature name and its stability information. pub(crate) fn parse_unstability( cx: &AcceptContext<'_, '_, S>, - args: &ArgParser<'_>, + args: &ArgParser, ) -> Option<(Symbol, StabilityLevel)> { let mut feature = None; let mut reason = None; diff --git a/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs index e0b006030758..7f25641b948e 100644 --- a/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs @@ -15,7 +15,7 @@ impl SingleAttributeParser for IgnoreParser { "https://doc.rust-lang.org/reference/attributes/testing.html#the-ignore-attribute" ); - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { Some(AttributeKind::Ignore { span: cx.attr_span, reason: match args { @@ -49,7 +49,7 @@ impl SingleAttributeParser for ShouldPanicParser { "https://doc.rust-lang.org/reference/attributes/testing.html#the-should_panic-attribute" ); - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { Some(AttributeKind::ShouldPanic { span: cx.attr_span, reason: match args { diff --git a/compiler/rustc_attr_parsing/src/attributes/traits.rs b/compiler/rustc_attr_parsing/src/attributes/traits.rs index 753892d1e997..a9b76021a989 100644 --- a/compiler/rustc_attr_parsing/src/attributes/traits.rs +++ b/compiler/rustc_attr_parsing/src/attributes/traits.rs @@ -18,7 +18,7 @@ impl SingleAttributeParser for SkipDuringMethodDispatchParser { const TEMPLATE: AttributeTemplate = template!(List: &["array, boxed_slice"]); - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let mut array = false; let mut boxed_slice = false; let Some(args) = args.list() else { diff --git a/compiler/rustc_attr_parsing/src/attributes/transparency.rs b/compiler/rustc_attr_parsing/src/attributes/transparency.rs index ea1f5549c4ec..52aa42b1085a 100644 --- a/compiler/rustc_attr_parsing/src/attributes/transparency.rs +++ b/compiler/rustc_attr_parsing/src/attributes/transparency.rs @@ -17,7 +17,7 @@ impl SingleAttributeParser for TransparencyParser { const TEMPLATE: AttributeTemplate = template!(NameValueStr: ["transparent", "semitransparent", "opaque"]); - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let Some(nv) = args.name_value() else { cx.expected_name_value(cx.attr_span, None); return None; diff --git a/compiler/rustc_attr_parsing/src/attributes/util.rs b/compiler/rustc_attr_parsing/src/attributes/util.rs index 105f7164bf3b..4e3478abbf4f 100644 --- a/compiler/rustc_attr_parsing/src/attributes/util.rs +++ b/compiler/rustc_attr_parsing/src/attributes/util.rs @@ -40,7 +40,7 @@ pub fn is_builtin_attr(attr: &impl AttributeExt) -> bool { /// `args` is the parser for the attribute arguments. pub(crate) fn parse_single_integer( cx: &mut AcceptContext<'_, '_, S>, - args: &ArgParser<'_>, + args: &ArgParser, ) -> Option { let Some(list) = args.list() else { cx.expected_list(cx.attr_span); diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index f41ea3708788..074f3b4194ae 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -75,7 +75,7 @@ use crate::attributes::traits::{ }; use crate::attributes::transparency::TransparencyParser; use crate::attributes::{AttributeParser as _, Combine, Single, WithoutArgs}; -use crate::parser::{ArgParser, PathParser}; +use crate::parser::{ArgParser, RefPathParser}; use crate::session_diagnostics::{ AttributeParseError, AttributeParseErrorReason, ParsedDescription, UnknownMetaItem, }; @@ -95,7 +95,7 @@ pub(super) struct GroupTypeInnerAccept { } type AcceptFn = - Box Fn(&mut AcceptContext<'_, 'sess, S>, &ArgParser<'a>) + Send + Sync>; + Box Fn(&mut AcceptContext<'_, 'sess, S>, &ArgParser) + Send + Sync>; type FinalizeFn = Box) -> Option>; @@ -713,7 +713,7 @@ pub(crate) struct FinalizeContext<'p, 'sess, S: Stage> { /// /// Usually, you should use normal attribute parsing logic instead, /// especially when making a *denylist* of other attributes. - pub(crate) all_attrs: &'p [PathParser<'p>], + pub(crate) all_attrs: &'p [RefPathParser<'p>], } impl<'p, 'sess: 'p, S: Stage> Deref for FinalizeContext<'p, 'sess, S> { diff --git a/compiler/rustc_attr_parsing/src/interface.rs b/compiler/rustc_attr_parsing/src/interface.rs index 45b46803419d..732f8d6e3a2a 100644 --- a/compiler/rustc_attr_parsing/src/interface.rs +++ b/compiler/rustc_attr_parsing/src/interface.rs @@ -1,4 +1,3 @@ -use std::borrow::Cow; use std::convert::identity; use rustc_ast as ast; @@ -14,7 +13,7 @@ use rustc_session::lint::BuiltinLintDiag; use rustc_span::{DUMMY_SP, Span, Symbol, sym}; use crate::context::{AcceptContext, FinalizeContext, SharedContext, Stage}; -use crate::parser::{ArgParser, PathParser}; +use crate::parser::{ArgParser, PathParser, RefPathParser}; use crate::session_diagnostics::ParsedDescription; use crate::{Early, Late, OmitDoc, ShouldEmit}; @@ -137,7 +136,7 @@ impl<'sess> AttributeParser<'sess, Early> { target_node_id: NodeId, features: Option<&'sess Features>, emit_errors: ShouldEmit, - parse_fn: fn(cx: &mut AcceptContext<'_, '_, Early>, item: &ArgParser<'_>) -> Option, + parse_fn: fn(cx: &mut AcceptContext<'_, '_, Early>, item: &ArgParser) -> Option, template: &AttributeTemplate, ) -> Option { let ast::AttrKind::Normal(normal_attr) = &attr.kind else { @@ -269,7 +268,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { mut emit_lint: impl FnMut(AttributeLint), ) -> Vec { let mut attributes = Vec::new(); - let mut attr_paths = Vec::new(); + let mut attr_paths: Vec> = Vec::new(); for attr in attrs { // If we're only looking for a single attribute, skip all the ones we don't care about. @@ -303,7 +302,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { })) } ast::AttrKind::Normal(n) => { - attr_paths.push(PathParser(Cow::Borrowed(&n.item.path))); + attr_paths.push(PathParser(&n.item.path)); let attr_path = AttrPath::from_ast(&n.item.path, lower_span); self.check_attribute_safety( diff --git a/compiler/rustc_attr_parsing/src/parser.rs b/compiler/rustc_attr_parsing/src/parser.rs index 2304fb0ca63c..09ecfaedb5ed 100644 --- a/compiler/rustc_attr_parsing/src/parser.rs +++ b/compiler/rustc_attr_parsing/src/parser.rs @@ -3,7 +3,7 @@ //! //! FIXME(jdonszelmann): delete `rustc_ast/attr/mod.rs` -use std::borrow::Cow; +use std::borrow::Borrow; use std::fmt::{Debug, Display}; use rustc_ast::token::{self, Delimiter, MetaVarKind}; @@ -26,9 +26,12 @@ use crate::session_diagnostics::{ }; #[derive(Clone, Debug)] -pub struct PathParser<'a>(pub Cow<'a, Path>); +pub struct PathParser>(pub P); -impl<'a> PathParser<'a> { +pub type OwnedPathParser = PathParser; +pub type RefPathParser<'p> = PathParser<&'p Path>; + +impl> PathParser

{ pub fn get_attribute_path(&self) -> hir::AttrPath { AttrPath { segments: self.segments().copied().collect::>().into_boxed_slice(), @@ -36,16 +39,16 @@ impl<'a> PathParser<'a> { } } - pub fn segments(&'a self) -> impl Iterator { - self.0.segments.iter().map(|seg| &seg.ident) + pub fn segments(&self) -> impl Iterator { + self.0.borrow().segments.iter().map(|seg| &seg.ident) } pub fn span(&self) -> Span { - self.0.span + self.0.borrow().span } pub fn len(&self) -> usize { - self.0.segments.len() + self.0.borrow().segments.len() } pub fn segments_is(&self, segments: &[Symbol]) -> bool { @@ -76,21 +79,21 @@ impl<'a> PathParser<'a> { } } -impl Display for PathParser<'_> { +impl> Display for PathParser

{ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", pprust::path_to_string(&self.0)) + write!(f, "{}", pprust::path_to_string(self.0.borrow())) } } #[derive(Clone, Debug)] #[must_use] -pub enum ArgParser<'a> { +pub enum ArgParser { NoArgs, - List(MetaItemListParser<'a>), + List(MetaItemListParser), NameValue(NameValueParser), } -impl<'a> ArgParser<'a> { +impl ArgParser { pub fn span(&self) -> Option { match self { Self::NoArgs => None, @@ -100,7 +103,7 @@ impl<'a> ArgParser<'a> { } pub fn from_attr_args<'sess>( - value: &'a AttrArgs, + value: &AttrArgs, parts: &[Symbol], psess: &'sess ParseSess, should_emit: ShouldEmit, @@ -144,7 +147,7 @@ impl<'a> ArgParser<'a> { /// /// - `#[allow(clippy::complexity)]`: `(clippy::complexity)` is a list /// - `#[rustfmt::skip::macros(target_macro_name)]`: `(target_macro_name)` is a list - pub fn list(&self) -> Option<&MetaItemListParser<'a>> { + pub fn list(&self) -> Option<&MetaItemListParser> { match self { Self::List(l) => Some(l), Self::NameValue(_) | Self::NoArgs => None, @@ -184,17 +187,17 @@ impl<'a> ArgParser<'a> { /// /// Choose which one you want using the provided methods. #[derive(Debug, Clone)] -pub enum MetaItemOrLitParser<'a> { - MetaItemParser(MetaItemParser<'a>), +pub enum MetaItemOrLitParser { + MetaItemParser(MetaItemParser), Lit(MetaItemLit), Err(Span, ErrorGuaranteed), } -impl<'sess> MetaItemOrLitParser<'sess> { - pub fn parse_single( +impl MetaItemOrLitParser { + pub fn parse_single<'sess>( parser: &mut Parser<'sess>, should_emit: ShouldEmit, - ) -> PResult<'sess, MetaItemOrLitParser<'static>> { + ) -> PResult<'sess, MetaItemOrLitParser> { let mut this = MetaItemListParserContext { parser, should_emit }; this.parse_meta_item_inner() } @@ -216,7 +219,7 @@ impl<'sess> MetaItemOrLitParser<'sess> { } } - pub fn meta_item(&self) -> Option<&MetaItemParser<'sess>> { + pub fn meta_item(&self) -> Option<&MetaItemParser> { match self { MetaItemOrLitParser::MetaItemParser(parser) => Some(parser), _ => None, @@ -238,12 +241,12 @@ impl<'sess> MetaItemOrLitParser<'sess> { /// /// The syntax of MetaItems can be found at #[derive(Clone)] -pub struct MetaItemParser<'a> { - path: PathParser<'a>, - args: ArgParser<'a>, +pub struct MetaItemParser { + path: OwnedPathParser, + args: ArgParser, } -impl<'a> Debug for MetaItemParser<'a> { +impl Debug for MetaItemParser { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("MetaItemParser") .field("path", &self.path) @@ -252,12 +255,12 @@ impl<'a> Debug for MetaItemParser<'a> { } } -impl<'a> MetaItemParser<'a> { +impl MetaItemParser { pub fn span(&self) -> Span { if let Some(other) = self.args.span() { - self.path.span().with_hi(other.hi()) + self.path.borrow().span().with_hi(other.hi()) } else { - self.path.span() + self.path.borrow().span() } } @@ -266,12 +269,12 @@ impl<'a> MetaItemParser<'a> { /// - `#[rustfmt::skip]`: `rustfmt::skip` is a path /// - `#[allow(clippy::complexity)]`: `clippy::complexity` is a path /// - `#[inline]`: `inline` is a single segment path - pub fn path(&self) -> &PathParser<'a> { + pub fn path(&self) -> &OwnedPathParser { &self.path } /// Gets just the args parser, without caring about the path. - pub fn args(&self) -> &ArgParser<'a> { + pub fn args(&self) -> &ArgParser { &self.args } @@ -281,7 +284,7 @@ impl<'a> MetaItemParser<'a> { /// - `#[inline]`: `inline` is a word /// - `#[rustfmt::skip]`: `rustfmt::skip` is a path, /// and not a word and should instead be parsed using [`path`](Self::path) - pub fn word_is(&self, sym: Symbol) -> Option<&ArgParser<'a>> { + pub fn word_is(&self, sym: Symbol) -> Option<&ArgParser> { self.path().word_is(sym).then(|| self.args()) } } @@ -405,7 +408,7 @@ impl<'a, 'sess> MetaItemListParserContext<'a, 'sess> { Ok(lit) } - fn parse_attr_item(&mut self) -> PResult<'sess, MetaItemParser<'static>> { + fn parse_attr_item(&mut self) -> PResult<'sess, MetaItemParser> { if let Some(MetaVarKind::Meta { has_meta_form }) = self.parser.token.is_metavar_seq() { return if has_meta_form { let attr_item = self @@ -441,10 +444,10 @@ impl<'a, 'sess> MetaItemListParserContext<'a, 'sess> { ArgParser::NoArgs }; - Ok(MetaItemParser { path: PathParser(Cow::Owned(path)), args }) + Ok(MetaItemParser { path: PathParser(path), args }) } - fn parse_meta_item_inner(&mut self) -> PResult<'sess, MetaItemOrLitParser<'static>> { + fn parse_meta_item_inner(&mut self) -> PResult<'sess, MetaItemOrLitParser> { if let Some(token_lit) = self.parser.eat_token_lit() { // If a literal token is parsed, we commit to parsing a MetaItemLit for better errors Ok(MetaItemOrLitParser::Lit(self.unsuffixed_meta_item_from_lit(token_lit)?)) @@ -531,7 +534,7 @@ impl<'a, 'sess> MetaItemListParserContext<'a, 'sess> { psess: &'sess ParseSess, span: Span, should_emit: ShouldEmit, - ) -> PResult<'sess, MetaItemListParser<'static>> { + ) -> PResult<'sess, MetaItemListParser> { let mut parser = Parser::new(psess, tokens, None); let mut this = MetaItemListParserContext { parser: &mut parser, should_emit }; @@ -554,14 +557,14 @@ impl<'a, 'sess> MetaItemListParserContext<'a, 'sess> { } #[derive(Debug, Clone)] -pub struct MetaItemListParser<'a> { - sub_parsers: ThinVec>, +pub struct MetaItemListParser { + sub_parsers: ThinVec, pub span: Span, } -impl<'a> MetaItemListParser<'a> { +impl MetaItemListParser { pub(crate) fn new<'sess>( - tokens: &'a TokenStream, + tokens: &TokenStream, span: Span, psess: &'sess ParseSess, should_emit: ShouldEmit, @@ -570,7 +573,7 @@ impl<'a> MetaItemListParser<'a> { } /// Lets you pick and choose as what you want to parse each element in the list - pub fn mixed(&self) -> impl Iterator> { + pub fn mixed(&self) -> impl Iterator { self.sub_parsers.iter() } @@ -585,7 +588,7 @@ impl<'a> MetaItemListParser<'a> { /// Returns Some if the list contains only a single element. /// /// Inside the Some is the parser to parse this single element. - pub fn single(&self) -> Option<&MetaItemOrLitParser<'a>> { + pub fn single(&self) -> Option<&MetaItemOrLitParser> { let mut iter = self.mixed(); iter.next().filter(|_| iter.next().is_none()) } From aa6db80ab20f8b3b0a8bb51217b412ec4f426b3b Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Mon, 8 Dec 2025 22:56:09 +0100 Subject: [PATCH 62/64] Remove lifetime param from parser functions --- .../src/attributes/allow_unstable.rs | 20 +++--- .../rustc_attr_parsing/src/attributes/cfg.rs | 6 +- .../src/attributes/codegen_attrs.rs | 24 +++---- .../src/attributes/debugger.rs | 8 +-- .../rustc_attr_parsing/src/attributes/doc.rs | 62 +++++++++---------- .../src/attributes/link_attrs.rs | 8 +-- .../rustc_attr_parsing/src/attributes/mod.rs | 8 +-- .../rustc_attr_parsing/src/attributes/repr.rs | 12 ++-- compiler/rustc_attr_parsing/src/interface.rs | 2 +- 9 files changed, 73 insertions(+), 77 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs index faa366a62831..79f7171cc0c8 100644 --- a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs +++ b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs @@ -17,9 +17,9 @@ impl CombineAttributeParser for AllowInternalUnstableParser { ]); const TEMPLATE: AttributeTemplate = template!(Word, List: &["feat1, feat2, ..."]); - fn extend<'c>( - cx: &'c mut AcceptContext<'_, '_, S>, - args: &'c ArgParser, + fn extend( + cx: &mut AcceptContext<'_, '_, S>, + args: &ArgParser, ) -> impl IntoIterator { parse_unstable(cx, args, >::PATH[0]) .into_iter() @@ -39,9 +39,9 @@ impl CombineAttributeParser for UnstableFeatureBoundParser { ]); const TEMPLATE: AttributeTemplate = template!(Word, List: &["feat1, feat2, ..."]); - fn extend<'c>( - cx: &'c mut AcceptContext<'_, '_, S>, - args: &'c ArgParser, + fn extend( + cx: &mut AcceptContext<'_, '_, S>, + args: &ArgParser, ) -> impl IntoIterator { if !cx.features().staged_api() { cx.emit_err(session_diagnostics::StabilityOutsideStd { span: cx.attr_span }); @@ -67,10 +67,10 @@ impl CombineAttributeParser for AllowConstFnUnstableParser { ]); const TEMPLATE: AttributeTemplate = template!(Word, List: &["feat1, feat2, ..."]); - fn extend<'c>( - cx: &'c mut AcceptContext<'_, '_, S>, - args: &'c ArgParser, - ) -> impl IntoIterator + 'c { + fn extend( + cx: &mut AcceptContext<'_, '_, S>, + args: &ArgParser, + ) -> impl IntoIterator { parse_unstable(cx, args, >::PATH[0]) } } diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg.rs b/compiler/rustc_attr_parsing/src/attributes/cfg.rs index 61c314b41b65..8c3896975201 100644 --- a/compiler/rustc_attr_parsing/src/attributes/cfg.rs +++ b/compiler/rustc_attr_parsing/src/attributes/cfg.rs @@ -35,9 +35,9 @@ const CFG_ATTR_TEMPLATE: AttributeTemplate = template!( "https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute" ); -pub fn parse_cfg<'c, S: Stage>( - cx: &'c mut AcceptContext<'_, '_, S>, - args: &'c ArgParser, +pub fn parse_cfg( + cx: &mut AcceptContext<'_, '_, S>, + args: &ArgParser, ) -> Option { let ArgParser::List(list) = args else { cx.expected_list(cx.attr_span); diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs index ce208203ec5e..7d3a7418f06c 100644 --- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs @@ -472,10 +472,10 @@ impl AttributeParser for UsedParser { } } -fn parse_tf_attribute<'c, S: Stage>( - cx: &'c mut AcceptContext<'_, '_, S>, - args: &'c ArgParser, -) -> impl IntoIterator + 'c { +fn parse_tf_attribute( + cx: &mut AcceptContext<'_, '_, S>, + args: &ArgParser, +) -> impl IntoIterator { let mut features = Vec::new(); let ArgParser::List(list) = args else { cx.expected_list(cx.attr_span); @@ -529,10 +529,10 @@ impl CombineAttributeParser for TargetFeatureParser { }; const TEMPLATE: AttributeTemplate = template!(List: &["enable = \"feat1, feat2\""]); - fn extend<'c>( - cx: &'c mut AcceptContext<'_, '_, S>, - args: &'c ArgParser, - ) -> impl IntoIterator + 'c { + fn extend( + cx: &mut AcceptContext<'_, '_, S>, + args: &ArgParser, + ) -> impl IntoIterator { parse_tf_attribute(cx, args) } @@ -567,10 +567,10 @@ impl CombineAttributeParser for ForceTargetFeatureParser { Allow(Target::Method(MethodKind::TraitImpl)), ]); - fn extend<'c>( - cx: &'c mut AcceptContext<'_, '_, S>, - args: &'c ArgParser, - ) -> impl IntoIterator + 'c { + fn extend( + cx: &mut AcceptContext<'_, '_, S>, + args: &ArgParser, + ) -> impl IntoIterator { parse_tf_attribute(cx, args) } } diff --git a/compiler/rustc_attr_parsing/src/attributes/debugger.rs b/compiler/rustc_attr_parsing/src/attributes/debugger.rs index dfb3b914e189..c88b795aab03 100644 --- a/compiler/rustc_attr_parsing/src/attributes/debugger.rs +++ b/compiler/rustc_attr_parsing/src/attributes/debugger.rs @@ -16,10 +16,10 @@ impl CombineAttributeParser for DebuggerViualizerParser { type Item = DebugVisualizer; const CONVERT: ConvertFn = |v, _| AttributeKind::DebuggerVisualizer(v); - fn extend<'c>( - cx: &'c mut AcceptContext<'_, '_, S>, - args: &'c ArgParser, - ) -> impl IntoIterator + 'c { + fn extend( + cx: &mut AcceptContext<'_, '_, S>, + args: &ArgParser, + ) -> impl IntoIterator { let Some(l) = args.list() else { cx.expected_list(args.span().unwrap_or(cx.attr_span)); return None; diff --git a/compiler/rustc_attr_parsing/src/attributes/doc.rs b/compiler/rustc_attr_parsing/src/attributes/doc.rs index 547f00d14041..b6fea37c92aa 100644 --- a/compiler/rustc_attr_parsing/src/attributes/doc.rs +++ b/compiler/rustc_attr_parsing/src/attributes/doc.rs @@ -10,7 +10,7 @@ use thin_vec::ThinVec; use super::prelude::{ALL_TARGETS, AllowedTargets}; use super::{AcceptMapping, AttributeParser}; use crate::context::{AcceptContext, FinalizeContext, Stage}; -use crate::parser::{ArgParser, MetaItemOrLitParser, MetaItemParser, PathParser}; +use crate::parser::{ArgParser, MetaItemOrLitParser, MetaItemParser, OwnedPathParser}; use crate::session_diagnostics::{ DocAliasBadChar, DocAliasEmpty, DocAliasMalformed, DocAliasStartEnd, DocAttributeNotAttribute, DocKeywordNotKeyword, @@ -43,10 +43,10 @@ fn check_attribute( false } -fn parse_keyword_and_attribute<'c, S, F>( - cx: &'c mut AcceptContext<'_, '_, S>, - path: &PathParser<'_>, - args: &ArgParser<'_>, +fn parse_keyword_and_attribute( + cx: &mut AcceptContext<'_, '_, S>, + path: &OwnedPathParser, + args: &ArgParser, attr_value: &mut Option<(Symbol, Span)>, callback: F, ) where @@ -82,10 +82,10 @@ pub(crate) struct DocParser { } impl DocParser { - fn parse_single_test_doc_attr_item<'c, S: Stage>( + fn parse_single_test_doc_attr_item( &mut self, - cx: &'c mut AcceptContext<'_, '_, S>, - mip: &'c MetaItemParser<'_>, + cx: &mut AcceptContext<'_, '_, S>, + mip: &MetaItemParser, ) { let path = mip.path(); let args = mip.args(); @@ -132,9 +132,9 @@ impl DocParser { } } - fn add_alias<'c, S: Stage>( + fn add_alias( &mut self, - cx: &'c mut AcceptContext<'_, '_, S>, + cx: &mut AcceptContext<'_, '_, S>, alias: Symbol, span: Span, ) { @@ -167,11 +167,11 @@ impl DocParser { self.attribute.aliases.insert(alias, span); } - fn parse_alias<'c, S: Stage>( + fn parse_alias( &mut self, - cx: &'c mut AcceptContext<'_, '_, S>, - path: &PathParser<'_>, - args: &ArgParser<'_>, + cx: &mut AcceptContext<'_, '_, S>, + path: &OwnedPathParser, + args: &ArgParser, ) { match args { ArgParser::NoArgs => { @@ -197,11 +197,11 @@ impl DocParser { } } - fn parse_inline<'c, S: Stage>( + fn parse_inline( &mut self, - cx: &'c mut AcceptContext<'_, '_, S>, - path: &PathParser<'_>, - args: &ArgParser<'_>, + cx: &mut AcceptContext<'_, '_, S>, + path: &OwnedPathParser, + args: &ArgParser, inline: DocInline, ) { if let Err(span) = args.no_args() { @@ -212,11 +212,7 @@ impl DocParser { self.attribute.inline.push((inline, path.span())); } - fn parse_cfg<'c, S: Stage>( - &mut self, - cx: &'c mut AcceptContext<'_, '_, S>, - args: &ArgParser<'_>, - ) { + fn parse_cfg(&mut self, cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) { // This function replaces cases like `cfg(all())` with `true`. fn simplify_cfg(cfg_entry: &mut CfgEntry) { match cfg_entry { @@ -236,11 +232,11 @@ impl DocParser { } } - fn parse_auto_cfg<'c, S: Stage>( + fn parse_auto_cfg( &mut self, - cx: &'c mut AcceptContext<'_, '_, S>, - path: &PathParser<'_>, - args: &ArgParser<'_>, + cx: &mut AcceptContext<'_, '_, S>, + path: &OwnedPathParser, + args: &ArgParser, ) { match args { ArgParser::NoArgs => { @@ -343,10 +339,10 @@ impl DocParser { } } - fn parse_single_doc_attr_item<'c, S: Stage>( + fn parse_single_doc_attr_item( &mut self, - cx: &'c mut AcceptContext<'_, '_, S>, - mip: &MetaItemParser<'_>, + cx: &mut AcceptContext<'_, '_, S>, + mip: &MetaItemParser, ) { let path = mip.path(); let args = mip.args(); @@ -506,10 +502,10 @@ impl DocParser { } } - fn accept_single_doc_attr<'c, S: Stage>( + fn accept_single_doc_attr( &mut self, - cx: &'c mut AcceptContext<'_, '_, S>, - args: &'c ArgParser<'_>, + cx: &mut AcceptContext<'_, '_, S>, + args: &ArgParser, ) { match args { ArgParser::NoArgs => { diff --git a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs index 67471e31b105..fe8f3578fe14 100644 --- a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs @@ -62,10 +62,10 @@ impl CombineAttributeParser for LinkParser { ], "https://doc.rust-lang.org/reference/items/external-blocks.html#the-link-attribute"); const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); //FIXME Still checked fully in `check_attr.rs` - fn extend<'c>( - cx: &'c mut AcceptContext<'_, '_, S>, - args: &'c ArgParser, - ) -> impl IntoIterator + 'c { + fn extend( + cx: &mut AcceptContext<'_, '_, S>, + args: &ArgParser, + ) -> impl IntoIterator { let items = match args { ArgParser::List(list) => list, // This is an edgecase added because making this a hard error would break too many crates diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs index a26159cb09e7..bd58c44214a2 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs @@ -315,10 +315,10 @@ pub(crate) trait CombineAttributeParser: 'static { const TEMPLATE: AttributeTemplate; /// Converts a single syntactical attribute to a number of elements of the semantic attribute, or [`AttributeKind`] - fn extend<'c>( - cx: &'c mut AcceptContext<'_, '_, S>, - args: &'c ArgParser, - ) -> impl IntoIterator + 'c; + fn extend( + cx: &mut AcceptContext<'_, '_, S>, + args: &ArgParser, + ) -> impl IntoIterator; } /// Use in combination with [`CombineAttributeParser`]. diff --git a/compiler/rustc_attr_parsing/src/attributes/repr.rs b/compiler/rustc_attr_parsing/src/attributes/repr.rs index c7320bf5d96f..4520e4f5dbac 100644 --- a/compiler/rustc_attr_parsing/src/attributes/repr.rs +++ b/compiler/rustc_attr_parsing/src/attributes/repr.rs @@ -26,10 +26,10 @@ impl CombineAttributeParser for ReprParser { "https://doc.rust-lang.org/reference/type-layout.html#representations" ); - fn extend<'c>( - cx: &'c mut AcceptContext<'_, '_, S>, - args: &'c ArgParser, - ) -> impl IntoIterator + 'c { + fn extend( + cx: &mut AcceptContext<'_, '_, S>, + args: &ArgParser, + ) -> impl IntoIterator { let mut reprs = Vec::new(); let Some(list) = args.list() else { @@ -275,7 +275,7 @@ impl AlignParser { const PATH: &'static [Symbol] = &[sym::rustc_align]; const TEMPLATE: AttributeTemplate = template!(List: &[""]); - fn parse<'c, S: Stage>(&mut self, cx: &'c mut AcceptContext<'_, '_, S>, args: &'c ArgParser) { + fn parse(&mut self, cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) { match args { ArgParser::NoArgs | ArgParser::NameValue(_) => { cx.expected_list(cx.attr_span); @@ -332,7 +332,7 @@ impl AlignStaticParser { const PATH: &'static [Symbol] = &[sym::rustc_align_static]; const TEMPLATE: AttributeTemplate = AlignParser::TEMPLATE; - fn parse<'c, S: Stage>(&mut self, cx: &'c mut AcceptContext<'_, '_, S>, args: &'c ArgParser) { + fn parse(&mut self, cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) { self.0.parse(cx, args) } } diff --git a/compiler/rustc_attr_parsing/src/interface.rs b/compiler/rustc_attr_parsing/src/interface.rs index 732f8d6e3a2a..91596ff0de60 100644 --- a/compiler/rustc_attr_parsing/src/interface.rs +++ b/compiler/rustc_attr_parsing/src/interface.rs @@ -342,7 +342,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { // blob // a if is_doc_attribute - && let ArgParser::NameValue(nv) = args + && let ArgParser::NameValue(nv) = &args // If not a string key/value, it should emit an error, but to make // things simpler, it's handled in `DocParser` because it's simpler to // emit an error with `AcceptContext`. From d025cdef7d9f5214dfffc4425eb1dd2228f8dc6c Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 12 Dec 2025 14:47:28 +0100 Subject: [PATCH 63/64] If there are too many suggestions for malformed attribute, do not suggest them --- .../src/session_diagnostics.rs | 24 +- .../rustc_attr_parsing/src/validate_attr.rs | 5 + tests/rustdoc-ui/bad-render-options.stderr | 144 --------- tests/rustdoc-ui/check-doc-alias-attr.stderr | 32 -- tests/rustdoc-ui/doc-cfg.stderr | 80 ----- tests/rustdoc-ui/invalid-cfg.stderr | 128 -------- tests/rustdoc-ui/lints/doc-attr.stderr | 48 --- .../ui/attributes/crate-type-delimited.stderr | 14 - tests/ui/attributes/crate-type-empty.stderr | 10 - .../attributes/crate-type-macro-call.stderr | 14 - tests/ui/attributes/doc-attr.stderr | 48 --- tests/ui/attributes/doc-test-literal.stderr | 16 - tests/ui/attributes/malformed-attrs.stderr | 62 ---- tests/ui/attributes/malformed-reprs.stderr | 11 - .../ui/deprecation/deprecation-sanity.stderr | 96 ------ tests/ui/error-codes/E0458.stderr | 15 - tests/ui/error-codes/E0565-1.stderr | 16 - tests/ui/issues/issue-43988.stderr | 22 -- tests/ui/link-native-libs/issue-43925.stderr | 15 - tests/ui/link-native-libs/issue-43926.stderr | 15 - .../link-attr-validation-early.stderr | 26 -- .../link-attr-validation-late.stderr | 279 ------------------ .../modifiers-override-4.stderr | 43 --- tests/ui/linkage-attr/linkage3.stderr | 16 - .../import-name-type-invalid-format.stderr | 15 - .../windows/import-name-type-multiple.stderr | 15 - .../import-name-type-unknown-value.stderr | 15 - .../ui/malformed/malformed-regressions.stderr | 26 -- tests/ui/repr/repr.stderr | 41 --- tests/ui/rustdoc/check-doc-alias-attr.stderr | 32 -- .../ui/sanitize-attr/invalid-sanitize.stderr | 76 ----- tests/ui/wasm/wasm-import-module.stderr | 45 --- 32 files changed, 19 insertions(+), 1425 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index 7bb55d2a6de5..2bbdb5c2590b 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -769,16 +769,20 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError<'_> { diag.note(format!("for more information, visit <{link}>")); } - diag.span_suggestions( - self.attr_span, - if self.suggestions.len() == 1 { - "must be of the form".to_string() - } else { - format!("try changing it to one of the following valid forms of the {description}") - }, - self.suggestions, - Applicability::HasPlaceholders, - ); + if self.suggestions.len() < 4 { + diag.span_suggestions( + self.attr_span, + if self.suggestions.len() == 1 { + "must be of the form".to_string() + } else { + format!( + "try changing it to one of the following valid forms of the {description}" + ) + }, + self.suggestions, + Applicability::HasPlaceholders, + ); + } diag } diff --git a/compiler/rustc_attr_parsing/src/validate_attr.rs b/compiler/rustc_attr_parsing/src/validate_attr.rs index cd28677b6a8f..e69ed0eea6b0 100644 --- a/compiler/rustc_attr_parsing/src/validate_attr.rs +++ b/compiler/rustc_attr_parsing/src/validate_attr.rs @@ -198,6 +198,11 @@ fn emit_malformed_attribute( suggestions.push(format!("#{inner}[{name} = \"{descr}\"]")); } } + // If there are too many suggestions, better remove all of them as it's just noise at this + // point. + if suggestions.len() > 3 { + suggestions.clear(); + } if should_warn(name) { psess.buffer_lint( ILL_FORMED_ATTRIBUTE_INPUT, diff --git a/tests/rustdoc-ui/bad-render-options.stderr b/tests/rustdoc-ui/bad-render-options.stderr index 296a41337f33..28d4533a6edb 100644 --- a/tests/rustdoc-ui/bad-render-options.stderr +++ b/tests/rustdoc-ui/bad-render-options.stderr @@ -5,22 +5,6 @@ LL | #![doc(html_favicon_url)] | ^^^^^^^----------------^^ | | | expected this to be of the form `html_favicon_url = "..."` - | -help: try changing it to one of the following valid forms of the attribute - | -LL - #![doc(html_favicon_url)] -LL + #![doc = "string"] - | -LL - #![doc(html_favicon_url)] -LL + #![doc(alias)] - | -LL - #![doc(html_favicon_url)] -LL + #![doc(attribute)] - | -LL - #![doc(html_favicon_url)] -LL + #![doc(auto_cfg)] - | - = and 21 other candidates error[E0539]: malformed `doc` attribute input --> $DIR/bad-render-options.rs:6:1 @@ -29,22 +13,6 @@ LL | #![doc(html_logo_url)] | ^^^^^^^-------------^^ | | | expected this to be of the form `html_logo_url = "..."` - | -help: try changing it to one of the following valid forms of the attribute - | -LL - #![doc(html_logo_url)] -LL + #![doc = "string"] - | -LL - #![doc(html_logo_url)] -LL + #![doc(alias)] - | -LL - #![doc(html_logo_url)] -LL + #![doc(attribute)] - | -LL - #![doc(html_logo_url)] -LL + #![doc(auto_cfg)] - | - = and 21 other candidates error[E0539]: malformed `doc` attribute input --> $DIR/bad-render-options.rs:9:1 @@ -53,22 +21,6 @@ LL | #![doc(html_playground_url)] | ^^^^^^^-------------------^^ | | | expected this to be of the form `html_playground_url = "..."` - | -help: try changing it to one of the following valid forms of the attribute - | -LL - #![doc(html_playground_url)] -LL + #![doc = "string"] - | -LL - #![doc(html_playground_url)] -LL + #![doc(alias)] - | -LL - #![doc(html_playground_url)] -LL + #![doc(attribute)] - | -LL - #![doc(html_playground_url)] -LL + #![doc(auto_cfg)] - | - = and 21 other candidates error[E0539]: malformed `doc` attribute input --> $DIR/bad-render-options.rs:12:1 @@ -77,22 +29,6 @@ LL | #![doc(issue_tracker_base_url)] | ^^^^^^^----------------------^^ | | | expected this to be of the form `issue_tracker_base_url = "..."` - | -help: try changing it to one of the following valid forms of the attribute - | -LL - #![doc(issue_tracker_base_url)] -LL + #![doc = "string"] - | -LL - #![doc(issue_tracker_base_url)] -LL + #![doc(alias)] - | -LL - #![doc(issue_tracker_base_url)] -LL + #![doc(attribute)] - | -LL - #![doc(issue_tracker_base_url)] -LL + #![doc(auto_cfg)] - | - = and 21 other candidates error[E0539]: malformed `doc` attribute input --> $DIR/bad-render-options.rs:15:1 @@ -101,22 +37,6 @@ LL | #![doc(html_favicon_url = 1)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^-^^ | | | expected a string literal here - | -help: try changing it to one of the following valid forms of the attribute - | -LL - #![doc(html_favicon_url = 1)] -LL + #![doc = "string"] - | -LL - #![doc(html_favicon_url = 1)] -LL + #![doc(alias)] - | -LL - #![doc(html_favicon_url = 1)] -LL + #![doc(attribute)] - | -LL - #![doc(html_favicon_url = 1)] -LL + #![doc(auto_cfg)] - | - = and 22 other candidates error[E0539]: malformed `doc` attribute input --> $DIR/bad-render-options.rs:18:1 @@ -125,22 +45,6 @@ LL | #![doc(html_logo_url = 2)] | ^^^^^^^^^^^^^^^^^^^^^^^-^^ | | | expected a string literal here - | -help: try changing it to one of the following valid forms of the attribute - | -LL - #![doc(html_logo_url = 2)] -LL + #![doc = "string"] - | -LL - #![doc(html_logo_url = 2)] -LL + #![doc(alias)] - | -LL - #![doc(html_logo_url = 2)] -LL + #![doc(attribute)] - | -LL - #![doc(html_logo_url = 2)] -LL + #![doc(auto_cfg)] - | - = and 22 other candidates error[E0539]: malformed `doc` attribute input --> $DIR/bad-render-options.rs:21:1 @@ -149,22 +53,6 @@ LL | #![doc(html_playground_url = 3)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-^^ | | | expected a string literal here - | -help: try changing it to one of the following valid forms of the attribute - | -LL - #![doc(html_playground_url = 3)] -LL + #![doc = "string"] - | -LL - #![doc(html_playground_url = 3)] -LL + #![doc(alias)] - | -LL - #![doc(html_playground_url = 3)] -LL + #![doc(attribute)] - | -LL - #![doc(html_playground_url = 3)] -LL + #![doc(auto_cfg)] - | - = and 22 other candidates error[E0539]: malformed `doc` attribute input --> $DIR/bad-render-options.rs:24:1 @@ -173,22 +61,6 @@ LL | #![doc(issue_tracker_base_url = 4)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-^^ | | | expected a string literal here - | -help: try changing it to one of the following valid forms of the attribute - | -LL - #![doc(issue_tracker_base_url = 4)] -LL + #![doc = "string"] - | -LL - #![doc(issue_tracker_base_url = 4)] -LL + #![doc(alias)] - | -LL - #![doc(issue_tracker_base_url = 4)] -LL + #![doc(attribute)] - | -LL - #![doc(issue_tracker_base_url = 4)] -LL + #![doc(auto_cfg)] - | - = and 22 other candidates error[E0565]: malformed `doc` attribute input --> $DIR/bad-render-options.rs:27:1 @@ -197,22 +69,6 @@ LL | #![doc(html_no_source = "asdf")] | ^^^^^^^^^^^^^^^^^^^^^^--------^^ | | | didn't expect any arguments here - | -help: try changing it to one of the following valid forms of the attribute - | -LL - #![doc(html_no_source = "asdf")] -LL + #![doc = "string"] - | -LL - #![doc(html_no_source = "asdf")] -LL + #![doc(alias)] - | -LL - #![doc(html_no_source = "asdf")] -LL + #![doc(attribute)] - | -LL - #![doc(html_no_source = "asdf")] -LL + #![doc(auto_cfg)] - | - = and 22 other candidates error: aborting due to 9 previous errors diff --git a/tests/rustdoc-ui/check-doc-alias-attr.stderr b/tests/rustdoc-ui/check-doc-alias-attr.stderr index 6c33f10e8785..d9e785ee0f1f 100644 --- a/tests/rustdoc-ui/check-doc-alias-attr.stderr +++ b/tests/rustdoc-ui/check-doc-alias-attr.stderr @@ -11,22 +11,6 @@ LL | #[doc(alias = 0)] | ^^^^^^^^^^^^^^-^^ | | | expected a string literal here - | -help: try changing it to one of the following valid forms of the attribute - | -LL - #[doc(alias = 0)] -LL + #[doc = "string"] - | -LL - #[doc(alias = 0)] -LL + #[doc(alias)] - | -LL - #[doc(alias = 0)] -LL + #[doc(attribute)] - | -LL - #[doc(alias = 0)] -LL + #[doc(auto_cfg)] - | - = and 22 other candidates error: '"' character isn't allowed in `#[doc(alias = "...")]` --> $DIR/check-doc-alias-attr.rs:9:15 @@ -79,22 +63,6 @@ LL | #[doc(alias(0))] | ^^^^^^^^^^^^-^^^ | | | expected a string literal here - | -help: try changing it to one of the following valid forms of the attribute - | -LL - #[doc(alias(0))] -LL + #[doc = "string"] - | -LL - #[doc(alias(0))] -LL + #[doc(alias)] - | -LL - #[doc(alias(0))] -LL + #[doc(attribute)] - | -LL - #[doc(alias(0))] -LL + #[doc(auto_cfg)] - | - = and 22 other candidates error: '"' character isn't allowed in `#[doc(alias = "...")]` --> $DIR/check-doc-alias-attr.rs:20:13 diff --git a/tests/rustdoc-ui/doc-cfg.stderr b/tests/rustdoc-ui/doc-cfg.stderr index 0efeac66554c..ce16ec31d875 100644 --- a/tests/rustdoc-ui/doc-cfg.stderr +++ b/tests/rustdoc-ui/doc-cfg.stderr @@ -5,22 +5,6 @@ LL | #[doc(cfg(), cfg(foo, bar))] | ^^^^^^^^^--^^^^^^^^^^^^^^^^^ | | | expected a single argument here - | -help: try changing it to one of the following valid forms of the attribute - | -LL - #[doc(cfg(), cfg(foo, bar))] -LL + #[doc = "string"] - | -LL - #[doc(cfg(), cfg(foo, bar))] -LL + #[doc(alias)] - | -LL - #[doc(cfg(), cfg(foo, bar))] -LL + #[doc(attribute)] - | -LL - #[doc(cfg(), cfg(foo, bar))] -LL + #[doc(auto_cfg)] - | - = and 22 other candidates error[E0805]: malformed `doc` attribute input --> $DIR/doc-cfg.rs:3:1 @@ -29,22 +13,6 @@ LL | #[doc(cfg(), cfg(foo, bar))] | ^^^^^^^^^^^^^^^^----------^^ | | | expected a single argument here - | -help: try changing it to one of the following valid forms of the attribute - | -LL - #[doc(cfg(), cfg(foo, bar))] -LL + #[doc = "string"] - | -LL - #[doc(cfg(), cfg(foo, bar))] -LL + #[doc(alias)] - | -LL - #[doc(cfg(), cfg(foo, bar))] -LL + #[doc(attribute)] - | -LL - #[doc(cfg(), cfg(foo, bar))] -LL + #[doc(auto_cfg)] - | - = and 22 other candidates error[E0805]: malformed `doc` attribute input --> $DIR/doc-cfg.rs:6:1 @@ -53,22 +21,6 @@ LL | #[doc(cfg())] | ^^^^^^^^^--^^ | | | expected a single argument here - | -help: try changing it to one of the following valid forms of the attribute - | -LL - #[doc(cfg())] -LL + #[doc = "string"] - | -LL - #[doc(cfg())] -LL + #[doc(alias)] - | -LL - #[doc(cfg())] -LL + #[doc(attribute)] - | -LL - #[doc(cfg())] -LL + #[doc(auto_cfg)] - | - = and 22 other candidates error[E0805]: malformed `doc` attribute input --> $DIR/doc-cfg.rs:7:1 @@ -77,22 +29,6 @@ LL | #[doc(cfg(foo, bar))] | ^^^^^^^^^----------^^ | | | expected a single argument here - | -help: try changing it to one of the following valid forms of the attribute - | -LL - #[doc(cfg(foo, bar))] -LL + #[doc = "string"] - | -LL - #[doc(cfg(foo, bar))] -LL + #[doc(alias)] - | -LL - #[doc(cfg(foo, bar))] -LL + #[doc(attribute)] - | -LL - #[doc(cfg(foo, bar))] -LL + #[doc(auto_cfg)] - | - = and 22 other candidates error[E0539]: malformed `doc` attribute input --> $DIR/doc-cfg.rs:8:1 @@ -101,22 +37,6 @@ LL | #[doc(auto_cfg(hide(foo::bar)))] | ^^^^^^^^^^^^^^^^^^^^--------^^^^ | | | expected a valid identifier here - | -help: try changing it to one of the following valid forms of the attribute - | -LL - #[doc(auto_cfg(hide(foo::bar)))] -LL + #[doc = "string"] - | -LL - #[doc(auto_cfg(hide(foo::bar)))] -LL + #[doc(alias)] - | -LL - #[doc(auto_cfg(hide(foo::bar)))] -LL + #[doc(attribute)] - | -LL - #[doc(auto_cfg(hide(foo::bar)))] -LL + #[doc(auto_cfg)] - | - = and 22 other candidates error: aborting due to 5 previous errors diff --git a/tests/rustdoc-ui/invalid-cfg.stderr b/tests/rustdoc-ui/invalid-cfg.stderr index 3363dbb56fb4..84f8cea54314 100644 --- a/tests/rustdoc-ui/invalid-cfg.stderr +++ b/tests/rustdoc-ui/invalid-cfg.stderr @@ -3,22 +3,6 @@ error[E0539]: malformed `doc` attribute input | LL | #[doc(cfg = "x")] | ^^^^^^^^^^^^^^^^^ expected this to be a list - | -help: try changing it to one of the following valid forms of the attribute - | -LL - #[doc(cfg = "x")] -LL + #[doc = "string"] - | -LL - #[doc(cfg = "x")] -LL + #[doc(alias)] - | -LL - #[doc(cfg = "x")] -LL + #[doc(attribute)] - | -LL - #[doc(cfg = "x")] -LL + #[doc(auto_cfg)] - | - = and 22 other candidates error[E0805]: malformed `doc` attribute input --> $DIR/invalid-cfg.rs:3:1 @@ -27,44 +11,12 @@ LL | #[doc(cfg(x, y))] | ^^^^^^^^^------^^ | | | expected a single argument here - | -help: try changing it to one of the following valid forms of the attribute - | -LL - #[doc(cfg(x, y))] -LL + #[doc = "string"] - | -LL - #[doc(cfg(x, y))] -LL + #[doc(alias)] - | -LL - #[doc(cfg(x, y))] -LL + #[doc(attribute)] - | -LL - #[doc(cfg(x, y))] -LL + #[doc(auto_cfg)] - | - = and 22 other candidates error[E0539]: malformed `doc` attribute input --> $DIR/invalid-cfg.rs:7:1 | LL | #[doc(cfg = "x")] | ^^^^^^^^^^^^^^^^^ expected this to be a list - | -help: try changing it to one of the following valid forms of the attribute - | -LL - #[doc(cfg = "x")] -LL + #[doc = "string"] - | -LL - #[doc(cfg = "x")] -LL + #[doc(alias)] - | -LL - #[doc(cfg = "x")] -LL + #[doc(attribute)] - | -LL - #[doc(cfg = "x")] -LL + #[doc(auto_cfg)] - | - = and 22 other candidates error[E0805]: malformed `doc` attribute input --> $DIR/invalid-cfg.rs:8:1 @@ -73,44 +25,12 @@ LL | #[doc(cfg(x, y))] | ^^^^^^^^^------^^ | | | expected a single argument here - | -help: try changing it to one of the following valid forms of the attribute - | -LL - #[doc(cfg(x, y))] -LL + #[doc = "string"] - | -LL - #[doc(cfg(x, y))] -LL + #[doc(alias)] - | -LL - #[doc(cfg(x, y))] -LL + #[doc(attribute)] - | -LL - #[doc(cfg(x, y))] -LL + #[doc(auto_cfg)] - | - = and 22 other candidates error[E0539]: malformed `doc` attribute input --> $DIR/invalid-cfg.rs:12:1 | LL | #[doc(cfg = "x")] | ^^^^^^^^^^^^^^^^^ expected this to be a list - | -help: try changing it to one of the following valid forms of the attribute - | -LL - #[doc(cfg = "x")] -LL + #[doc = "string"] - | -LL - #[doc(cfg = "x")] -LL + #[doc(alias)] - | -LL - #[doc(cfg = "x")] -LL + #[doc(attribute)] - | -LL - #[doc(cfg = "x")] -LL + #[doc(auto_cfg)] - | - = and 22 other candidates error[E0805]: malformed `doc` attribute input --> $DIR/invalid-cfg.rs:13:1 @@ -119,44 +39,12 @@ LL | #[doc(cfg(x, y))] | ^^^^^^^^^------^^ | | | expected a single argument here - | -help: try changing it to one of the following valid forms of the attribute - | -LL - #[doc(cfg(x, y))] -LL + #[doc = "string"] - | -LL - #[doc(cfg(x, y))] -LL + #[doc(alias)] - | -LL - #[doc(cfg(x, y))] -LL + #[doc(attribute)] - | -LL - #[doc(cfg(x, y))] -LL + #[doc(auto_cfg)] - | - = and 22 other candidates error[E0539]: malformed `doc` attribute input --> $DIR/invalid-cfg.rs:18:1 | LL | #[doc(cfg = "x")] | ^^^^^^^^^^^^^^^^^ expected this to be a list - | -help: try changing it to one of the following valid forms of the attribute - | -LL - #[doc(cfg = "x")] -LL + #[doc = "string"] - | -LL - #[doc(cfg = "x")] -LL + #[doc(alias)] - | -LL - #[doc(cfg = "x")] -LL + #[doc(attribute)] - | -LL - #[doc(cfg = "x")] -LL + #[doc(auto_cfg)] - | - = and 22 other candidates error[E0805]: malformed `doc` attribute input --> $DIR/invalid-cfg.rs:19:1 @@ -165,22 +53,6 @@ LL | #[doc(cfg(x, y))] | ^^^^^^^^^------^^ | | | expected a single argument here - | -help: try changing it to one of the following valid forms of the attribute - | -LL - #[doc(cfg(x, y))] -LL + #[doc = "string"] - | -LL - #[doc(cfg(x, y))] -LL + #[doc(alias)] - | -LL - #[doc(cfg(x, y))] -LL + #[doc(attribute)] - | -LL - #[doc(cfg(x, y))] -LL + #[doc(auto_cfg)] - | - = and 22 other candidates error: aborting due to 8 previous errors diff --git a/tests/rustdoc-ui/lints/doc-attr.stderr b/tests/rustdoc-ui/lints/doc-attr.stderr index 1201bd5c71f1..8f8c6000b364 100644 --- a/tests/rustdoc-ui/lints/doc-attr.stderr +++ b/tests/rustdoc-ui/lints/doc-attr.stderr @@ -5,22 +5,6 @@ LL | #[doc(123)] | ^^^^^^---^^ | | | expected this to be of the form `... = "..."` - | -help: try changing it to one of the following valid forms of the attribute - | -LL - #[doc(123)] -LL + #[doc = "string"] - | -LL - #[doc(123)] -LL + #[doc(alias)] - | -LL - #[doc(123)] -LL + #[doc(attribute)] - | -LL - #[doc(123)] -LL + #[doc(auto_cfg)] - | - = and 22 other candidates error[E0539]: malformed `doc` attribute input --> $DIR/doc-attr.rs:5:1 @@ -29,22 +13,6 @@ LL | #[doc("hello", "bar")] | ^^^^^^-------^^^^^^^^^ | | | expected this to be of the form `... = "..."` - | -help: try changing it to one of the following valid forms of the attribute - | -LL - #[doc("hello", "bar")] -LL + #[doc = "string"] - | -LL - #[doc("hello", "bar")] -LL + #[doc(alias)] - | -LL - #[doc("hello", "bar")] -LL + #[doc(attribute)] - | -LL - #[doc("hello", "bar")] -LL + #[doc(auto_cfg)] - | - = and 22 other candidates error[E0539]: malformed `doc` attribute input --> $DIR/doc-attr.rs:5:1 @@ -53,22 +21,6 @@ LL | #[doc("hello", "bar")] | ^^^^^^^^^^^^^^^-----^^ | | | expected this to be of the form `... = "..."` - | -help: try changing it to one of the following valid forms of the attribute - | -LL - #[doc("hello", "bar")] -LL + #[doc = "string"] - | -LL - #[doc("hello", "bar")] -LL + #[doc(alias)] - | -LL - #[doc("hello", "bar")] -LL + #[doc(attribute)] - | -LL - #[doc("hello", "bar")] -LL + #[doc(auto_cfg)] - | - = and 22 other candidates error: aborting due to 3 previous errors diff --git a/tests/ui/attributes/crate-type-delimited.stderr b/tests/ui/attributes/crate-type-delimited.stderr index 7f080f748386..23234efe169f 100644 --- a/tests/ui/attributes/crate-type-delimited.stderr +++ b/tests/ui/attributes/crate-type-delimited.stderr @@ -5,21 +5,7 @@ LL | #![crate_type(lib)] | ^^^^^^^^^^^^^^^^^^^ | = note: for more information, visit -help: the following are the possible correct uses | -LL - #![crate_type(lib)] -LL + #![crate_type = "bin"] - | -LL - #![crate_type(lib)] -LL + #![crate_type = "cdylib"] - | -LL - #![crate_type(lib)] -LL + #![crate_type = "dylib"] - | -LL - #![crate_type(lib)] -LL + #![crate_type = "lib"] - | - = and 4 other candidates error: aborting due to 1 previous error diff --git a/tests/ui/attributes/crate-type-empty.stderr b/tests/ui/attributes/crate-type-empty.stderr index f50bb33d6bb0..c1d474d9f17f 100644 --- a/tests/ui/attributes/crate-type-empty.stderr +++ b/tests/ui/attributes/crate-type-empty.stderr @@ -5,17 +5,7 @@ LL | #![crate_type] | ^^^^^^^^^^^^^^ | = note: for more information, visit -help: the following are the possible correct uses | -LL | #![crate_type = "bin"] - | +++++++ -LL | #![crate_type = "cdylib"] - | ++++++++++ -LL | #![crate_type = "dylib"] - | +++++++++ -LL | #![crate_type = "lib"] - | +++++++ - = and 4 other candidates error: aborting due to 1 previous error diff --git a/tests/ui/attributes/crate-type-macro-call.stderr b/tests/ui/attributes/crate-type-macro-call.stderr index 97938f7af24e..cd17b324041b 100644 --- a/tests/ui/attributes/crate-type-macro-call.stderr +++ b/tests/ui/attributes/crate-type-macro-call.stderr @@ -5,21 +5,7 @@ LL | #![crate_type = foo!()] | ^^^^^^^^^^^^^^^^^^^^^^^ | = note: for more information, visit -help: the following are the possible correct uses | -LL - #![crate_type = foo!()] -LL + #![crate_type = "bin"] - | -LL - #![crate_type = foo!()] -LL + #![crate_type = "cdylib"] - | -LL - #![crate_type = foo!()] -LL + #![crate_type = "dylib"] - | -LL - #![crate_type = foo!()] -LL + #![crate_type = "lib"] - | - = and 4 other candidates error: aborting due to 1 previous error diff --git a/tests/ui/attributes/doc-attr.stderr b/tests/ui/attributes/doc-attr.stderr index 9234c1a0719b..dfc0e8ad5b6f 100644 --- a/tests/ui/attributes/doc-attr.stderr +++ b/tests/ui/attributes/doc-attr.stderr @@ -5,22 +5,6 @@ LL | #[doc(123)] | ^^^^^^---^^ | | | expected this to be of the form `... = "..."` - | -help: try changing it to one of the following valid forms of the attribute - | -LL - #[doc(123)] -LL + #[doc = "string"] - | -LL - #[doc(123)] -LL + #[doc(alias)] - | -LL - #[doc(123)] -LL + #[doc(attribute)] - | -LL - #[doc(123)] -LL + #[doc(auto_cfg)] - | - = and 22 other candidates error[E0539]: malformed `doc` attribute input --> $DIR/doc-attr.rs:11:1 @@ -29,22 +13,6 @@ LL | #[doc("hello", "bar")] | ^^^^^^-------^^^^^^^^^ | | | expected this to be of the form `... = "..."` - | -help: try changing it to one of the following valid forms of the attribute - | -LL - #[doc("hello", "bar")] -LL + #[doc = "string"] - | -LL - #[doc("hello", "bar")] -LL + #[doc(alias)] - | -LL - #[doc("hello", "bar")] -LL + #[doc(attribute)] - | -LL - #[doc("hello", "bar")] -LL + #[doc(auto_cfg)] - | - = and 22 other candidates error[E0539]: malformed `doc` attribute input --> $DIR/doc-attr.rs:11:1 @@ -53,22 +21,6 @@ LL | #[doc("hello", "bar")] | ^^^^^^^^^^^^^^^-----^^ | | | expected this to be of the form `... = "..."` - | -help: try changing it to one of the following valid forms of the attribute - | -LL - #[doc("hello", "bar")] -LL + #[doc = "string"] - | -LL - #[doc("hello", "bar")] -LL + #[doc(alias)] - | -LL - #[doc("hello", "bar")] -LL + #[doc(attribute)] - | -LL - #[doc("hello", "bar")] -LL + #[doc(auto_cfg)] - | - = and 22 other candidates error: unknown `doc` attribute `as_ptr` --> $DIR/doc-attr.rs:5:7 diff --git a/tests/ui/attributes/doc-test-literal.stderr b/tests/ui/attributes/doc-test-literal.stderr index 3ffbdcbb9fee..2d70d5d206f0 100644 --- a/tests/ui/attributes/doc-test-literal.stderr +++ b/tests/ui/attributes/doc-test-literal.stderr @@ -5,22 +5,6 @@ LL | #![doc(test(""))] | ^^^^^^^^^^^^--^^^ | | | didn't expect a literal here - | -help: try changing it to one of the following valid forms of the attribute - | -LL - #![doc(test(""))] -LL + #![doc = "string"] - | -LL - #![doc(test(""))] -LL + #![doc(alias)] - | -LL - #![doc(test(""))] -LL + #![doc(attribute)] - | -LL - #![doc(test(""))] -LL + #![doc(auto_cfg)] - | - = and 22 other candidates error: aborting due to 1 previous error diff --git a/tests/ui/attributes/malformed-attrs.stderr b/tests/ui/attributes/malformed-attrs.stderr index a6bd62fa1214..e1ebe4ac9eab 100644 --- a/tests/ui/attributes/malformed-attrs.stderr +++ b/tests/ui/attributes/malformed-attrs.stderr @@ -240,22 +240,6 @@ LL | #[deprecated = 5] | ^^^^^^^^^^^^^^^-^ | | | expected a string literal here - | -help: try changing it to one of the following valid forms of the attribute - | -LL - #[deprecated = 5] -LL + #[deprecated = "reason"] - | -LL - #[deprecated = 5] -LL + #[deprecated(note = "reason")] - | -LL - #[deprecated = 5] -LL + #[deprecated(since = "version")] - | -LL - #[deprecated = 5] -LL + #[deprecated(since = "version", note = "reason")] - | - = and 1 other candidate error[E0539]: malformed `rustc_macro_transparency` attribute input --> $DIR/malformed-attrs.rs:44:1 @@ -287,17 +271,6 @@ LL | #[repr] | ^^^^^^^ expected this to be a list | = note: for more information, visit -help: try changing it to one of the following valid forms of the attribute - | -LL | #[repr()] - | ++++++++++++++++ -LL | #[repr(C)] - | +++ -LL | #[repr(Rust)] - | ++++++ -LL | #[repr(align(...))] - | ++++++++++++ - = and 2 other candidates error[E0565]: malformed `rustc_as_ptr` attribute input --> $DIR/malformed-attrs.rs:50:1 @@ -437,17 +410,6 @@ LL | #[link] | ^^^^^^^ expected this to be a list | = note: for more information, visit -help: try changing it to one of the following valid forms of the attribute - | -LL | #[link(name = "...")] - | ++++++++++++++ -LL | #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] - | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -LL | #[link(name = "...", kind = "dylib|static|...")] - | +++++++++++++++++++++++++++++++++++++++++ -LL | #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] - | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - = and 1 other candidate error[E0539]: malformed `link_name` attribute input --> $DIR/malformed-attrs.rs:88:1 @@ -483,18 +445,6 @@ error[E0539]: malformed `sanitize` attribute input | LL | #[sanitize] | ^^^^^^^^^^^ expected this to be a list - | -help: try changing it to one of the following valid forms of the attribute - | -LL | #[sanitize(address = "on|off")] - | ++++++++++++++++++++ -LL | #[sanitize(cfi = "on|off")] - | ++++++++++++++++ -LL | #[sanitize(hwaddress = "on|off")] - | ++++++++++++++++++++++ -LL | #[sanitize(kcfi = "on|off")] - | +++++++++++++++++ - = and 6 other candidates error[E0565]: malformed `no_implicit_prelude` attribute input --> $DIR/malformed-attrs.rs:101:1 @@ -634,18 +584,6 @@ error[E0539]: malformed `linkage` attribute input | LL | #[linkage] | ^^^^^^^^^^ expected this to be of the form `linkage = "..."` - | -help: try changing it to one of the following valid forms of the attribute - | -LL | #[linkage = "available_externally"] - | ++++++++++++++++++++++++ -LL | #[linkage = "common"] - | ++++++++++ -LL | #[linkage = "extern_weak"] - | +++++++++++++++ -LL | #[linkage = "external"] - | ++++++++++++ - = and 5 other candidates error[E0539]: malformed `debugger_visualizer` attribute input --> $DIR/malformed-attrs.rs:194:1 diff --git a/tests/ui/attributes/malformed-reprs.stderr b/tests/ui/attributes/malformed-reprs.stderr index 3a788999542b..504ba91aac5f 100644 --- a/tests/ui/attributes/malformed-reprs.stderr +++ b/tests/ui/attributes/malformed-reprs.stderr @@ -5,17 +5,6 @@ LL | #![repr] | ^^^^^^^^ expected this to be a list | = note: for more information, visit -help: try changing it to one of the following valid forms of the attribute - | -LL | #![repr()] - | ++++++++++++++++ -LL | #![repr(C)] - | +++ -LL | #![repr(Rust)] - | ++++++ -LL | #![repr(align(...))] - | ++++++++++++ - = and 2 other candidates error[E0589]: invalid `repr(align)` attribute: not a power of two --> $DIR/malformed-reprs.rs:9:14 diff --git a/tests/ui/deprecation/deprecation-sanity.stderr b/tests/ui/deprecation/deprecation-sanity.stderr index 48d08b18f8bd..a96d4a0bdea8 100644 --- a/tests/ui/deprecation/deprecation-sanity.stderr +++ b/tests/ui/deprecation/deprecation-sanity.stderr @@ -11,22 +11,6 @@ LL | #[deprecated(since = "a", note)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^----^^ | | | expected this to be of the form `note = "..."` - | -help: try changing it to one of the following valid forms of the attribute - | -LL - #[deprecated(since = "a", note)] -LL + #[deprecated = "reason"] - | -LL - #[deprecated(since = "a", note)] -LL + #[deprecated(note = "reason")] - | -LL - #[deprecated(since = "a", note)] -LL + #[deprecated(since = "version")] - | -LL - #[deprecated(since = "a", note)] -LL + #[deprecated(since = "version", note = "reason")] - | - = and 1 other candidate error[E0539]: malformed `deprecated` attribute input --> $DIR/deprecation-sanity.rs:12:5 @@ -35,22 +19,6 @@ LL | #[deprecated(since, note = "a")] | ^^^^^^^^^^^^^-----^^^^^^^^^^^^^^ | | | expected this to be of the form `since = "..."` - | -help: try changing it to one of the following valid forms of the attribute - | -LL - #[deprecated(since, note = "a")] -LL + #[deprecated = "reason"] - | -LL - #[deprecated(since, note = "a")] -LL + #[deprecated(note = "reason")] - | -LL - #[deprecated(since, note = "a")] -LL + #[deprecated(since = "version")] - | -LL - #[deprecated(since, note = "a")] -LL + #[deprecated(since = "version", note = "reason")] - | - = and 1 other candidate error[E0539]: malformed `deprecated` attribute input --> $DIR/deprecation-sanity.rs:15:5 @@ -59,22 +27,6 @@ LL | #[deprecated(since = "a", note(b))] | ^^^^^^^^^^^^^^^^^^^^^^^^^^-------^^ | | | expected this to be of the form `note = "..."` - | -help: try changing it to one of the following valid forms of the attribute - | -LL - #[deprecated(since = "a", note(b))] -LL + #[deprecated = "reason"] - | -LL - #[deprecated(since = "a", note(b))] -LL + #[deprecated(note = "reason")] - | -LL - #[deprecated(since = "a", note(b))] -LL + #[deprecated(since = "version")] - | -LL - #[deprecated(since = "a", note(b))] -LL + #[deprecated(since = "version", note = "reason")] - | - = and 1 other candidate error[E0539]: malformed `deprecated` attribute input --> $DIR/deprecation-sanity.rs:18:5 @@ -83,22 +35,6 @@ LL | #[deprecated(since(b), note = "a")] | ^^^^^^^^^^^^^--------^^^^^^^^^^^^^^ | | | expected this to be of the form `since = "..."` - | -help: try changing it to one of the following valid forms of the attribute - | -LL - #[deprecated(since(b), note = "a")] -LL + #[deprecated = "reason"] - | -LL - #[deprecated(since(b), note = "a")] -LL + #[deprecated(note = "reason")] - | -LL - #[deprecated(since(b), note = "a")] -LL + #[deprecated(since = "version")] - | -LL - #[deprecated(since(b), note = "a")] -LL + #[deprecated(since = "version", note = "reason")] - | - = and 1 other candidate error[E0539]: malformed `deprecated` attribute input --> $DIR/deprecation-sanity.rs:21:5 @@ -117,22 +53,6 @@ LL | #[deprecated("test")] | ^^^^^^^^^^^^^------^^ | | | didn't expect a literal here - | -help: try changing it to one of the following valid forms of the attribute - | -LL - #[deprecated("test")] -LL + #[deprecated = "reason"] - | -LL - #[deprecated("test")] -LL + #[deprecated(note = "reason")] - | -LL - #[deprecated("test")] -LL + #[deprecated(since = "version")] - | -LL - #[deprecated("test")] -LL + #[deprecated(since = "version", note = "reason")] - | - = and 1 other candidate error: multiple `deprecated` attributes --> $DIR/deprecation-sanity.rs:29:1 @@ -153,22 +73,6 @@ LL | #[deprecated(since = "a", since = "b", note = "c")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^-----------^^^^^^^^^^^^^^ | | | found `since` used as a key more than once - | -help: try changing it to one of the following valid forms of the attribute - | -LL - #[deprecated(since = "a", since = "b", note = "c")] -LL + #[deprecated = "reason"] - | -LL - #[deprecated(since = "a", since = "b", note = "c")] -LL + #[deprecated(note = "reason")] - | -LL - #[deprecated(since = "a", since = "b", note = "c")] -LL + #[deprecated(since = "version")] - | -LL - #[deprecated(since = "a", since = "b", note = "c")] -LL + #[deprecated(since = "version", note = "reason")] - | - = and 1 other candidate error: `#[deprecated]` attribute cannot be used on trait impl blocks --> $DIR/deprecation-sanity.rs:37:1 diff --git a/tests/ui/error-codes/E0458.stderr b/tests/ui/error-codes/E0458.stderr index 524765ea12a1..e56c9473d287 100644 --- a/tests/ui/error-codes/E0458.stderr +++ b/tests/ui/error-codes/E0458.stderr @@ -7,21 +7,6 @@ LL | #[link(kind = "wonderful_unicorn")] extern "C" {} | valid arguments are "static", "dylib", "framework", "raw-dylib" or "link-arg" | = note: for more information, visit -help: try changing it to one of the following valid forms of the attribute - | -LL - #[link(kind = "wonderful_unicorn")] extern "C" {} -LL + #[link(name = "...")] extern "C" {} - | -LL - #[link(kind = "wonderful_unicorn")] extern "C" {} -LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] extern "C" {} - | -LL - #[link(kind = "wonderful_unicorn")] extern "C" {} -LL + #[link(name = "...", kind = "dylib|static|...")] extern "C" {} - | -LL - #[link(kind = "wonderful_unicorn")] extern "C" {} -LL + #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] extern "C" {} - | - = and 1 other candidate error[E0459]: `#[link]` attribute requires a `name = "string"` argument --> $DIR/E0458.rs:1:1 diff --git a/tests/ui/error-codes/E0565-1.stderr b/tests/ui/error-codes/E0565-1.stderr index 52daf2a62fcd..d1aff042e8fb 100644 --- a/tests/ui/error-codes/E0565-1.stderr +++ b/tests/ui/error-codes/E0565-1.stderr @@ -5,22 +5,6 @@ LL | #[deprecated("since")] | ^^^^^^^^^^^^^-------^^ | | | didn't expect a literal here - | -help: try changing it to one of the following valid forms of the attribute - | -LL - #[deprecated("since")] -LL + #[deprecated = "reason"] - | -LL - #[deprecated("since")] -LL + #[deprecated(note = "reason")] - | -LL - #[deprecated("since")] -LL + #[deprecated(since = "version")] - | -LL - #[deprecated("since")] -LL + #[deprecated(since = "version", note = "reason")] - | - = and 1 other candidate error: aborting due to 1 previous error diff --git a/tests/ui/issues/issue-43988.stderr b/tests/ui/issues/issue-43988.stderr index 0219eeb693e7..d393255e0ee1 100644 --- a/tests/ui/issues/issue-43988.stderr +++ b/tests/ui/issues/issue-43988.stderr @@ -60,17 +60,6 @@ LL | #[repr] | ^^^^^^^ expected this to be a list | = note: for more information, visit -help: try changing it to one of the following valid forms of the attribute - | -LL | #[repr()] - | ++++++++++++++++ -LL | #[repr(C)] - | +++ -LL | #[repr(Rust)] - | ++++++ -LL | #[repr(align(...))] - | ++++++++++++ - = and 2 other candidates error[E0539]: malformed `inline` attribute input --> $DIR/issue-43988.rs:31:5 @@ -108,17 +97,6 @@ LL | let _z = #[repr] 1; | ^^^^^^^ expected this to be a list | = note: for more information, visit -help: try changing it to one of the following valid forms of the attribute - | -LL | let _z = #[repr()] 1; - | ++++++++++++++++ -LL | let _z = #[repr(C)] 1; - | +++ -LL | let _z = #[repr(Rust)] 1; - | ++++++ -LL | let _z = #[repr(align(...))] 1; - | ++++++++++++ - = and 2 other candidates error: aborting due to 9 previous errors diff --git a/tests/ui/link-native-libs/issue-43925.stderr b/tests/ui/link-native-libs/issue-43925.stderr index 68a020546c14..fdc644ed6469 100644 --- a/tests/ui/link-native-libs/issue-43925.stderr +++ b/tests/ui/link-native-libs/issue-43925.stderr @@ -16,21 +16,6 @@ LL | #[link(name = "foo", cfg("rlib"))] | expected a valid identifier here | = note: for more information, visit -help: try changing it to one of the following valid forms of the attribute - | -LL - #[link(name = "foo", cfg("rlib"))] -LL + #[link(name = "...")] - | -LL - #[link(name = "foo", cfg("rlib"))] -LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] - | -LL - #[link(name = "foo", cfg("rlib"))] -LL + #[link(name = "...", kind = "dylib|static|...")] - | -LL - #[link(name = "foo", cfg("rlib"))] -LL + #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] - | - = and 1 other candidate error: aborting due to 2 previous errors diff --git a/tests/ui/link-native-libs/issue-43926.stderr b/tests/ui/link-native-libs/issue-43926.stderr index 9e3ec21cc945..f7b85788a2a3 100644 --- a/tests/ui/link-native-libs/issue-43926.stderr +++ b/tests/ui/link-native-libs/issue-43926.stderr @@ -7,21 +7,6 @@ LL | #[link(name = "foo", cfg())] | expected a single argument here | = note: for more information, visit -help: try changing it to one of the following valid forms of the attribute - | -LL - #[link(name = "foo", cfg())] -LL + #[link(name = "...")] - | -LL - #[link(name = "foo", cfg())] -LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] - | -LL - #[link(name = "foo", cfg())] -LL + #[link(name = "...", kind = "dylib|static|...")] - | -LL - #[link(name = "foo", cfg())] -LL + #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] - | - = and 1 other candidate error: aborting due to 1 previous error diff --git a/tests/ui/link-native-libs/link-attr-validation-early.stderr b/tests/ui/link-native-libs/link-attr-validation-early.stderr index e4799b1a1618..101df0371b54 100644 --- a/tests/ui/link-native-libs/link-attr-validation-early.stderr +++ b/tests/ui/link-native-libs/link-attr-validation-early.stderr @@ -5,17 +5,6 @@ LL | #[link] | ^^^^^^^ expected this to be a list | = note: for more information, visit -help: try changing it to one of the following valid forms of the attribute - | -LL | #[link(name = "...")] - | ++++++++++++++ -LL | #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] - | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -LL | #[link(name = "...", kind = "dylib|static|...")] - | +++++++++++++++++++++++++++++++++++++++++ -LL | #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] - | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - = and 1 other candidate error[E0539]: malformed `link` attribute input --> $DIR/link-attr-validation-early.rs:3:1 @@ -24,21 +13,6 @@ LL | #[link = "foo"] | ^^^^^^^^^^^^^^^ expected this to be a list | = note: for more information, visit -help: try changing it to one of the following valid forms of the attribute - | -LL - #[link = "foo"] -LL + #[link(name = "...")] - | -LL - #[link = "foo"] -LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] - | -LL - #[link = "foo"] -LL + #[link(name = "...", kind = "dylib|static|...")] - | -LL - #[link = "foo"] -LL + #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] - | - = and 1 other candidate error: aborting due to 2 previous errors diff --git a/tests/ui/link-native-libs/link-attr-validation-late.stderr b/tests/ui/link-native-libs/link-attr-validation-late.stderr index 106b7cebc99f..a5f654ca0aeb 100644 --- a/tests/ui/link-native-libs/link-attr-validation-late.stderr +++ b/tests/ui/link-native-libs/link-attr-validation-late.stderr @@ -7,21 +7,6 @@ LL | #[link(name = "...", "literal")] | didn't expect a literal here | = note: for more information, visit -help: try changing it to one of the following valid forms of the attribute - | -LL - #[link(name = "...", "literal")] -LL + #[link(name = "...")] - | -LL - #[link(name = "...", "literal")] -LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] - | -LL - #[link(name = "...", "literal")] -LL + #[link(name = "...", kind = "dylib|static|...")] - | -LL - #[link(name = "...", "literal")] -LL + #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] - | - = and 1 other candidate error[E0539]: malformed `link` attribute input --> $DIR/link-attr-validation-late.rs:5:1 @@ -32,21 +17,6 @@ LL | #[link(name = "...", unknown)] | valid arguments are "name", "kind", "modifiers", "cfg", "wasm_import_module" or "import_name_type" | = note: for more information, visit -help: try changing it to one of the following valid forms of the attribute - | -LL - #[link(name = "...", unknown)] -LL + #[link(name = "...")] - | -LL - #[link(name = "...", unknown)] -LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] - | -LL - #[link(name = "...", unknown)] -LL + #[link(name = "...", kind = "dylib|static|...")] - | -LL - #[link(name = "...", unknown)] -LL + #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] - | - = and 1 other candidate error[E0538]: malformed `link` attribute input --> $DIR/link-attr-validation-late.rs:9:1 @@ -57,21 +27,6 @@ LL | #[link(name = "foo", name = "bar")] | found `name` used as a key more than once | = note: for more information, visit -help: try changing it to one of the following valid forms of the attribute - | -LL - #[link(name = "foo", name = "bar")] -LL + #[link(name = "...")] - | -LL - #[link(name = "foo", name = "bar")] -LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] - | -LL - #[link(name = "foo", name = "bar")] -LL + #[link(name = "...", kind = "dylib|static|...")] - | -LL - #[link(name = "foo", name = "bar")] -LL + #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] - | - = and 1 other candidate error[E0538]: malformed `link` attribute input --> $DIR/link-attr-validation-late.rs:10:1 @@ -82,21 +37,6 @@ LL | #[link(name = "...", kind = "dylib", kind = "bar")] | found `kind` used as a key more than once | = note: for more information, visit -help: try changing it to one of the following valid forms of the attribute - | -LL - #[link(name = "...", kind = "dylib", kind = "bar")] -LL + #[link(name = "...")] - | -LL - #[link(name = "...", kind = "dylib", kind = "bar")] -LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] - | -LL - #[link(name = "...", kind = "dylib", kind = "bar")] -LL + #[link(name = "...", kind = "dylib|static|...")] - | -LL - #[link(name = "...", kind = "dylib", kind = "bar")] -LL + #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] - | - = and 1 other candidate error[E0538]: malformed `link` attribute input --> $DIR/link-attr-validation-late.rs:11:1 @@ -107,21 +47,6 @@ LL | #[link(name = "...", modifiers = "+verbatim", modifiers = "bar")] | found `modifiers` used as a key more than once | = note: for more information, visit -help: try changing it to one of the following valid forms of the attribute - | -LL - #[link(name = "...", modifiers = "+verbatim", modifiers = "bar")] -LL + #[link(name = "...")] - | -LL - #[link(name = "...", modifiers = "+verbatim", modifiers = "bar")] -LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] - | -LL - #[link(name = "...", modifiers = "+verbatim", modifiers = "bar")] -LL + #[link(name = "...", kind = "dylib|static|...")] - | -LL - #[link(name = "...", modifiers = "+verbatim", modifiers = "bar")] -LL + #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] - | - = and 1 other candidate error[E0538]: malformed `link` attribute input --> $DIR/link-attr-validation-late.rs:12:1 @@ -132,21 +57,6 @@ LL | #[link(name = "...", cfg(false), cfg(false))] | found `cfg` used as a key more than once | = note: for more information, visit -help: try changing it to one of the following valid forms of the attribute - | -LL - #[link(name = "...", cfg(false), cfg(false))] -LL + #[link(name = "...")] - | -LL - #[link(name = "...", cfg(false), cfg(false))] -LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] - | -LL - #[link(name = "...", cfg(false), cfg(false))] -LL + #[link(name = "...", kind = "dylib|static|...")] - | -LL - #[link(name = "...", cfg(false), cfg(false))] -LL + #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] - | - = and 1 other candidate error[E0538]: malformed `link` attribute input --> $DIR/link-attr-validation-late.rs:13:1 @@ -157,21 +67,6 @@ LL | #[link(wasm_import_module = "foo", wasm_import_module = "bar")] | found `wasm_import_module` used as a key more than once | = note: for more information, visit -help: try changing it to one of the following valid forms of the attribute - | -LL - #[link(wasm_import_module = "foo", wasm_import_module = "bar")] -LL + #[link(name = "...")] - | -LL - #[link(wasm_import_module = "foo", wasm_import_module = "bar")] -LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] - | -LL - #[link(wasm_import_module = "foo", wasm_import_module = "bar")] -LL + #[link(name = "...", kind = "dylib|static|...")] - | -LL - #[link(wasm_import_module = "foo", wasm_import_module = "bar")] -LL + #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] - | - = and 1 other candidate error[E0539]: malformed `link` attribute input --> $DIR/link-attr-validation-late.rs:17:1 @@ -182,17 +77,6 @@ LL | #[link(name)] | expected this to be of the form `name = "..."` | = note: for more information, visit -help: try changing it to one of the following valid forms of the attribute - | -LL | #[link(name = "...")] - | +++++++ -LL | #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] - | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -LL | #[link(name = "...", kind = "dylib|static|...")] - | ++++++++++++++++++++++++++++++++++ -LL | #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] - | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - = and 1 other candidate error[E0539]: malformed `link` attribute input --> $DIR/link-attr-validation-late.rs:18:1 @@ -203,21 +87,6 @@ LL | #[link(name())] | expected this to be of the form `name = "..."` | = note: for more information, visit -help: try changing it to one of the following valid forms of the attribute - | -LL - #[link(name())] -LL + #[link(name = "...")] - | -LL - #[link(name())] -LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] - | -LL - #[link(name())] -LL + #[link(name = "...", kind = "dylib|static|...")] - | -LL - #[link(name())] -LL + #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] - | - = and 1 other candidate error[E0539]: malformed `link` attribute input --> $DIR/link-attr-validation-late.rs:19:1 @@ -228,19 +97,6 @@ LL | #[link(name = "...", kind)] | expected this to be of the form `kind = "..."` | = note: for more information, visit -help: try changing it to one of the following valid forms of the attribute - | -LL - #[link(name = "...", kind)] -LL + #[link(name = "...")] - | -LL - #[link(name = "...", kind)] -LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] - | -LL | #[link(name = "...", kind = "dylib|static|...")] - | ++++++++++++++++++++ -LL | #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] - | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - = and 1 other candidate error[E0539]: malformed `link` attribute input --> $DIR/link-attr-validation-late.rs:20:1 @@ -251,21 +107,6 @@ LL | #[link(name = "...", kind())] | expected this to be of the form `kind = "..."` | = note: for more information, visit -help: try changing it to one of the following valid forms of the attribute - | -LL - #[link(name = "...", kind())] -LL + #[link(name = "...")] - | -LL - #[link(name = "...", kind())] -LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] - | -LL - #[link(name = "...", kind())] -LL + #[link(name = "...", kind = "dylib|static|...")] - | -LL - #[link(name = "...", kind())] -LL + #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] - | - = and 1 other candidate error[E0539]: malformed `link` attribute input --> $DIR/link-attr-validation-late.rs:21:1 @@ -276,21 +117,6 @@ LL | #[link(name = "...", modifiers)] | expected this to be of the form `modifiers = "..."` | = note: for more information, visit -help: try changing it to one of the following valid forms of the attribute - | -LL - #[link(name = "...", modifiers)] -LL + #[link(name = "...")] - | -LL - #[link(name = "...", modifiers)] -LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] - | -LL - #[link(name = "...", modifiers)] -LL + #[link(name = "...", kind = "dylib|static|...")] - | -LL - #[link(name = "...", modifiers)] -LL + #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] - | - = and 1 other candidate error[E0539]: malformed `link` attribute input --> $DIR/link-attr-validation-late.rs:22:1 @@ -301,21 +127,6 @@ LL | #[link(name = "...", modifiers())] | expected this to be of the form `modifiers = "..."` | = note: for more information, visit -help: try changing it to one of the following valid forms of the attribute - | -LL - #[link(name = "...", modifiers())] -LL + #[link(name = "...")] - | -LL - #[link(name = "...", modifiers())] -LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] - | -LL - #[link(name = "...", modifiers())] -LL + #[link(name = "...", kind = "dylib|static|...")] - | -LL - #[link(name = "...", modifiers())] -LL + #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] - | - = and 1 other candidate error[E0539]: malformed `link` attribute input --> $DIR/link-attr-validation-late.rs:23:1 @@ -326,21 +137,6 @@ LL | #[link(name = "...", cfg)] | expected this to be a list | = note: for more information, visit -help: try changing it to one of the following valid forms of the attribute - | -LL - #[link(name = "...", cfg)] -LL + #[link(name = "...")] - | -LL - #[link(name = "...", cfg)] -LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] - | -LL - #[link(name = "...", cfg)] -LL + #[link(name = "...", kind = "dylib|static|...")] - | -LL - #[link(name = "...", cfg)] -LL + #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] - | - = and 1 other candidate error[E0539]: malformed `link` attribute input --> $DIR/link-attr-validation-late.rs:24:1 @@ -351,21 +147,6 @@ LL | #[link(name = "...", cfg = "literal")] | expected this to be a list | = note: for more information, visit -help: try changing it to one of the following valid forms of the attribute - | -LL - #[link(name = "...", cfg = "literal")] -LL + #[link(name = "...")] - | -LL - #[link(name = "...", cfg = "literal")] -LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] - | -LL - #[link(name = "...", cfg = "literal")] -LL + #[link(name = "...", kind = "dylib|static|...")] - | -LL - #[link(name = "...", cfg = "literal")] -LL + #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] - | - = and 1 other candidate error[E0539]: malformed `link` attribute input --> $DIR/link-attr-validation-late.rs:25:1 @@ -376,21 +157,6 @@ LL | #[link(name = "...", cfg("literal"))] | expected a valid identifier here | = note: for more information, visit -help: try changing it to one of the following valid forms of the attribute - | -LL - #[link(name = "...", cfg("literal"))] -LL + #[link(name = "...")] - | -LL - #[link(name = "...", cfg("literal"))] -LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] - | -LL - #[link(name = "...", cfg("literal"))] -LL + #[link(name = "...", kind = "dylib|static|...")] - | -LL - #[link(name = "...", cfg("literal"))] -LL + #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] - | - = and 1 other candidate error[E0539]: malformed `link` attribute input --> $DIR/link-attr-validation-late.rs:26:1 @@ -401,21 +167,6 @@ LL | #[link(name = "...", wasm_import_module)] | expected this to be of the form `wasm_import_module = "..."` | = note: for more information, visit -help: try changing it to one of the following valid forms of the attribute - | -LL - #[link(name = "...", wasm_import_module)] -LL + #[link(name = "...")] - | -LL - #[link(name = "...", wasm_import_module)] -LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] - | -LL - #[link(name = "...", wasm_import_module)] -LL + #[link(name = "...", kind = "dylib|static|...")] - | -LL - #[link(name = "...", wasm_import_module)] -LL + #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] - | - = and 1 other candidate error[E0539]: malformed `link` attribute input --> $DIR/link-attr-validation-late.rs:27:1 @@ -426,21 +177,6 @@ LL | #[link(name = "...", wasm_import_module())] | expected this to be of the form `wasm_import_module = "..."` | = note: for more information, visit -help: try changing it to one of the following valid forms of the attribute - | -LL - #[link(name = "...", wasm_import_module())] -LL + #[link(name = "...")] - | -LL - #[link(name = "...", wasm_import_module())] -LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] - | -LL - #[link(name = "...", wasm_import_module())] -LL + #[link(name = "...", kind = "dylib|static|...")] - | -LL - #[link(name = "...", wasm_import_module())] -LL + #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] - | - = and 1 other candidate error: invalid linking modifier syntax, expected '+' or '-' prefix before one of: bundle, verbatim, whole-archive, as-needed --> $DIR/link-attr-validation-late.rs:31:34 @@ -463,21 +199,6 @@ LL | #[link(name = "...", modifiers = "+unknown")] | valid arguments are "bundle", "verbatim", "whole-archive" or "as-needed" | = note: for more information, visit -help: try changing it to one of the following valid forms of the attribute - | -LL - #[link(name = "...", modifiers = "+unknown")] -LL + #[link(name = "...")] - | -LL - #[link(name = "...", modifiers = "+unknown")] -LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] - | -LL - #[link(name = "...", modifiers = "+unknown")] -LL + #[link(name = "...", kind = "dylib|static|...")] - | -LL - #[link(name = "...", modifiers = "+unknown")] -LL + #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] - | - = and 1 other candidate error: multiple `verbatim` modifiers in a single `modifiers` argument --> $DIR/link-attr-validation-late.rs:34:34 diff --git a/tests/ui/link-native-libs/modifiers-override-4.stderr b/tests/ui/link-native-libs/modifiers-override-4.stderr index 317e89cb39cc..12b0d89c79a7 100644 --- a/tests/ui/link-native-libs/modifiers-override-4.stderr +++ b/tests/ui/link-native-libs/modifiers-override-4.stderr @@ -12,49 +12,6 @@ LL | | )] | |__^ | = note: for more information, visit -help: try changing it to one of the following valid forms of the attribute - | -LL - #[link( -LL - -LL - name = "bar", -LL - kind = "static", -LL - modifiers = "+whole-archive,-whole-archive", -LL - -LL - modifiers = "+bundle" -LL - )] -LL + #[link(name = "...")] - | -LL - #[link( -LL - -LL - name = "bar", -LL - kind = "static", -LL - modifiers = "+whole-archive,-whole-archive", -LL - -LL - modifiers = "+bundle" -LL - )] -LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] - | -LL - #[link( -LL - -LL - name = "bar", -LL - kind = "static", -LL - modifiers = "+whole-archive,-whole-archive", -LL - -LL - modifiers = "+bundle" -LL - )] -LL + #[link(name = "...", kind = "dylib|static|...")] - | -LL - #[link( -LL - -LL - name = "bar", -LL - kind = "static", -LL - modifiers = "+whole-archive,-whole-archive", -LL - -LL - modifiers = "+bundle" -LL - )] -LL + #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] - | - = and 1 other candidate error: multiple `whole-archive` modifiers in a single `modifiers` argument --> $DIR/modifiers-override-4.rs:6:17 diff --git a/tests/ui/linkage-attr/linkage3.stderr b/tests/ui/linkage-attr/linkage3.stderr index f1215f09aeaf..564090e9538f 100644 --- a/tests/ui/linkage-attr/linkage3.stderr +++ b/tests/ui/linkage-attr/linkage3.stderr @@ -5,22 +5,6 @@ LL | #[linkage = "foo"] | ^^^^^^^^^^^^-----^ | | | valid arguments are `available_externally`, `common`, `extern_weak`, `external`, `internal`, `linkonce`, `linkonce_odr`, `weak` or `weak_odr` - | -help: try changing it to one of the following valid forms of the attribute - | -LL - #[linkage = "foo"] -LL + #[linkage = "available_externally"] - | -LL - #[linkage = "foo"] -LL + #[linkage = "common"] - | -LL - #[linkage = "foo"] -LL + #[linkage = "extern_weak"] - | -LL - #[linkage = "foo"] -LL + #[linkage = "external"] - | - = and 5 other candidates error: aborting due to 1 previous error diff --git a/tests/ui/linkage-attr/raw-dylib/windows/import-name-type-invalid-format.stderr b/tests/ui/linkage-attr/raw-dylib/windows/import-name-type-invalid-format.stderr index 6b54f3b247d1..86a53a030f50 100644 --- a/tests/ui/linkage-attr/raw-dylib/windows/import-name-type-invalid-format.stderr +++ b/tests/ui/linkage-attr/raw-dylib/windows/import-name-type-invalid-format.stderr @@ -7,21 +7,6 @@ LL | #[link(name = "foo", kind = "raw-dylib", import_name_type = 6)] | expected this to be of the form `import_name_type = "..."` | = note: for more information, visit -help: try changing it to one of the following valid forms of the attribute - | -LL - #[link(name = "foo", kind = "raw-dylib", import_name_type = 6)] -LL + #[link(name = "...")] - | -LL - #[link(name = "foo", kind = "raw-dylib", import_name_type = 6)] -LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] - | -LL - #[link(name = "foo", kind = "raw-dylib", import_name_type = 6)] -LL + #[link(name = "...", kind = "dylib|static|...")] - | -LL - #[link(name = "foo", kind = "raw-dylib", import_name_type = 6)] -LL + #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] - | - = and 1 other candidate error: aborting due to 1 previous error diff --git a/tests/ui/linkage-attr/raw-dylib/windows/import-name-type-multiple.stderr b/tests/ui/linkage-attr/raw-dylib/windows/import-name-type-multiple.stderr index 35ddb2a7e3d3..ef909ad7278b 100644 --- a/tests/ui/linkage-attr/raw-dylib/windows/import-name-type-multiple.stderr +++ b/tests/ui/linkage-attr/raw-dylib/windows/import-name-type-multiple.stderr @@ -7,21 +7,6 @@ LL | #[link(name = "foo", kind = "raw-dylib", import_name_type = "decorated", im | found `import_name_type` used as a key more than once | = note: for more information, visit -help: try changing it to one of the following valid forms of the attribute - | -LL - #[link(name = "foo", kind = "raw-dylib", import_name_type = "decorated", import_name_type = "decorated")] -LL + #[link(name = "...")] - | -LL - #[link(name = "foo", kind = "raw-dylib", import_name_type = "decorated", import_name_type = "decorated")] -LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] - | -LL - #[link(name = "foo", kind = "raw-dylib", import_name_type = "decorated", import_name_type = "decorated")] -LL + #[link(name = "...", kind = "dylib|static|...")] - | -LL - #[link(name = "foo", kind = "raw-dylib", import_name_type = "decorated", import_name_type = "decorated")] -LL + #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] - | - = and 1 other candidate error: aborting due to 1 previous error diff --git a/tests/ui/linkage-attr/raw-dylib/windows/import-name-type-unknown-value.stderr b/tests/ui/linkage-attr/raw-dylib/windows/import-name-type-unknown-value.stderr index b0099675dd23..577ec8e7764c 100644 --- a/tests/ui/linkage-attr/raw-dylib/windows/import-name-type-unknown-value.stderr +++ b/tests/ui/linkage-attr/raw-dylib/windows/import-name-type-unknown-value.stderr @@ -7,21 +7,6 @@ LL | #[link(name = "foo", kind = "raw-dylib", import_name_type = "unknown")] | valid arguments are "decorated", "noprefix" or "undecorated" | = note: for more information, visit -help: try changing it to one of the following valid forms of the attribute - | -LL - #[link(name = "foo", kind = "raw-dylib", import_name_type = "unknown")] -LL + #[link(name = "...")] - | -LL - #[link(name = "foo", kind = "raw-dylib", import_name_type = "unknown")] -LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] - | -LL - #[link(name = "foo", kind = "raw-dylib", import_name_type = "unknown")] -LL + #[link(name = "...", kind = "dylib|static|...")] - | -LL - #[link(name = "foo", kind = "raw-dylib", import_name_type = "unknown")] -LL + #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] - | - = and 1 other candidate error: aborting due to 1 previous error diff --git a/tests/ui/malformed/malformed-regressions.stderr b/tests/ui/malformed/malformed-regressions.stderr index 29734fd84e6b..f46afda1e477 100644 --- a/tests/ui/malformed/malformed-regressions.stderr +++ b/tests/ui/malformed/malformed-regressions.stderr @@ -5,17 +5,6 @@ LL | #[link] | ^^^^^^^ expected this to be a list | = note: for more information, visit -help: try changing it to one of the following valid forms of the attribute - | -LL | #[link(name = "...")] - | ++++++++++++++ -LL | #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] - | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -LL | #[link(name = "...", kind = "dylib|static|...")] - | +++++++++++++++++++++++++++++++++++++++++ -LL | #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] - | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - = and 1 other candidate error[E0539]: malformed `link` attribute input --> $DIR/malformed-regressions.rs:10:1 @@ -24,21 +13,6 @@ LL | #[link = ""] | ^^^^^^^^^^^^ expected this to be a list | = note: for more information, visit -help: try changing it to one of the following valid forms of the attribute - | -LL - #[link = ""] -LL + #[link(name = "...")] - | -LL - #[link = ""] -LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] - | -LL - #[link = ""] -LL + #[link(name = "...", kind = "dylib|static|...")] - | -LL - #[link = ""] -LL + #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] - | - = and 1 other candidate warning: attribute should be applied to an `extern` block with non-Rust ABI --> $DIR/malformed-regressions.rs:7:1 diff --git a/tests/ui/repr/repr.stderr b/tests/ui/repr/repr.stderr index d4faea125176..e8168f8f9a58 100644 --- a/tests/ui/repr/repr.stderr +++ b/tests/ui/repr/repr.stderr @@ -5,17 +5,6 @@ LL | #[repr] | ^^^^^^^ expected this to be a list | = note: for more information, visit -help: try changing it to one of the following valid forms of the attribute - | -LL | #[repr()] - | ++++++++++++++++ -LL | #[repr(C)] - | +++ -LL | #[repr(Rust)] - | ++++++ -LL | #[repr(align(...))] - | ++++++++++++ - = and 2 other candidates error[E0539]: malformed `repr` attribute input --> $DIR/repr.rs:4:1 @@ -24,21 +13,6 @@ LL | #[repr = "B"] | ^^^^^^^^^^^^^ expected this to be a list | = note: for more information, visit -help: try changing it to one of the following valid forms of the attribute - | -LL - #[repr = "B"] -LL + #[repr()] - | -LL - #[repr = "B"] -LL + #[repr(C)] - | -LL - #[repr = "B"] -LL + #[repr(Rust)] - | -LL - #[repr = "B"] -LL + #[repr(align(...))] - | - = and 2 other candidates error[E0539]: malformed `repr` attribute input --> $DIR/repr.rs:7:1 @@ -47,21 +21,6 @@ LL | #[repr = "C"] | ^^^^^^^^^^^^^ expected this to be a list | = note: for more information, visit -help: try changing it to one of the following valid forms of the attribute - | -LL - #[repr = "C"] -LL + #[repr()] - | -LL - #[repr = "C"] -LL + #[repr(C)] - | -LL - #[repr = "C"] -LL + #[repr(Rust)] - | -LL - #[repr = "C"] -LL + #[repr(align(...))] - | - = and 2 other candidates error: aborting due to 3 previous errors diff --git a/tests/ui/rustdoc/check-doc-alias-attr.stderr b/tests/ui/rustdoc/check-doc-alias-attr.stderr index 6c33f10e8785..d9e785ee0f1f 100644 --- a/tests/ui/rustdoc/check-doc-alias-attr.stderr +++ b/tests/ui/rustdoc/check-doc-alias-attr.stderr @@ -11,22 +11,6 @@ LL | #[doc(alias = 0)] | ^^^^^^^^^^^^^^-^^ | | | expected a string literal here - | -help: try changing it to one of the following valid forms of the attribute - | -LL - #[doc(alias = 0)] -LL + #[doc = "string"] - | -LL - #[doc(alias = 0)] -LL + #[doc(alias)] - | -LL - #[doc(alias = 0)] -LL + #[doc(attribute)] - | -LL - #[doc(alias = 0)] -LL + #[doc(auto_cfg)] - | - = and 22 other candidates error: '"' character isn't allowed in `#[doc(alias = "...")]` --> $DIR/check-doc-alias-attr.rs:9:15 @@ -79,22 +63,6 @@ LL | #[doc(alias(0))] | ^^^^^^^^^^^^-^^^ | | | expected a string literal here - | -help: try changing it to one of the following valid forms of the attribute - | -LL - #[doc(alias(0))] -LL + #[doc = "string"] - | -LL - #[doc(alias(0))] -LL + #[doc(alias)] - | -LL - #[doc(alias(0))] -LL + #[doc(attribute)] - | -LL - #[doc(alias(0))] -LL + #[doc(auto_cfg)] - | - = and 22 other candidates error: '"' character isn't allowed in `#[doc(alias = "...")]` --> $DIR/check-doc-alias-attr.rs:20:13 diff --git a/tests/ui/sanitize-attr/invalid-sanitize.stderr b/tests/ui/sanitize-attr/invalid-sanitize.stderr index 9c1a6e5c4528..2a3497678bdc 100644 --- a/tests/ui/sanitize-attr/invalid-sanitize.stderr +++ b/tests/ui/sanitize-attr/invalid-sanitize.stderr @@ -5,22 +5,6 @@ LL | #[sanitize(brontosaurus = "off")] | ^^^^^^^^^^^------------^^^^^^^^^^ | | | valid arguments are "address", "cfi", "kcfi", "memory", "memtag", "shadow_call_stack", "thread", "hwaddress" or "realtime" - | -help: try changing it to one of the following valid forms of the attribute - | -LL - #[sanitize(brontosaurus = "off")] -LL + #[sanitize(address = "on|off")] - | -LL - #[sanitize(brontosaurus = "off")] -LL + #[sanitize(cfi = "on|off")] - | -LL - #[sanitize(brontosaurus = "off")] -LL + #[sanitize(hwaddress = "on|off")] - | -LL - #[sanitize(brontosaurus = "off")] -LL + #[sanitize(kcfi = "on|off")] - | - = and 6 other candidates error: multiple `sanitize` attributes --> $DIR/invalid-sanitize.rs:7:1 @@ -53,62 +37,18 @@ LL | #[sanitize(address = "bogus")] | ^^^^^^^^^^^^^^^^^^^^^-------^^ | | | valid arguments are "on" or "off" - | -help: try changing it to one of the following valid forms of the attribute - | -LL - #[sanitize(address = "bogus")] -LL + #[sanitize(address = "on|off")] - | -LL - #[sanitize(address = "bogus")] -LL + #[sanitize(cfi = "on|off")] - | -LL - #[sanitize(address = "bogus")] -LL + #[sanitize(hwaddress = "on|off")] - | -LL - #[sanitize(address = "bogus")] -LL + #[sanitize(kcfi = "on|off")] - | - = and 6 other candidates error[E0539]: malformed `sanitize` attribute input --> $DIR/invalid-sanitize.rs:18:1 | LL | #[sanitize = "off"] | ^^^^^^^^^^^^^^^^^^^ expected this to be a list - | -help: try changing it to one of the following valid forms of the attribute - | -LL - #[sanitize = "off"] -LL + #[sanitize(address = "on|off")] - | -LL - #[sanitize = "off"] -LL + #[sanitize(cfi = "on|off")] - | -LL - #[sanitize = "off"] -LL + #[sanitize(hwaddress = "on|off")] - | -LL - #[sanitize = "off"] -LL + #[sanitize(kcfi = "on|off")] - | - = and 6 other candidates error[E0539]: malformed `sanitize` attribute input --> $DIR/invalid-sanitize.rs:21:1 | LL | #[sanitize] | ^^^^^^^^^^^ expected this to be a list - | -help: try changing it to one of the following valid forms of the attribute - | -LL | #[sanitize(address = "on|off")] - | ++++++++++++++++++++ -LL | #[sanitize(cfi = "on|off")] - | ++++++++++++++++ -LL | #[sanitize(hwaddress = "on|off")] - | ++++++++++++++++++++++ -LL | #[sanitize(kcfi = "on|off")] - | +++++++++++++++++ - = and 6 other candidates error[E0539]: malformed `sanitize` attribute input --> $DIR/invalid-sanitize.rs:24:1 @@ -117,22 +57,6 @@ LL | #[sanitize(realtime = "on")] | ^^^^^^^^^^^^^^^^^^^^^^----^^ | | | valid arguments are "nonblocking", "blocking" or "caller" - | -help: try changing it to one of the following valid forms of the attribute - | -LL - #[sanitize(realtime = "on")] -LL + #[sanitize(address = "on|off")] - | -LL - #[sanitize(realtime = "on")] -LL + #[sanitize(cfi = "on|off")] - | -LL - #[sanitize(realtime = "on")] -LL + #[sanitize(hwaddress = "on|off")] - | -LL - #[sanitize(realtime = "on")] -LL + #[sanitize(kcfi = "on|off")] - | - = and 6 other candidates warning: the async executor can run blocking code, without realtime sanitizer catching it --> $DIR/invalid-sanitize.rs:27:1 diff --git a/tests/ui/wasm/wasm-import-module.stderr b/tests/ui/wasm/wasm-import-module.stderr index f5ea449839bb..6171f04f862c 100644 --- a/tests/ui/wasm/wasm-import-module.stderr +++ b/tests/ui/wasm/wasm-import-module.stderr @@ -7,21 +7,6 @@ LL | #[link(name = "...", wasm_import_module)] | expected this to be of the form `wasm_import_module = "..."` | = note: for more information, visit -help: try changing it to one of the following valid forms of the attribute - | -LL - #[link(name = "...", wasm_import_module)] -LL + #[link(name = "...")] - | -LL - #[link(name = "...", wasm_import_module)] -LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] - | -LL - #[link(name = "...", wasm_import_module)] -LL + #[link(name = "...", kind = "dylib|static|...")] - | -LL - #[link(name = "...", wasm_import_module)] -LL + #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] - | - = and 1 other candidate error[E0539]: malformed `link` attribute input --> $DIR/wasm-import-module.rs:6:1 @@ -32,21 +17,6 @@ LL | #[link(name = "...", wasm_import_module(x))] | expected this to be of the form `wasm_import_module = "..."` | = note: for more information, visit -help: try changing it to one of the following valid forms of the attribute - | -LL - #[link(name = "...", wasm_import_module(x))] -LL + #[link(name = "...")] - | -LL - #[link(name = "...", wasm_import_module(x))] -LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] - | -LL - #[link(name = "...", wasm_import_module(x))] -LL + #[link(name = "...", kind = "dylib|static|...")] - | -LL - #[link(name = "...", wasm_import_module(x))] -LL + #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] - | - = and 1 other candidate error[E0539]: malformed `link` attribute input --> $DIR/wasm-import-module.rs:9:1 @@ -57,21 +27,6 @@ LL | #[link(name = "...", wasm_import_module())] | expected this to be of the form `wasm_import_module = "..."` | = note: for more information, visit -help: try changing it to one of the following valid forms of the attribute - | -LL - #[link(name = "...", wasm_import_module())] -LL + #[link(name = "...")] - | -LL - #[link(name = "...", wasm_import_module())] -LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] - | -LL - #[link(name = "...", wasm_import_module())] -LL + #[link(name = "...", kind = "dylib|static|...")] - | -LL - #[link(name = "...", wasm_import_module())] -LL + #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] - | - = and 1 other candidate error: `wasm_import_module` is incompatible with other arguments in `#[link]` attributes --> $DIR/wasm-import-module.rs:12:8 From acc3a0e2da38051690d45e8f2ad620baf4600015 Mon Sep 17 00:00:00 2001 From: Boxy Uwu Date: Wed, 19 Nov 2025 20:01:24 +0000 Subject: [PATCH 64/64] Syntactically distinguish anon const const args --- compiler/rustc_ast/src/ast.rs | 43 +++++---- compiler/rustc_ast/src/visit.rs | 1 + compiler/rustc_ast_lowering/src/expr.rs | 6 +- compiler/rustc_ast_lowering/src/lib.rs | 80 ++++++++++++++-- compiler/rustc_ast_passes/src/feature_gate.rs | 1 + compiler/rustc_builtin_macros/src/autodiff.rs | 10 +- .../rustc_builtin_macros/src/pattern_type.rs | 18 +++- compiler/rustc_expand/src/build.rs | 5 +- compiler/rustc_parse/src/parser/asm.rs | 4 +- .../rustc_parse/src/parser/diagnostics.rs | 71 ++++++-------- compiler/rustc_parse/src/parser/expr.rs | 28 +++++- compiler/rustc_parse/src/parser/item.rs | 13 ++- compiler/rustc_parse/src/parser/mod.rs | 26 +++++- compiler/rustc_parse/src/parser/path.rs | 88 ++++++++++++++++-- compiler/rustc_parse/src/parser/ty.rs | 25 +++-- compiler/rustc_resolve/src/late.rs | 17 ++-- .../assoc-const-eq-ambiguity.rs | 2 +- .../assoc-const-eq-ambiguity.stderr | 8 +- .../assoc-const-eq-bound-var-in-ty-not-wf.rs | 2 +- ...soc-const-eq-bound-var-in-ty-not-wf.stderr | 12 +-- .../assoc-const-eq-bound-var-in-ty.rs | 2 +- .../assoc-const-eq-esc-bound-var-in-ty.rs | 2 +- .../assoc-const-eq-esc-bound-var-in-ty.stderr | 2 +- .../assoc-const-eq-param-in-ty.rs | 34 +++---- .../assoc-const-eq-param-in-ty.stderr | 63 +++++++------ tests/ui/associated-consts/assoc-const.rs | 4 +- tests/ui/associated-consts/issue-110933.rs | 2 +- .../const-projection-err.rs | 4 - ...gce.stderr => const-projection-err.stderr} | 8 +- .../duplicate-bound-err.rs | 4 +- .../duplicate-bound-err.stderr | 46 +++++----- .../associated-type-bounds/duplicate-bound.rs | 4 +- .../unconstrained_impl_param.rs | 2 +- .../unconstrained_impl_param.stderr | 6 +- .../mgca/explicit_anon_consts.rs | 70 ++++++++++++++ .../mgca/explicit_anon_consts.stderr | 92 +++++++++++++++++++ .../explicit_anon_consts_literals_hack.rs | 22 +++++ .../mgca/multi_braced_direct_const_args.rs | 25 +++++ .../mgca/type_const-not-constparamty.rs | 8 +- .../mgca/type_const-not-constparamty.stderr | 4 +- .../mgca/type_const-on-generic-expr.rs | 10 +- .../mgca/type_const-on-generic-expr.stderr | 30 +++--- .../unbraced_const_block_const_arg_gated.rs | 42 +++++++++ ...nbraced_const_block_const_arg_gated.stderr | 73 +++++++++++++++ .../mgca/using-fnptr-as-type_const.rs | 2 +- .../assoc-const-no-infer-ice-115806.rs | 4 +- .../assoc-const-no-infer-ice-115806.stderr | 4 +- .../associated-const-equality.rs | 2 +- 48 files changed, 779 insertions(+), 252 deletions(-) rename tests/ui/associated-type-bounds/{const-projection-err.gce.stderr => const-projection-err.stderr} (66%) create mode 100644 tests/ui/const-generics/mgca/explicit_anon_consts.rs create mode 100644 tests/ui/const-generics/mgca/explicit_anon_consts.stderr create mode 100644 tests/ui/const-generics/mgca/explicit_anon_consts_literals_hack.rs create mode 100644 tests/ui/const-generics/mgca/multi_braced_direct_const_args.rs create mode 100644 tests/ui/const-generics/mgca/unbraced_const_block_const_arg_gated.rs create mode 100644 tests/ui/const-generics/mgca/unbraced_const_block_const_arg_gated.stderr diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index e348cc1ab281..a2975935ef55 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -141,16 +141,11 @@ impl Path { /// Check if this path is potentially a trivial const arg, i.e., one that can _potentially_ /// be represented without an anon const in the HIR. /// - /// If `allow_mgca_arg` is true (as should be the case in most situations when - /// `#![feature(min_generic_const_args)]` is enabled), then this always returns true - /// because all paths are valid. - /// - /// Otherwise, it returns true iff the path has exactly one segment, and it has no generic args + /// Returns true iff the path has exactly one segment, and it has no generic args /// (i.e., it is _potentially_ a const parameter). #[tracing::instrument(level = "debug", ret)] - pub fn is_potential_trivial_const_arg(&self, allow_mgca_arg: bool) -> bool { - allow_mgca_arg - || self.segments.len() == 1 && self.segments.iter().all(|seg| seg.args.is_none()) + pub fn is_potential_trivial_const_arg(&self) -> bool { + self.segments.len() == 1 && self.segments.iter().all(|seg| seg.args.is_none()) } } @@ -1385,6 +1380,15 @@ pub enum UnsafeSource { UserProvided, } +/// Track whether under `feature(min_generic_const_args)` this anon const +/// was explicitly disambiguated as an anon const or not through the use of +/// `const { ... }` syntax. +#[derive(Clone, PartialEq, Encodable, Decodable, Debug, Copy, Walkable)] +pub enum MgcaDisambiguation { + AnonConst, + Direct, +} + /// A constant (expression) that's not an item or associated item, /// but needs its own `DefId` for type-checking, const-eval, etc. /// These are usually found nested inside types (e.g., array lengths) @@ -1394,6 +1398,7 @@ pub enum UnsafeSource { pub struct AnonConst { pub id: NodeId, pub value: Box, + pub mgca_disambiguation: MgcaDisambiguation, } /// An expression. @@ -1412,26 +1417,20 @@ impl Expr { /// /// This will unwrap at most one block level (curly braces). After that, if the expression /// is a path, it mostly dispatches to [`Path::is_potential_trivial_const_arg`]. - /// See there for more info about `allow_mgca_arg`. /// - /// The only additional thing to note is that when `allow_mgca_arg` is false, this function - /// will only allow paths with no qself, before dispatching to the `Path` function of - /// the same name. + /// This function will only allow paths with no qself, before dispatching to the `Path` + /// function of the same name. /// /// Does not ensure that the path resolves to a const param/item, the caller should check this. /// This also does not consider macros, so it's only correct after macro-expansion. - pub fn is_potential_trivial_const_arg(&self, allow_mgca_arg: bool) -> bool { + pub fn is_potential_trivial_const_arg(&self) -> bool { let this = self.maybe_unwrap_block(); - if allow_mgca_arg { - matches!(this.kind, ExprKind::Path(..)) + if let ExprKind::Path(None, path) = &this.kind + && path.is_potential_trivial_const_arg() + { + true } else { - if let ExprKind::Path(None, path) = &this.kind - && path.is_potential_trivial_const_arg(allow_mgca_arg) - { - true - } else { - false - } + false } } diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 7a0424d39575..49bff8fdd65d 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -415,6 +415,7 @@ macro_rules! common_visitor_and_walkers { UnsafeBinderCastKind, BinOpKind, BlockCheckMode, + MgcaDisambiguation, BorrowKind, BoundAsyncness, BoundConstness, diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 7230e1c42474..c8a311443a58 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -489,7 +489,11 @@ impl<'hir> LoweringContext<'_, 'hir> { arg }; - let anon_const = AnonConst { id: node_id, value: const_value }; + let anon_const = AnonConst { + id: node_id, + value: const_value, + mgca_disambiguation: MgcaDisambiguation::AnonConst, + }; generic_args.push(AngleBracketedArg::Arg(GenericArg::Const(anon_const))); } else { real_args.push(arg); diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index c20bbcca44f7..47a8f744820f 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1219,7 +1219,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { .and_then(|partial_res| partial_res.full_res()) { if !res.matches_ns(Namespace::TypeNS) - && path.is_potential_trivial_const_arg(false) + && path.is_potential_trivial_const_arg() { debug!( "lower_generic_arg: Lowering type argument as const argument: {:?}", @@ -2287,11 +2287,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ) -> &'hir hir::ConstArg<'hir> { let tcx = self.tcx; - let ct_kind = if path - .is_potential_trivial_const_arg(tcx.features().min_generic_const_args()) - && (tcx.features().min_generic_const_args() - || matches!(res, Res::Def(DefKind::ConstParam, _))) - { + let is_trivial_path = path.is_potential_trivial_const_arg() + && matches!(res, Res::Def(DefKind::ConstParam, _)); + let ct_kind = if is_trivial_path || tcx.features().min_generic_const_args() { let qpath = self.lower_qpath( ty_id, &None, @@ -2370,6 +2368,53 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } } + #[instrument(level = "debug", skip(self), ret)] + fn lower_expr_to_const_arg_direct(&mut self, expr: &Expr) -> hir::ConstArg<'hir> { + let overly_complex_const = |this: &mut Self| { + let e = this.dcx().struct_span_err( + expr.span, + "complex const arguments must be placed inside of a `const` block", + ); + + ConstArg { hir_id: this.next_id(), kind: hir::ConstArgKind::Error(expr.span, e.emit()) } + }; + + match &expr.kind { + ExprKind::Path(qself, path) => { + let qpath = self.lower_qpath( + expr.id, + qself, + path, + ParamMode::Explicit, + AllowReturnTypeNotation::No, + // FIXME(mgca): update for `fn foo() -> Bar>` support + ImplTraitContext::Disallowed(ImplTraitPosition::Path), + None, + ); + + ConstArg { hir_id: self.next_id(), kind: hir::ConstArgKind::Path(qpath) } + } + ExprKind::Underscore => ConstArg { + hir_id: self.lower_node_id(expr.id), + kind: hir::ConstArgKind::Infer(expr.span, ()), + }, + ExprKind::Block(block, _) => { + if let [stmt] = block.stmts.as_slice() + && let StmtKind::Expr(expr) = &stmt.kind + && matches!( + expr.kind, + ExprKind::Block(..) | ExprKind::Path(..) | ExprKind::Struct(..) + ) + { + return self.lower_expr_to_const_arg_direct(expr); + } + + overly_complex_const(self) + } + _ => overly_complex_const(self), + } + } + /// See [`hir::ConstArg`] for when to use this function vs /// [`Self::lower_anon_const_to_anon_const`]. fn lower_anon_const_to_const_arg(&mut self, anon: &AnonConst) -> &'hir hir::ConstArg<'hir> { @@ -2379,6 +2424,22 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { #[instrument(level = "debug", skip(self))] fn lower_anon_const_to_const_arg_direct(&mut self, anon: &AnonConst) -> hir::ConstArg<'hir> { let tcx = self.tcx; + + // We cannot change parsing depending on feature gates available, + // we can only require feature gates to be active as a delayed check. + // Thus we just parse anon consts generally and make the real decision + // making in ast lowering. + // FIXME(min_generic_const_args): revisit once stable + if tcx.features().min_generic_const_args() { + return match anon.mgca_disambiguation { + MgcaDisambiguation::AnonConst => { + let lowered_anon = self.lower_anon_const_to_anon_const(anon); + ConstArg { hir_id: self.next_id(), kind: hir::ConstArgKind::Anon(lowered_anon) } + } + MgcaDisambiguation::Direct => self.lower_expr_to_const_arg_direct(&anon.value), + }; + } + // Unwrap a block, so that e.g. `{ P }` is recognised as a parameter. Const arguments // currently have to be wrapped in curly brackets, so it's necessary to special-case. let expr = if let ExprKind::Block(block, _) = &anon.value.kind @@ -2390,12 +2451,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } else { &anon.value }; + let maybe_res = self.resolver.get_partial_res(expr.id).and_then(|partial_res| partial_res.full_res()); if let ExprKind::Path(qself, path) = &expr.kind - && path.is_potential_trivial_const_arg(tcx.features().min_generic_const_args()) - && (tcx.features().min_generic_const_args() - || matches!(maybe_res, Some(Res::Def(DefKind::ConstParam, _)))) + && path.is_potential_trivial_const_arg() + && matches!(maybe_res, Some(Res::Def(DefKind::ConstParam, _))) { let qpath = self.lower_qpath( expr.id, @@ -2403,7 +2464,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { path, ParamMode::Explicit, AllowReturnTypeNotation::No, - // FIXME(mgca): update for `fn foo() -> Bar>` support ImplTraitContext::Disallowed(ImplTraitPosition::Path), None, ); diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 88e9bbd71060..dbbd3906b525 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -517,6 +517,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) { gate_all!(fn_delegation, "functions delegation is not yet fully implemented"); gate_all!(postfix_match, "postfix match is experimental"); gate_all!(mut_ref, "mutable by-reference bindings are experimental"); + gate_all!(min_generic_const_args, "unbraced const blocks as const args are experimental"); gate_all!(global_registration, "global registration is experimental"); gate_all!(return_type_notation, "return type notation is experimental"); gate_all!(pin_ergonomics, "pinned reference syntax is experimental"); diff --git a/compiler/rustc_builtin_macros/src/autodiff.rs b/compiler/rustc_builtin_macros/src/autodiff.rs index ddc59bfe1414..9de70b8ced1d 100644 --- a/compiler/rustc_builtin_macros/src/autodiff.rs +++ b/compiler/rustc_builtin_macros/src/autodiff.rs @@ -17,7 +17,7 @@ mod llvm_enzyme { use rustc_ast::{ self as ast, AngleBracketedArg, AngleBracketedArgs, AnonConst, AssocItemKind, BindingMode, FnRetTy, FnSig, GenericArg, GenericArgs, GenericParamKind, Generics, ItemKind, - MetaItemInner, PatKind, Path, PathSegment, TyKind, Visibility, + MetaItemInner, MgcaDisambiguation, PatKind, Path, PathSegment, TyKind, Visibility, }; use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_span::{Ident, Span, Symbol, sym}; @@ -558,7 +558,11 @@ mod llvm_enzyme { } GenericParamKind::Const { .. } => { let expr = ecx.expr_path(ast::Path::from_ident(p.ident)); - let anon_const = AnonConst { id: ast::DUMMY_NODE_ID, value: expr }; + let anon_const = AnonConst { + id: ast::DUMMY_NODE_ID, + value: expr, + mgca_disambiguation: MgcaDisambiguation::Direct, + }; Some(AngleBracketedArg::Arg(GenericArg::Const(anon_const))) } GenericParamKind::Lifetime { .. } => None, @@ -813,6 +817,7 @@ mod llvm_enzyme { let anon_const = rustc_ast::AnonConst { id: ast::DUMMY_NODE_ID, value: ecx.expr_usize(span, 1 + x.width as usize), + mgca_disambiguation: MgcaDisambiguation::Direct, }; TyKind::Array(ty.clone(), anon_const) }; @@ -827,6 +832,7 @@ mod llvm_enzyme { let anon_const = rustc_ast::AnonConst { id: ast::DUMMY_NODE_ID, value: ecx.expr_usize(span, x.width as usize), + mgca_disambiguation: MgcaDisambiguation::Direct, }; let kind = TyKind::Array(ty.clone(), anon_const); let ty = diff --git a/compiler/rustc_builtin_macros/src/pattern_type.rs b/compiler/rustc_builtin_macros/src/pattern_type.rs index 87a5a440140e..4126547b0515 100644 --- a/compiler/rustc_builtin_macros/src/pattern_type.rs +++ b/compiler/rustc_builtin_macros/src/pattern_type.rs @@ -1,5 +1,5 @@ use rustc_ast::tokenstream::TokenStream; -use rustc_ast::{AnonConst, DUMMY_NODE_ID, Ty, TyPat, TyPatKind, ast, token}; +use rustc_ast::{AnonConst, DUMMY_NODE_ID, MgcaDisambiguation, Ty, TyPat, TyPatKind, ast, token}; use rustc_errors::PResult; use rustc_expand::base::{self, DummyResult, ExpandResult, ExtCtxt, MacroExpanderResult}; use rustc_parse::exp; @@ -60,8 +60,20 @@ fn ty_pat(kind: TyPatKind, span: Span) -> TyPat { fn pat_to_ty_pat(cx: &mut ExtCtxt<'_>, pat: ast::Pat) -> TyPat { let kind = match pat.kind { ast::PatKind::Range(start, end, include_end) => TyPatKind::Range( - start.map(|value| Box::new(AnonConst { id: DUMMY_NODE_ID, value })), - end.map(|value| Box::new(AnonConst { id: DUMMY_NODE_ID, value })), + start.map(|value| { + Box::new(AnonConst { + id: DUMMY_NODE_ID, + value, + mgca_disambiguation: MgcaDisambiguation::Direct, + }) + }), + end.map(|value| { + Box::new(AnonConst { + id: DUMMY_NODE_ID, + value, + mgca_disambiguation: MgcaDisambiguation::Direct, + }) + }), include_end, ), ast::PatKind::Or(variants) => { diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs index 6be65b0fff16..e5c06889f3e0 100644 --- a/compiler/rustc_expand/src/build.rs +++ b/compiler/rustc_expand/src/build.rs @@ -2,8 +2,8 @@ use rustc_ast::token::Delimiter; use rustc_ast::tokenstream::TokenStream; use rustc_ast::util::literal; use rustc_ast::{ - self as ast, AnonConst, AttrItem, AttrVec, BlockCheckMode, Expr, LocalKind, MatchKind, PatKind, - UnOp, attr, token, tokenstream, + self as ast, AnonConst, AttrItem, AttrVec, BlockCheckMode, Expr, LocalKind, MatchKind, + MgcaDisambiguation, PatKind, UnOp, attr, token, tokenstream, }; use rustc_span::source_map::Spanned; use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, sym}; @@ -101,6 +101,7 @@ impl<'a> ExtCtxt<'a> { attrs: AttrVec::new(), tokens: None, }), + mgca_disambiguation: MgcaDisambiguation::Direct, } } diff --git a/compiler/rustc_parse/src/parser/asm.rs b/compiler/rustc_parse/src/parser/asm.rs index 41c3b0f0b676..caec877232a6 100644 --- a/compiler/rustc_parse/src/parser/asm.rs +++ b/compiler/rustc_parse/src/parser/asm.rs @@ -1,4 +1,4 @@ -use rustc_ast::{self as ast, AsmMacro}; +use rustc_ast::{self as ast, AsmMacro, MgcaDisambiguation}; use rustc_span::{Span, Symbol, kw}; use super::{ExpKeywordPair, ForceCollect, IdentIsRaw, Trailing, UsePreAttrPos}; @@ -149,7 +149,7 @@ fn parse_asm_operand<'a>( let block = p.parse_block()?; ast::InlineAsmOperand::Label { block } } else if p.eat_keyword(exp!(Const)) { - let anon_const = p.parse_expr_anon_const()?; + let anon_const = p.parse_expr_anon_const(|_, _| MgcaDisambiguation::AnonConst)?; ast::InlineAsmOperand::Const { anon_const } } else if p.eat_keyword(exp!(Sym)) { let expr = p.parse_expr()?; diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 4f6860fead8d..d7d343ac16b4 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -6,8 +6,8 @@ use rustc_ast::token::{self, Lit, LitKind, Token, TokenKind}; use rustc_ast::util::parser::AssocOp; use rustc_ast::{ self as ast, AngleBracketedArg, AngleBracketedArgs, AnonConst, AttrVec, BinOpKind, BindingMode, - Block, BlockCheckMode, Expr, ExprKind, GenericArg, Generics, Item, ItemKind, Param, Pat, - PatKind, Path, PathSegment, QSelf, Recovered, Ty, TyKind, + Block, BlockCheckMode, Expr, ExprKind, GenericArg, Generics, Item, ItemKind, + MgcaDisambiguation, Param, Pat, PatKind, Path, PathSegment, QSelf, Recovered, Ty, TyKind, }; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashSet; @@ -31,16 +31,15 @@ use crate::errors::{ AddParen, AmbiguousPlus, AsyncMoveBlockIn2015, AsyncUseBlockIn2015, AttributeOnParamType, AwaitSuggestion, BadQPathStage2, BadTypePlus, BadTypePlusSub, ColonAsSemi, ComparisonOperatorsCannotBeChained, ComparisonOperatorsCannotBeChainedSugg, - ConstGenericWithoutBraces, ConstGenericWithoutBracesSugg, DocCommentDoesNotDocumentAnything, - DocCommentOnParamType, DoubleColonInBound, ExpectedIdentifier, ExpectedSemi, ExpectedSemiSugg, - GenericParamsWithoutAngleBrackets, GenericParamsWithoutAngleBracketsSugg, - HelpIdentifierStartsWithNumber, HelpUseLatestEdition, InInTypo, IncorrectAwait, - IncorrectSemicolon, IncorrectUseOfAwait, IncorrectUseOfUse, PatternMethodParamWithoutBody, - QuestionMarkInType, QuestionMarkInTypeSugg, SelfParamNotFirst, StructLiteralBodyWithoutPath, - StructLiteralBodyWithoutPathSugg, SuggAddMissingLetStmt, SuggEscapeIdentifier, SuggRemoveComma, - TernaryOperator, TernaryOperatorSuggestion, UnexpectedConstInGenericParam, - UnexpectedConstParamDeclaration, UnexpectedConstParamDeclarationSugg, UnmatchedAngleBrackets, - UseEqInstead, WrapType, + DocCommentDoesNotDocumentAnything, DocCommentOnParamType, DoubleColonInBound, + ExpectedIdentifier, ExpectedSemi, ExpectedSemiSugg, GenericParamsWithoutAngleBrackets, + GenericParamsWithoutAngleBracketsSugg, HelpIdentifierStartsWithNumber, HelpUseLatestEdition, + InInTypo, IncorrectAwait, IncorrectSemicolon, IncorrectUseOfAwait, IncorrectUseOfUse, + PatternMethodParamWithoutBody, QuestionMarkInType, QuestionMarkInTypeSugg, SelfParamNotFirst, + StructLiteralBodyWithoutPath, StructLiteralBodyWithoutPathSugg, SuggAddMissingLetStmt, + SuggEscapeIdentifier, SuggRemoveComma, TernaryOperator, TernaryOperatorSuggestion, + UnexpectedConstInGenericParam, UnexpectedConstParamDeclaration, + UnexpectedConstParamDeclarationSugg, UnmatchedAngleBrackets, UseEqInstead, WrapType, }; use crate::parser::FnContext; use crate::parser::attr::InnerAttrPolicy; @@ -2558,36 +2557,6 @@ impl<'a> Parser<'a> { Ok(false) // Don't continue. } - /// Attempt to parse a generic const argument that has not been enclosed in braces. - /// There are a limited number of expressions that are permitted without being encoded - /// in braces: - /// - Literals. - /// - Single-segment paths (i.e. standalone generic const parameters). - /// All other expressions that can be parsed will emit an error suggesting the expression be - /// wrapped in braces. - pub(super) fn handle_unambiguous_unbraced_const_arg(&mut self) -> PResult<'a, Box> { - let start = self.token.span; - let attrs = self.parse_outer_attributes()?; - let (expr, _) = - self.parse_expr_res(Restrictions::CONST_EXPR, attrs).map_err(|mut err| { - err.span_label( - start.shrink_to_lo(), - "while parsing a const generic argument starting here", - ); - err - })?; - if !self.expr_is_valid_const_arg(&expr) { - self.dcx().emit_err(ConstGenericWithoutBraces { - span: expr.span, - sugg: ConstGenericWithoutBracesSugg { - left: expr.span.shrink_to_lo(), - right: expr.span.shrink_to_hi(), - }, - }); - } - Ok(expr) - } - fn recover_const_param_decl(&mut self, ty_generics: Option<&Generics>) -> Option { let snapshot = self.create_snapshot_for_diagnostic(); let param = match self.parse_const_param(AttrVec::new()) { @@ -2623,7 +2592,11 @@ impl<'a> Parser<'a> { self.dcx().emit_err(UnexpectedConstParamDeclaration { span: param.span(), sugg }); let value = self.mk_expr_err(param.span(), guar); - Some(GenericArg::Const(AnonConst { id: ast::DUMMY_NODE_ID, value })) + Some(GenericArg::Const(AnonConst { + id: ast::DUMMY_NODE_ID, + value, + mgca_disambiguation: MgcaDisambiguation::Direct, + })) } pub(super) fn recover_const_param_declaration( @@ -2707,7 +2680,11 @@ impl<'a> Parser<'a> { ); let guar = err.emit(); let value = self.mk_expr_err(start.to(expr.span), guar); - return Ok(GenericArg::Const(AnonConst { id: ast::DUMMY_NODE_ID, value })); + return Ok(GenericArg::Const(AnonConst { + id: ast::DUMMY_NODE_ID, + value, + mgca_disambiguation: MgcaDisambiguation::Direct, + })); } else if snapshot.token == token::Colon && expr.span.lo() == snapshot.token.span.hi() && matches!(expr.kind, ExprKind::Path(..)) @@ -2776,7 +2753,11 @@ impl<'a> Parser<'a> { ); let guar = err.emit(); let value = self.mk_expr_err(span, guar); - GenericArg::Const(AnonConst { id: ast::DUMMY_NODE_ID, value }) + GenericArg::Const(AnonConst { + id: ast::DUMMY_NODE_ID, + value, + mgca_disambiguation: MgcaDisambiguation::Direct, + }) } /// Some special error handling for the "top-level" patterns in a match arm, diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index fa5e61d24d91..3f0853a3c54d 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -15,8 +15,8 @@ use rustc_ast::visit::{Visitor, walk_expr}; use rustc_ast::{ self as ast, AnonConst, Arm, AssignOp, AssignOpKind, AttrStyle, AttrVec, BinOp, BinOpKind, BlockCheckMode, CaptureBy, ClosureBinder, DUMMY_NODE_ID, Expr, ExprField, ExprKind, FnDecl, - FnRetTy, Label, MacCall, MetaItemLit, Movability, Param, RangeLimits, StmtKind, Ty, TyKind, - UnOp, UnsafeBinderCastKind, YieldKind, + FnRetTy, Label, MacCall, MetaItemLit, MgcaDisambiguation, Movability, Param, RangeLimits, + StmtKind, Ty, TyKind, UnOp, UnsafeBinderCastKind, YieldKind, }; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::{Applicability, Diag, PResult, StashKey, Subdiagnostic}; @@ -85,8 +85,15 @@ impl<'a> Parser<'a> { ) } - pub fn parse_expr_anon_const(&mut self) -> PResult<'a, AnonConst> { - self.parse_expr().map(|value| AnonConst { id: DUMMY_NODE_ID, value }) + pub fn parse_expr_anon_const( + &mut self, + mgca_disambiguation: impl FnOnce(&Self, &Expr) -> MgcaDisambiguation, + ) -> PResult<'a, AnonConst> { + self.parse_expr().map(|value| AnonConst { + id: DUMMY_NODE_ID, + mgca_disambiguation: mgca_disambiguation(self, &value), + value, + }) } fn parse_expr_catch_underscore( @@ -1615,7 +1622,18 @@ impl<'a> Parser<'a> { let first_expr = self.parse_expr()?; if self.eat(exp!(Semi)) { // Repeating array syntax: `[ 0; 512 ]` - let count = self.parse_expr_anon_const()?; + let count = if self.token.is_keyword(kw::Const) + && self.look_ahead(1, |t| *t == token::OpenBrace) + { + // While we could just disambiguate `Direct` from `AnonConst` by + // treating all const block exprs as `AnonConst`, that would + // complicate the DefCollector and likely all other visitors. + // So we strip the const blockiness and just store it as a block + // in the AST with the extra disambiguator on the AnonConst + self.parse_expr_anon_const(|_, _| MgcaDisambiguation::AnonConst)? + } else { + self.parse_expr_anon_const(|this, expr| this.mgca_direct_lit_hack(expr))? + }; self.expect(close)?; ExprKind::Repeat(first_expr, count) } else if self.eat(exp!(Comma)) { diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index abc0ffa87d3d..b4ce30767cb8 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -1431,7 +1431,7 @@ impl<'a> Parser<'a> { let rhs = if self.eat(exp!(Eq)) { if attr::contains_name(attrs, sym::type_const) { - Some(ConstItemRhs::TypeConst(self.parse_expr_anon_const()?)) + Some(ConstItemRhs::TypeConst(self.parse_const_arg()?)) } else { Some(ConstItemRhs::Body(self.parse_expr()?)) } @@ -1650,8 +1650,11 @@ impl<'a> Parser<'a> { VariantData::Unit(DUMMY_NODE_ID) }; - let disr_expr = - if this.eat(exp!(Eq)) { Some(this.parse_expr_anon_const()?) } else { None }; + let disr_expr = if this.eat(exp!(Eq)) { + Some(this.parse_expr_anon_const(|_, _| MgcaDisambiguation::AnonConst)?) + } else { + None + }; let vr = ast::Variant { ident, @@ -1864,7 +1867,7 @@ impl<'a> Parser<'a> { if p.token == token::Eq { let mut snapshot = p.create_snapshot_for_diagnostic(); snapshot.bump(); - match snapshot.parse_expr_anon_const() { + match snapshot.parse_expr_anon_const(|_, _| MgcaDisambiguation::AnonConst) { Ok(const_expr) => { let sp = ty.span.shrink_to_hi().to(const_expr.value.span); p.psess.gated_spans.gate(sym::default_field_values, sp); @@ -2066,7 +2069,7 @@ impl<'a> Parser<'a> { } let default = if self.token == token::Eq { self.bump(); - let const_expr = self.parse_expr_anon_const()?; + let const_expr = self.parse_expr_anon_const(|_, _| MgcaDisambiguation::AnonConst)?; let sp = ty.span.shrink_to_hi().to(const_expr.value.span); self.psess.gated_spans.gate(sym::default_field_values, sp); Some(const_expr) diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 8577ea40589a..c86d586e4783 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -35,9 +35,9 @@ use rustc_ast::tokenstream::{ }; use rustc_ast::util::case::Case; use rustc_ast::{ - self as ast, AnonConst, AttrArgs, AttrId, ByRef, Const, CoroutineKind, DUMMY_NODE_ID, - DelimArgs, Expr, ExprKind, Extern, HasAttrs, HasTokens, Mutability, Recovered, Safety, StrLit, - Visibility, VisibilityKind, + self as ast, AnonConst, AttrArgs, AttrId, BlockCheckMode, ByRef, Const, CoroutineKind, + DUMMY_NODE_ID, DelimArgs, Expr, ExprKind, Extern, HasAttrs, HasTokens, MgcaDisambiguation, + Mutability, Recovered, Safety, StrLit, Visibility, VisibilityKind, }; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashMap; @@ -727,7 +727,10 @@ impl<'a> Parser<'a> { } fn check_const_arg(&mut self) -> bool { - self.check_or_expected(self.token.can_begin_const_arg(), TokenType::Const) + let is_mcg_arg = self.check_or_expected(self.token.can_begin_const_arg(), TokenType::Const); + let is_mgca_arg = self.is_keyword_ahead(0, &[kw::Const]) + && self.look_ahead(1, |t| *t == token::OpenBrace); + is_mcg_arg || is_mgca_arg } fn check_const_closure(&self) -> bool { @@ -1299,6 +1302,20 @@ impl<'a> Parser<'a> { } } + fn parse_mgca_const_block(&mut self, gate_syntax: bool) -> PResult<'a, AnonConst> { + self.expect_keyword(exp!(Const))?; + let kw_span = self.token.span; + let value = self.parse_expr_block(None, self.token.span, BlockCheckMode::Default)?; + if gate_syntax { + self.psess.gated_spans.gate(sym::min_generic_const_args, kw_span.to(value.span)); + } + Ok(AnonConst { + id: ast::DUMMY_NODE_ID, + value, + mgca_disambiguation: MgcaDisambiguation::AnonConst, + }) + } + /// Parses inline const expressions. fn parse_const_block(&mut self, span: Span, pat: bool) -> PResult<'a, Box> { self.expect_keyword(exp!(Const))?; @@ -1306,6 +1323,7 @@ impl<'a> Parser<'a> { let anon_const = AnonConst { id: DUMMY_NODE_ID, value: self.mk_expr(blk.span, ExprKind::Block(blk, None)), + mgca_disambiguation: MgcaDisambiguation::AnonConst, }; let blk_span = anon_const.value.span; let kind = if pat { diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index 437f6da67b74..ce9e9c73669e 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -4,8 +4,8 @@ use ast::token::IdentIsRaw; use rustc_ast::token::{self, MetaVarKind, Token, TokenKind}; use rustc_ast::{ self as ast, AngleBracketedArg, AngleBracketedArgs, AnonConst, AssocItemConstraint, - AssocItemConstraintKind, BlockCheckMode, GenericArg, GenericArgs, Generics, ParenthesizedArgs, - Path, PathSegment, QSelf, + AssocItemConstraintKind, BlockCheckMode, GenericArg, GenericArgs, Generics, MgcaDisambiguation, + ParenthesizedArgs, Path, PathSegment, QSelf, }; use rustc_errors::{Applicability, Diag, PResult}; use rustc_span::{BytePos, Ident, Span, kw, sym}; @@ -16,12 +16,13 @@ use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign}; use super::{Parser, Restrictions, TokenType}; use crate::ast::{PatKind, TyKind}; use crate::errors::{ - self, AttributeOnEmptyType, AttributeOnGenericArg, FnPathFoundNamedParams, - PathFoundAttributeInParams, PathFoundCVariadicParams, PathSingleColon, PathTripleColon, + self, AttributeOnEmptyType, AttributeOnGenericArg, ConstGenericWithoutBraces, + ConstGenericWithoutBracesSugg, FnPathFoundNamedParams, PathFoundAttributeInParams, + PathFoundCVariadicParams, PathSingleColon, PathTripleColon, }; use crate::exp; use crate::parser::{ - CommaRecoveryMode, ExprKind, FnContext, FnParseMode, RecoverColon, RecoverComma, + CommaRecoveryMode, Expr, ExprKind, FnContext, FnParseMode, RecoverColon, RecoverComma, }; /// Specifies how to parse a path. @@ -870,12 +871,75 @@ impl<'a> Parser<'a> { /// the caller. pub(super) fn parse_const_arg(&mut self) -> PResult<'a, AnonConst> { // Parse const argument. - let value = if self.token.kind == token::OpenBrace { - self.parse_expr_block(None, self.token.span, BlockCheckMode::Default)? + let (value, mgca_disambiguation) = if self.token.kind == token::OpenBrace { + let value = self.parse_expr_block(None, self.token.span, BlockCheckMode::Default)?; + (value, MgcaDisambiguation::Direct) + } else if self.token.is_keyword(kw::Const) { + // While we could just disambiguate `Direct` from `AnonConst` by + // treating all const block exprs as `AnonConst`, that would + // complicate the DefCollector and likely all other visitors. + // So we strip the const blockiness and just store it as a block + // in the AST with the extra disambiguator on the AnonConst + let value = self.parse_mgca_const_block(true)?; + (value.value, MgcaDisambiguation::AnonConst) } else { - self.handle_unambiguous_unbraced_const_arg()? + self.parse_unambiguous_unbraced_const_arg()? }; - Ok(AnonConst { id: ast::DUMMY_NODE_ID, value }) + Ok(AnonConst { id: ast::DUMMY_NODE_ID, value, mgca_disambiguation }) + } + + /// Attempt to parse a const argument that has not been enclosed in braces. + /// There are a limited number of expressions that are permitted without being + /// enclosed in braces: + /// - Literals. + /// - Single-segment paths (i.e. standalone generic const parameters). + /// All other expressions that can be parsed will emit an error suggesting the expression be + /// wrapped in braces. + pub(super) fn parse_unambiguous_unbraced_const_arg( + &mut self, + ) -> PResult<'a, (Box, MgcaDisambiguation)> { + let start = self.token.span; + let attrs = self.parse_outer_attributes()?; + let (expr, _) = + self.parse_expr_res(Restrictions::CONST_EXPR, attrs).map_err(|mut err| { + err.span_label( + start.shrink_to_lo(), + "while parsing a const generic argument starting here", + ); + err + })?; + if !self.expr_is_valid_const_arg(&expr) { + self.dcx().emit_err(ConstGenericWithoutBraces { + span: expr.span, + sugg: ConstGenericWithoutBracesSugg { + left: expr.span.shrink_to_lo(), + right: expr.span.shrink_to_hi(), + }, + }); + } + + let mgca_disambiguation = self.mgca_direct_lit_hack(&expr); + Ok((expr, mgca_disambiguation)) + } + + /// Under `min_generic_const_args` we still allow *some* anon consts to be written without + /// a `const` block as it makes things quite a lot nicer. This function is useful for contexts + /// where we would like to use `MgcaDisambiguation::Direct` but need to fudge it to be `AnonConst` + /// in the presence of literals. + // + /// FIXME(min_generic_const_args): In the long term it would be nice to have a way to directly + /// represent literals in `hir::ConstArgKind` so that we can remove this special case by not + /// needing an anon const. + pub fn mgca_direct_lit_hack(&self, expr: &Expr) -> MgcaDisambiguation { + match &expr.kind { + ast::ExprKind::Lit(_) => MgcaDisambiguation::AnonConst, + ast::ExprKind::Unary(ast::UnOp::Neg, expr) + if matches!(expr.kind, ast::ExprKind::Lit(_)) => + { + MgcaDisambiguation::AnonConst + } + _ => MgcaDisambiguation::Direct, + } } /// Parse a generic argument in a path segment. @@ -976,7 +1040,11 @@ impl<'a> Parser<'a> { GenericArg::Type(_) => GenericArg::Type(self.mk_ty(attr_span, TyKind::Err(guar))), GenericArg::Const(_) => { let error_expr = self.mk_expr(attr_span, ExprKind::Err(guar)); - GenericArg::Const(AnonConst { id: ast::DUMMY_NODE_ID, value: error_expr }) + GenericArg::Const(AnonConst { + id: ast::DUMMY_NODE_ID, + value: error_expr, + mgca_disambiguation: MgcaDisambiguation::Direct, + }) } GenericArg::Lifetime(lt) => GenericArg::Lifetime(lt), })); diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index c79b99a80e87..676514344586 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -2,9 +2,9 @@ use rustc_ast::token::{self, IdentIsRaw, MetaVarKind, Token, TokenKind}; use rustc_ast::util::case::Case; use rustc_ast::{ self as ast, BoundAsyncness, BoundConstness, BoundPolarity, DUMMY_NODE_ID, FnPtrTy, FnRetTy, - GenericBound, GenericBounds, GenericParam, Generics, Lifetime, MacCall, MutTy, Mutability, - Pinnedness, PolyTraitRef, PreciseCapturingArg, TraitBoundModifiers, TraitObjectSyntax, Ty, - TyKind, UnsafeBinderTy, + GenericBound, GenericBounds, GenericParam, Generics, Lifetime, MacCall, MgcaDisambiguation, + MutTy, Mutability, Pinnedness, PolyTraitRef, PreciseCapturingArg, TraitBoundModifiers, + TraitObjectSyntax, Ty, TyKind, UnsafeBinderTy, }; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::{Applicability, Diag, E0516, PResult}; @@ -658,7 +658,19 @@ impl<'a> Parser<'a> { }; let ty = if self.eat(exp!(Semi)) { - let mut length = self.parse_expr_anon_const()?; + let mut length = if self.token.is_keyword(kw::Const) + && self.look_ahead(1, |t| *t == token::OpenBrace) + { + // While we could just disambiguate `Direct` from `AnonConst` by + // treating all const block exprs as `AnonConst`, that would + // complicate the DefCollector and likely all other visitors. + // So we strip the const blockiness and just store it as a block + // in the AST with the extra disambiguator on the AnonConst + self.parse_mgca_const_block(false)? + } else { + self.parse_expr_anon_const(|this, expr| this.mgca_direct_lit_hack(expr))? + }; + if let Err(e) = self.expect(exp!(CloseBracket)) { // Try to recover from `X` when `X::` works self.check_mistyped_turbofish_with_multiple_type_params(e, &mut length.value)?; @@ -699,8 +711,9 @@ impl<'a> Parser<'a> { _ = self.eat(exp!(Comma)) || self.eat(exp!(Colon)) || self.eat(exp!(Star)); let suggestion_span = self.prev_token.span.with_lo(hi); + // FIXME(mgca): recovery is broken for `const {` args // we first try to parse pattern like `[u8 5]` - let length = match self.parse_expr_anon_const() { + let length = match self.parse_expr_anon_const(|_, _| MgcaDisambiguation::Direct) { Ok(length) => length, Err(e) => { e.cancel(); @@ -788,7 +801,7 @@ impl<'a> Parser<'a> { /// an error type. fn parse_typeof_ty(&mut self, lo: Span) -> PResult<'a, TyKind> { self.expect(exp!(OpenParen))?; - let _expr = self.parse_expr_anon_const()?; + let _expr = self.parse_expr_anon_const(|_, _| MgcaDisambiguation::AnonConst)?; self.expect(exp!(CloseParen))?; let span = lo.to(self.prev_token.span); let guar = self diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index f1a03d5a0610..50e11fdde568 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -1222,7 +1222,7 @@ impl<'ast, 'ra, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'ra, 'tc if let TyKind::Path(None, ref path) = ty.kind // We cannot disambiguate multi-segment paths right now as that requires type // checking. - && path.is_potential_trivial_const_arg(false) + && path.is_potential_trivial_const_arg() { let mut check_ns = |ns| { self.maybe_resolve_ident_in_lexical_scope(path.segments[0].ident, ns) @@ -4840,9 +4840,12 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { constant, anon_const_kind ); - let is_trivial_const_arg = constant - .value - .is_potential_trivial_const_arg(self.r.tcx.features().min_generic_const_args()); + let is_trivial_const_arg = if self.r.tcx.features().min_generic_const_args() { + matches!(constant.mgca_disambiguation, MgcaDisambiguation::Direct) + } else { + constant.value.is_potential_trivial_const_arg() + }; + self.resolve_anon_const_manual(is_trivial_const_arg, anon_const_kind, |this| { this.resolve_expr(&constant.value, None) }) @@ -5023,9 +5026,9 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { // Constant arguments need to be treated as AnonConst since // that is how they will be later lowered to HIR. if const_args.contains(&idx) { - let is_trivial_const_arg = argument.is_potential_trivial_const_arg( - self.r.tcx.features().min_generic_const_args(), - ); + // FIXME(mgca): legacy const generics doesn't support mgca but maybe + // that's okay. + let is_trivial_const_arg = argument.is_potential_trivial_const_arg(); self.resolve_anon_const_manual( is_trivial_const_arg, AnonConstKind::ConstArg(IsRepeatExpr::No), diff --git a/tests/ui/associated-consts/assoc-const-eq-ambiguity.rs b/tests/ui/associated-consts/assoc-const-eq-ambiguity.rs index 2ff5a0353a0a..27261a4806eb 100644 --- a/tests/ui/associated-consts/assoc-const-eq-ambiguity.rs +++ b/tests/ui/associated-consts/assoc-const-eq-ambiguity.rs @@ -10,7 +10,7 @@ trait Parent0 { const K: (); } -fn take0(_: impl Trait0) {} +fn take0(_: impl Trait0) {} //~^ ERROR ambiguous associated constant `K` in bounds of `Trait0` trait Trait1: Parent1 + Parent2 {} diff --git a/tests/ui/associated-consts/assoc-const-eq-ambiguity.stderr b/tests/ui/associated-consts/assoc-const-eq-ambiguity.stderr index 3541664d1c6a..9ab39e6b8a60 100644 --- a/tests/ui/associated-consts/assoc-const-eq-ambiguity.stderr +++ b/tests/ui/associated-consts/assoc-const-eq-ambiguity.stderr @@ -7,14 +7,14 @@ LL | const K: (); | ambiguous `K` from `Parent0` | ambiguous `K` from `Parent0` ... -LL | fn take0(_: impl Trait0) {} - | ^^^^^^^^^^ ambiguous associated constant `K` +LL | fn take0(_: impl Trait0) {} + | ^^^^^^^^^^^^^ ambiguous associated constant `K` | = help: consider introducing a new type parameter `T` and adding `where` constraints: where T: Trait0, - T: Parent0::K = { () }, - T: Parent0::K = { () } + T: Parent0::K = { }, + T: Parent0::K = { } error[E0222]: ambiguous associated constant `C` in bounds of `Trait1` --> $DIR/assoc-const-eq-ambiguity.rs:26:25 diff --git a/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty-not-wf.rs b/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty-not-wf.rs index 8334e67ae9a1..7f8b3036c3e8 100644 --- a/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty-not-wf.rs +++ b/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty-not-wf.rs @@ -18,7 +18,7 @@ trait Trait { fn take( _: impl Trait< < fn(&'a str) -> &'a str as Project>::Out as Discard>::Out, - K = { () } + K = const { () } >, ) {} //~^^^ ERROR higher-ranked subtype error diff --git a/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty-not-wf.stderr b/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty-not-wf.stderr index 9fac60763dae..4a4c2b285829 100644 --- a/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty-not-wf.stderr +++ b/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty-not-wf.stderr @@ -1,14 +1,14 @@ error: higher-ranked subtype error - --> $DIR/assoc-const-eq-bound-var-in-ty-not-wf.rs:21:13 + --> $DIR/assoc-const-eq-bound-var-in-ty-not-wf.rs:21:19 | -LL | K = { () } - | ^^^^^^ +LL | K = const { () } + | ^^^^^^ error: higher-ranked subtype error - --> $DIR/assoc-const-eq-bound-var-in-ty-not-wf.rs:21:13 + --> $DIR/assoc-const-eq-bound-var-in-ty-not-wf.rs:21:19 | -LL | K = { () } - | ^^^^^^ +LL | K = const { () } + | ^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` diff --git a/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty.rs b/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty.rs index ef8077b9f44a..d3975bc19ad3 100644 --- a/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty.rs +++ b/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty.rs @@ -21,7 +21,7 @@ trait Trait { fn take( _: impl Trait< fn(&'a str) -> &'a str as Discard>::Out, - K = { () } + K = const { } >, ) {} diff --git a/tests/ui/associated-consts/assoc-const-eq-esc-bound-var-in-ty.rs b/tests/ui/associated-consts/assoc-const-eq-esc-bound-var-in-ty.rs index 1ab93ea596a7..2571af57e66b 100644 --- a/tests/ui/associated-consts/assoc-const-eq-esc-bound-var-in-ty.rs +++ b/tests/ui/associated-consts/assoc-const-eq-esc-bound-var-in-ty.rs @@ -8,7 +8,7 @@ trait Trait<'a> { const K: &'a (); } -fn take(_: impl for<'r> Trait<'r, K = { &() }>) {} +fn take(_: impl for<'r> Trait<'r, K = const { &() }>) {} //~^ ERROR the type of the associated constant `K` cannot capture late-bound generic parameters //~| NOTE its type cannot capture the late-bound lifetime parameter `'r` //~| NOTE the late-bound lifetime parameter `'r` is defined here diff --git a/tests/ui/associated-consts/assoc-const-eq-esc-bound-var-in-ty.stderr b/tests/ui/associated-consts/assoc-const-eq-esc-bound-var-in-ty.stderr index d6a7eb6cfc7d..44304443ac54 100644 --- a/tests/ui/associated-consts/assoc-const-eq-esc-bound-var-in-ty.stderr +++ b/tests/ui/associated-consts/assoc-const-eq-esc-bound-var-in-ty.stderr @@ -1,7 +1,7 @@ error: the type of the associated constant `K` cannot capture late-bound generic parameters --> $DIR/assoc-const-eq-esc-bound-var-in-ty.rs:11:35 | -LL | fn take(_: impl for<'r> Trait<'r, K = { &() }>) {} +LL | fn take(_: impl for<'r> Trait<'r, K = const { &() }>) {} | -- ^ its type cannot capture the late-bound lifetime parameter `'r` | | | the late-bound lifetime parameter `'r` is defined here diff --git a/tests/ui/associated-consts/assoc-const-eq-param-in-ty.rs b/tests/ui/associated-consts/assoc-const-eq-param-in-ty.rs index 0afb95a0b033..242ad385947a 100644 --- a/tests/ui/associated-consts/assoc-const-eq-param-in-ty.rs +++ b/tests/ui/associated-consts/assoc-const-eq-param-in-ty.rs @@ -15,31 +15,33 @@ trait Trait<'a, T: 'a + ConstParamTy_, const N: usize> { const K: &'a [T; N]; } -fn take0<'r, A: 'r + ConstParamTy_, const Q: usize>(_: impl Trait<'r, A, Q, K = { loop {} }>) {} -//~^ ERROR the type of the associated constant `K` must not depend on generic parameters -//~| NOTE its type must not depend on the lifetime parameter `'r` -//~| NOTE the lifetime parameter `'r` is defined here -//~| NOTE `K` has type `&'r [A; Q]` -//~| ERROR the type of the associated constant `K` must not depend on generic parameters -//~| NOTE its type must not depend on the type parameter `A` -//~| NOTE the type parameter `A` is defined here -//~| NOTE `K` has type `&'r [A; Q]` -//~| ERROR the type of the associated constant `K` must not depend on generic parameters -//~| NOTE its type must not depend on the const parameter `Q` -//~| NOTE the const parameter `Q` is defined here -//~| NOTE `K` has type `&'r [A; Q]` +fn take0<'r, A: 'r + ConstParamTy_, const Q: usize>( + //~^ NOTE the lifetime parameter `'r` is defined here + //~| NOTE the type parameter `A` is defined here + //~| NOTE the const parameter `Q` is defined here + _: impl Trait<'r, A, Q, K = const { loop {} }> + //~^ ERROR the type of the associated constant `K` must not depend on generic parameters + //~| NOTE its type must not depend on the lifetime parameter `'r` + //~| NOTE `K` has type `&'r [A; Q]` + //~| ERROR the type of the associated constant `K` must not depend on generic parameters + //~| NOTE its type must not depend on the type parameter `A` + //~| NOTE `K` has type `&'r [A; Q]` + //~| ERROR the type of the associated constant `K` must not depend on generic parameters + //~| NOTE its type must not depend on the const parameter `Q` + //~| NOTE `K` has type `&'r [A; Q]` +) {} trait Project: ConstParamTy_ { #[type_const] const SELF: Self; } -fn take1(_: impl Project) {} +fn take1(_: impl Project) {} //~^ ERROR the type of the associated constant `SELF` must not depend on `impl Trait` //~| NOTE its type must not depend on `impl Trait` //~| NOTE the `impl Trait` is specified here -fn take2>(_: P) {} +fn take2>(_: P) {} //~^ ERROR the type of the associated constant `SELF` must not depend on generic parameters //~| NOTE its type must not depend on the type parameter `P` //~| NOTE the type parameter `P` is defined here @@ -48,7 +50,7 @@ fn take2>(_: P) {} trait Iface<'r>: ConstParamTy_ { //~^ NOTE the lifetime parameter `'r` is defined here //~| NOTE the lifetime parameter `'r` is defined here - type Assoc: Trait<'r, Self, Q, K = { loop {} }> + type Assoc: Trait<'r, Self, Q, K = const { loop {} }> //~^ ERROR the type of the associated constant `K` must not depend on generic parameters //~| ERROR the type of the associated constant `K` must not depend on generic parameters //~| NOTE its type must not depend on the lifetime parameter `'r` diff --git a/tests/ui/associated-consts/assoc-const-eq-param-in-ty.stderr b/tests/ui/associated-consts/assoc-const-eq-param-in-ty.stderr index 229dd10c0beb..b742e68044b0 100644 --- a/tests/ui/associated-consts/assoc-const-eq-param-in-ty.stderr +++ b/tests/ui/associated-consts/assoc-const-eq-param-in-ty.stderr @@ -1,42 +1,49 @@ error: the type of the associated constant `K` must not depend on generic parameters - --> $DIR/assoc-const-eq-param-in-ty.rs:18:77 + --> $DIR/assoc-const-eq-param-in-ty.rs:22:29 | -LL | fn take0<'r, A: 'r + ConstParamTy_, const Q: usize>(_: impl Trait<'r, A, Q, K = { loop {} }>) {} - | -- the lifetime parameter `'r` is defined here ^ its type must not depend on the lifetime parameter `'r` +LL | fn take0<'r, A: 'r + ConstParamTy_, const Q: usize>( + | -- the lifetime parameter `'r` is defined here +... +LL | _: impl Trait<'r, A, Q, K = const { loop {} }> + | ^ its type must not depend on the lifetime parameter `'r` | = note: `K` has type `&'r [A; Q]` error: the type of the associated constant `K` must not depend on generic parameters - --> $DIR/assoc-const-eq-param-in-ty.rs:18:77 + --> $DIR/assoc-const-eq-param-in-ty.rs:22:29 | -LL | fn take0<'r, A: 'r + ConstParamTy_, const Q: usize>(_: impl Trait<'r, A, Q, K = { loop {} }>) {} - | - the type parameter `A` is defined here ^ its type must not depend on the type parameter `A` +LL | fn take0<'r, A: 'r + ConstParamTy_, const Q: usize>( + | - the type parameter `A` is defined here +... +LL | _: impl Trait<'r, A, Q, K = const { loop {} }> + | ^ its type must not depend on the type parameter `A` | = note: `K` has type `&'r [A; Q]` error: the type of the associated constant `K` must not depend on generic parameters - --> $DIR/assoc-const-eq-param-in-ty.rs:18:77 + --> $DIR/assoc-const-eq-param-in-ty.rs:22:29 | -LL | fn take0<'r, A: 'r + ConstParamTy_, const Q: usize>(_: impl Trait<'r, A, Q, K = { loop {} }>) {} - | - ^ its type must not depend on the const parameter `Q` - | | - | the const parameter `Q` is defined here +LL | fn take0<'r, A: 'r + ConstParamTy_, const Q: usize>( + | - the const parameter `Q` is defined here +... +LL | _: impl Trait<'r, A, Q, K = const { loop {} }> + | ^ its type must not depend on the const parameter `Q` | = note: `K` has type `&'r [A; Q]` error: the type of the associated constant `SELF` must not depend on `impl Trait` - --> $DIR/assoc-const-eq-param-in-ty.rs:37:26 + --> $DIR/assoc-const-eq-param-in-ty.rs:39:26 | -LL | fn take1(_: impl Project) {} - | -------------^^^^------ +LL | fn take1(_: impl Project) {} + | -------------^^^^------------ | | | | | its type must not depend on `impl Trait` | the `impl Trait` is specified here error: the type of the associated constant `SELF` must not depend on generic parameters - --> $DIR/assoc-const-eq-param-in-ty.rs:42:21 + --> $DIR/assoc-const-eq-param-in-ty.rs:44:21 | -LL | fn take2>(_: P) {} +LL | fn take2>(_: P) {} | - ^^^^ its type must not depend on the type parameter `P` | | | the type parameter `P` is defined here @@ -44,28 +51,28 @@ LL | fn take2>(_: P) {} = note: `SELF` has type `P` error: the type of the associated constant `K` must not depend on generic parameters - --> $DIR/assoc-const-eq-param-in-ty.rs:51:52 + --> $DIR/assoc-const-eq-param-in-ty.rs:53:52 | LL | trait Iface<'r>: ConstParamTy_ { | -- the lifetime parameter `'r` is defined here ... -LL | type Assoc: Trait<'r, Self, Q, K = { loop {} }> +LL | type Assoc: Trait<'r, Self, Q, K = const { loop {} }> | ^ its type must not depend on the lifetime parameter `'r` | = note: `K` has type `&'r [Self; Q]` error: the type of the associated constant `K` must not depend on `Self` - --> $DIR/assoc-const-eq-param-in-ty.rs:51:52 + --> $DIR/assoc-const-eq-param-in-ty.rs:53:52 | -LL | type Assoc: Trait<'r, Self, Q, K = { loop {} }> +LL | type Assoc: Trait<'r, Self, Q, K = const { loop {} }> | ^ its type must not depend on `Self` | = note: `K` has type `&'r [Self; Q]` error: the type of the associated constant `K` must not depend on generic parameters - --> $DIR/assoc-const-eq-param-in-ty.rs:51:52 + --> $DIR/assoc-const-eq-param-in-ty.rs:53:52 | -LL | type Assoc: Trait<'r, Self, Q, K = { loop {} }> +LL | type Assoc: Trait<'r, Self, Q, K = const { loop {} }> | - ^ its type must not depend on the const parameter `Q` | | | the const parameter `Q` is defined here @@ -73,30 +80,30 @@ LL | type Assoc: Trait<'r, Self, Q, K = { loop {} }> = note: `K` has type `&'r [Self; Q]` error: the type of the associated constant `K` must not depend on generic parameters - --> $DIR/assoc-const-eq-param-in-ty.rs:51:52 + --> $DIR/assoc-const-eq-param-in-ty.rs:53:52 | LL | trait Iface<'r>: ConstParamTy_ { | -- the lifetime parameter `'r` is defined here ... -LL | type Assoc: Trait<'r, Self, Q, K = { loop {} }> +LL | type Assoc: Trait<'r, Self, Q, K = const { loop {} }> | ^ its type must not depend on the lifetime parameter `'r` | = note: `K` has type `&'r [Self; Q]` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: the type of the associated constant `K` must not depend on `Self` - --> $DIR/assoc-const-eq-param-in-ty.rs:51:52 + --> $DIR/assoc-const-eq-param-in-ty.rs:53:52 | -LL | type Assoc: Trait<'r, Self, Q, K = { loop {} }> +LL | type Assoc: Trait<'r, Self, Q, K = const { loop {} }> | ^ its type must not depend on `Self` | = note: `K` has type `&'r [Self; Q]` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: the type of the associated constant `K` must not depend on generic parameters - --> $DIR/assoc-const-eq-param-in-ty.rs:51:52 + --> $DIR/assoc-const-eq-param-in-ty.rs:53:52 | -LL | type Assoc: Trait<'r, Self, Q, K = { loop {} }> +LL | type Assoc: Trait<'r, Self, Q, K = const { loop {} }> | - ^ its type must not depend on the const parameter `Q` | | | the const parameter `Q` is defined here diff --git a/tests/ui/associated-consts/assoc-const.rs b/tests/ui/associated-consts/assoc-const.rs index 4eed8bba53b1..6295fd50b8ff 100644 --- a/tests/ui/associated-consts/assoc-const.rs +++ b/tests/ui/associated-consts/assoc-const.rs @@ -14,10 +14,10 @@ impl Foo for Bar { const N: usize = 3; } -const TEST:usize = 3; +const TEST: usize = 3; -fn foo>() {} +fn foo>() {} fn main() { foo::() diff --git a/tests/ui/associated-consts/issue-110933.rs b/tests/ui/associated-consts/issue-110933.rs index 0284369f4d65..731ff1564ce2 100644 --- a/tests/ui/associated-consts/issue-110933.rs +++ b/tests/ui/associated-consts/issue-110933.rs @@ -10,7 +10,7 @@ pub trait Trait { pub fn foo< T: Trait< - ASSOC = { + ASSOC = const { let a = 10_usize; let b: &'_ usize = &a; *b diff --git a/tests/ui/associated-type-bounds/const-projection-err.rs b/tests/ui/associated-type-bounds/const-projection-err.rs index 80845ec3ee86..b230ea77f5fe 100644 --- a/tests/ui/associated-type-bounds/const-projection-err.rs +++ b/tests/ui/associated-type-bounds/const-projection-err.rs @@ -1,10 +1,6 @@ -//@ revisions: stock gce - #![feature(associated_const_equality, min_generic_const_args)] #![allow(incomplete_features)] -#![cfg_attr(gce, feature(generic_const_exprs))] - trait TraitWAssocConst { #[type_const] const A: usize; diff --git a/tests/ui/associated-type-bounds/const-projection-err.gce.stderr b/tests/ui/associated-type-bounds/const-projection-err.stderr similarity index 66% rename from tests/ui/associated-type-bounds/const-projection-err.gce.stderr rename to tests/ui/associated-type-bounds/const-projection-err.stderr index 9ad851d188d3..552b1579e618 100644 --- a/tests/ui/associated-type-bounds/const-projection-err.gce.stderr +++ b/tests/ui/associated-type-bounds/const-projection-err.stderr @@ -1,11 +1,13 @@ error[E0271]: type mismatch resolving `::A == 1` - --> $DIR/const-projection-err.rs:16:11 + --> $DIR/const-projection-err.rs:12:11 | LL | foo::(); - | ^ expected `0`, found `1` + | ^ expected `1`, found `0` | + = note: expected constant `1` + found constant `0` note: required by a bound in `foo` - --> $DIR/const-projection-err.rs:13:28 + --> $DIR/const-projection-err.rs:9:28 | LL | fn foo>() {} | ^^^^^ required by this bound in `foo` diff --git a/tests/ui/associated-type-bounds/duplicate-bound-err.rs b/tests/ui/associated-type-bounds/duplicate-bound-err.rs index 72c1ab559bdf..7e86148eb811 100644 --- a/tests/ui/associated-type-bounds/duplicate-bound-err.rs +++ b/tests/ui/associated-type-bounds/duplicate-bound-err.rs @@ -81,7 +81,9 @@ fn uncallable(_: impl Iterator) {} fn uncallable_const(_: impl Trait) {} -fn uncallable_rtn(_: impl Trait, foo(..): Trait>) {} +fn uncallable_rtn( + _: impl Trait, foo(..): Trait> +) {} type MustFail = dyn Iterator; //~^ ERROR [E0719] diff --git a/tests/ui/associated-type-bounds/duplicate-bound-err.stderr b/tests/ui/associated-type-bounds/duplicate-bound-err.stderr index a54425c3a295..6484880392d6 100644 --- a/tests/ui/associated-type-bounds/duplicate-bound-err.stderr +++ b/tests/ui/associated-type-bounds/duplicate-bound-err.stderr @@ -100,7 +100,7 @@ LL | iter::empty::() | ----------------------- return type was inferred to be `std::iter::Empty` here error[E0271]: expected `IntoIter` to be an iterator that yields `i32`, but it yields `u32` - --> $DIR/duplicate-bound-err.rs:110:17 + --> $DIR/duplicate-bound-err.rs:112:17 | LL | fn foo() -> impl Iterator { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `i32`, found `u32` @@ -109,7 +109,7 @@ LL | [2u32].into_iter() | ------------------ return type was inferred to be `std::array::IntoIter` here error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate-bound-err.rs:86:42 + --> $DIR/duplicate-bound-err.rs:88:42 | LL | type MustFail = dyn Iterator; | ---------- ^^^^^^^^^^ re-bound here @@ -117,7 +117,7 @@ LL | type MustFail = dyn Iterator; | `Item` bound here first error: conflicting associated type bounds for `Item` - --> $DIR/duplicate-bound-err.rs:86:17 + --> $DIR/duplicate-bound-err.rs:88:17 | LL | type MustFail = dyn Iterator; | ^^^^^^^^^^^^^----------^^----------^ @@ -126,7 +126,7 @@ LL | type MustFail = dyn Iterator; | `Item` is specified to be `i32` here error[E0719]: the value of the associated type `ASSOC` in trait `Trait2` is already specified - --> $DIR/duplicate-bound-err.rs:95:43 + --> $DIR/duplicate-bound-err.rs:97:43 | LL | type MustFail2 = dyn Trait2; | ------------ ^^^^^^^^^^^^ re-bound here @@ -134,7 +134,7 @@ LL | type MustFail2 = dyn Trait2; | `ASSOC` bound here first error: conflicting associated type bounds for `ASSOC` - --> $DIR/duplicate-bound-err.rs:95:18 + --> $DIR/duplicate-bound-err.rs:97:18 | LL | type MustFail2 = dyn Trait2; | ^^^^^^^^^^^------------^^------------^ @@ -143,7 +143,7 @@ LL | type MustFail2 = dyn Trait2; | `ASSOC` is specified to be `3` here error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate-bound-err.rs:99:43 + --> $DIR/duplicate-bound-err.rs:101:43 | LL | type MustFail3 = dyn Iterator; | ---------- ^^^^^^^^^^ re-bound here @@ -151,7 +151,7 @@ LL | type MustFail3 = dyn Iterator; | `Item` bound here first error[E0719]: the value of the associated type `ASSOC` in trait `Trait2` is already specified - --> $DIR/duplicate-bound-err.rs:102:43 + --> $DIR/duplicate-bound-err.rs:104:43 | LL | type MustFail4 = dyn Trait2; | ------------ ^^^^^^^^^^^^ re-bound here @@ -159,19 +159,19 @@ LL | type MustFail4 = dyn Trait2; | `ASSOC` bound here first error[E0271]: expected `impl Iterator` to be an iterator that yields `i32`, but it yields `u32` - --> $DIR/duplicate-bound-err.rs:110:17 + --> $DIR/duplicate-bound-err.rs:112:17 | LL | fn foo() -> impl Iterator { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `i32`, found `u32` | note: required by a bound in `Trait3::foo::{anon_assoc#0}` - --> $DIR/duplicate-bound-err.rs:106:31 + --> $DIR/duplicate-bound-err.rs:108:31 | LL | fn foo() -> impl Iterator; | ^^^^^^^^^^ required by this bound in `Trait3::foo::{anon_assoc#0}` error[E0271]: expected `Empty` to be an iterator that yields `i32`, but it yields `u32` - --> $DIR/duplicate-bound-err.rs:118:16 + --> $DIR/duplicate-bound-err.rs:120:16 | LL | uncallable(iter::empty::()); | ---------- ^^^^^^^^^^^^^^^^^^^^ expected `i32`, found `u32` @@ -185,7 +185,7 @@ LL | fn uncallable(_: impl Iterator) {} | ^^^^^^^^^^ required by this bound in `uncallable` error[E0271]: expected `Empty` to be an iterator that yields `u32`, but it yields `i32` - --> $DIR/duplicate-bound-err.rs:119:16 + --> $DIR/duplicate-bound-err.rs:121:16 | LL | uncallable(iter::empty::()); | ---------- ^^^^^^^^^^^^^^^^^^^^ expected `u32`, found `i32` @@ -199,7 +199,7 @@ LL | fn uncallable(_: impl Iterator) {} | ^^^^^^^^^^ required by this bound in `uncallable` error[E0271]: type mismatch resolving `<() as Trait>::ASSOC == 4` - --> $DIR/duplicate-bound-err.rs:120:22 + --> $DIR/duplicate-bound-err.rs:122:22 | LL | uncallable_const(()); | ---------------- ^^ expected `4`, found `3` @@ -215,7 +215,7 @@ LL | fn uncallable_const(_: impl Trait) {} | ^^^^^^^^^ required by this bound in `uncallable_const` error[E0271]: type mismatch resolving `::ASSOC == 3` - --> $DIR/duplicate-bound-err.rs:121:22 + --> $DIR/duplicate-bound-err.rs:123:22 | LL | uncallable_const(4u32); | ---------------- ^^^^ expected `3`, found `4` @@ -231,7 +231,7 @@ LL | fn uncallable_const(_: impl Trait) {} | ^^^^^^^^^ required by this bound in `uncallable_const` error[E0271]: type mismatch resolving `<() as Trait>::ASSOC == 4` - --> $DIR/duplicate-bound-err.rs:122:20 + --> $DIR/duplicate-bound-err.rs:124:20 | LL | uncallable_rtn(()); | -------------- ^^ expected `4`, found `3` @@ -241,13 +241,15 @@ LL | uncallable_rtn(()); = note: expected constant `4` found constant `3` note: required by a bound in `uncallable_rtn` - --> $DIR/duplicate-bound-err.rs:84:75 + --> $DIR/duplicate-bound-err.rs:85:61 | -LL | fn uncallable_rtn(_: impl Trait, foo(..): Trait>) {} - | ^^^^^^^^^ required by this bound in `uncallable_rtn` +LL | fn uncallable_rtn( + | -------------- required by a bound in this function +LL | _: impl Trait, foo(..): Trait> + | ^^^^^^^^^ required by this bound in `uncallable_rtn` error[E0271]: type mismatch resolving `::ASSOC == 3` - --> $DIR/duplicate-bound-err.rs:123:20 + --> $DIR/duplicate-bound-err.rs:125:20 | LL | uncallable_rtn(17u32); | -------------- ^^^^^ expected `3`, found `4` @@ -257,10 +259,12 @@ LL | uncallable_rtn(17u32); = note: expected constant `3` found constant `4` note: required by a bound in `uncallable_rtn` - --> $DIR/duplicate-bound-err.rs:84:48 + --> $DIR/duplicate-bound-err.rs:85:34 | -LL | fn uncallable_rtn(_: impl Trait, foo(..): Trait>) {} - | ^^^^^^^^^ required by this bound in `uncallable_rtn` +LL | fn uncallable_rtn( + | -------------- required by a bound in this function +LL | _: impl Trait, foo(..): Trait> + | ^^^^^^^^^ required by this bound in `uncallable_rtn` error: aborting due to 25 previous errors diff --git a/tests/ui/associated-type-bounds/duplicate-bound.rs b/tests/ui/associated-type-bounds/duplicate-bound.rs index 3f40e429260f..6ea0daeca2c4 100644 --- a/tests/ui/associated-type-bounds/duplicate-bound.rs +++ b/tests/ui/associated-type-bounds/duplicate-bound.rs @@ -224,7 +224,9 @@ fn uncallable_const(_: impl Trait) {} fn callable_const(_: impl Trait) {} -fn uncallable_rtn(_: impl Trait, foo(..): Trait>) {} +fn uncallable_rtn( + _: impl Trait, foo(..): Trait> +) {} fn callable_rtn(_: impl Trait) {} diff --git a/tests/ui/const-generics/associated_const_equality/unconstrained_impl_param.rs b/tests/ui/const-generics/associated_const_equality/unconstrained_impl_param.rs index edadcd7c80ed..f28f3f694ff3 100644 --- a/tests/ui/const-generics/associated_const_equality/unconstrained_impl_param.rs +++ b/tests/ui/const-generics/associated_const_equality/unconstrained_impl_param.rs @@ -12,7 +12,7 @@ impl AssocConst for (T,) { trait Trait {} -impl Trait for () where (U,): AssocConst {} +impl Trait for () where (U,): AssocConst {} //~^ ERROR associated const equality is incomplete //~| ERROR the type parameter `U` is not constrained by the impl trait diff --git a/tests/ui/const-generics/associated_const_equality/unconstrained_impl_param.stderr b/tests/ui/const-generics/associated_const_equality/unconstrained_impl_param.stderr index 4106c500215b..092faff93511 100644 --- a/tests/ui/const-generics/associated_const_equality/unconstrained_impl_param.stderr +++ b/tests/ui/const-generics/associated_const_equality/unconstrained_impl_param.stderr @@ -1,8 +1,8 @@ error[E0658]: associated const equality is incomplete --> $DIR/unconstrained_impl_param.rs:15:45 | -LL | impl Trait for () where (U,): AssocConst {} - | ^^^^^^^^^ +LL | impl Trait for () where (U,): AssocConst {} + | ^^^^^ | = note: see issue #92827 for more information = help: add `#![feature(associated_const_equality)]` to the crate attributes to enable @@ -11,7 +11,7 @@ LL | impl Trait for () where (U,): AssocConst {} error[E0207]: the type parameter `U` is not constrained by the impl trait, self type, or predicates --> $DIR/unconstrained_impl_param.rs:15:6 | -LL | impl Trait for () where (U,): AssocConst {} +LL | impl Trait for () where (U,): AssocConst {} | ^ unconstrained type parameter error[E0282]: type annotations needed diff --git a/tests/ui/const-generics/mgca/explicit_anon_consts.rs b/tests/ui/const-generics/mgca/explicit_anon_consts.rs new file mode 100644 index 000000000000..459282776266 --- /dev/null +++ b/tests/ui/const-generics/mgca/explicit_anon_consts.rs @@ -0,0 +1,70 @@ +#![feature(associated_const_equality, generic_const_items, min_generic_const_args)] +#![expect(incomplete_features)] + +struct Foo; + +type Adt1 = Foo; +type Adt2 = Foo<{ N }>; +type Adt3 = Foo; +//~^ ERROR: generic parameters may not be used in const operations +type Adt4 = Foo<{ 1 + 1 }>; +//~^ ERROR: complex const arguments must be placed inside of a `const` block +type Adt5 = Foo; + +type Arr = [(); N]; +type Arr2 = [(); { N }]; +type Arr3 = [(); const { N }]; +//~^ ERROR: generic parameters may not be used in const operations +type Arr4 = [(); 1 + 1]; +//~^ ERROR: complex const arguments must be placed inside of a `const` block +type Arr5 = [(); const { 1 + 1 }]; + +fn repeats() { + let _1 = [(); N]; + let _2 = [(); { N }]; + let _3 = [(); const { N }]; + //~^ ERROR: generic parameters may not be used in const operations + let _4 = [(); 1 + 1]; + //~^ ERROR: complex const arguments must be placed inside of a `const` block + let _5 = [(); const { 1 + 1 }]; +} + +#[type_const] +const ITEM1: usize = N; +#[type_const] +const ITEM2: usize = { N }; +#[type_const] +const ITEM3: usize = const { N }; +//~^ ERROR: generic parameters may not be used in const operations +#[type_const] +const ITEM4: usize = { 1 + 1 }; +//~^ ERROR: complex const arguments must be placed inside of a `const` block +#[type_const] +const ITEM5: usize = const { 1 + 1}; + +trait Trait { + #[type_const] + const ASSOC: usize; +} + +fn ace_bounds< + const N: usize, + // We skip the T1 case because it doesn't resolve + // T1: Trait, + T2: Trait, + T3: Trait, + //~^ ERROR: generic parameters may not be used in const operations + T4: Trait, + //~^ ERROR: complex const arguments must be placed inside of a `const` block + T5: Trait, +>() {} + +struct Default1; +struct Default2; +struct Default3; +//~^ ERROR: generic parameters may not be used in const operations +struct Default4; +//~^ ERROR: complex const arguments must be placed inside of a `const` block +struct Default5; + +fn main() {} diff --git a/tests/ui/const-generics/mgca/explicit_anon_consts.stderr b/tests/ui/const-generics/mgca/explicit_anon_consts.stderr new file mode 100644 index 000000000000..e4bf49c71efe --- /dev/null +++ b/tests/ui/const-generics/mgca/explicit_anon_consts.stderr @@ -0,0 +1,92 @@ +error: generic parameters may not be used in const operations + --> $DIR/explicit_anon_consts.rs:8:41 + | +LL | type Adt3 = Foo; + | ^ cannot perform const operation using `N` + | + = help: const parameters may only be used as standalone arguments here, i.e. `N` + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions + +error: generic parameters may not be used in const operations + --> $DIR/explicit_anon_consts.rs:16:42 + | +LL | type Arr3 = [(); const { N }]; + | ^ cannot perform const operation using `N` + | + = help: const parameters may only be used as standalone arguments here, i.e. `N` + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions + +error: generic parameters may not be used in const operations + --> $DIR/explicit_anon_consts.rs:25:27 + | +LL | let _3 = [(); const { N }]; + | ^ cannot perform const operation using `N` + | + = help: const parameters may only be used as standalone arguments here, i.e. `N` + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions + +error: generic parameters may not be used in const operations + --> $DIR/explicit_anon_consts.rs:37:46 + | +LL | const ITEM3: usize = const { N }; + | ^ cannot perform const operation using `N` + | + = help: const parameters may only be used as standalone arguments here, i.e. `N` + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions + +error: generic parameters may not be used in const operations + --> $DIR/explicit_anon_consts.rs:55:31 + | +LL | T3: Trait, + | ^ cannot perform const operation using `N` + | + = help: const parameters may only be used as standalone arguments here, i.e. `N` + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions + +error: generic parameters may not be used in const operations + --> $DIR/explicit_anon_consts.rs:64:58 + | +LL | struct Default3; + | ^ cannot perform const operation using `N` + | + = help: const parameters may only be used as standalone arguments here, i.e. `N` + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions + +error: complex const arguments must be placed inside of a `const` block + --> $DIR/explicit_anon_consts.rs:10:33 + | +LL | type Adt4 = Foo<{ 1 + 1 }>; + | ^^^^^^^^^ + +error: complex const arguments must be placed inside of a `const` block + --> $DIR/explicit_anon_consts.rs:18:34 + | +LL | type Arr4 = [(); 1 + 1]; + | ^^^^^ + +error: complex const arguments must be placed inside of a `const` block + --> $DIR/explicit_anon_consts.rs:27:19 + | +LL | let _4 = [(); 1 + 1]; + | ^^^^^ + +error: complex const arguments must be placed inside of a `const` block + --> $DIR/explicit_anon_consts.rs:40:38 + | +LL | const ITEM4: usize = { 1 + 1 }; + | ^^^^^^^^^ + +error: complex const arguments must be placed inside of a `const` block + --> $DIR/explicit_anon_consts.rs:57:23 + | +LL | T4: Trait, + | ^^^^^^^^^ + +error: complex const arguments must be placed inside of a `const` block + --> $DIR/explicit_anon_consts.rs:66:50 + | +LL | struct Default4; + | ^^^^^^^^^ + +error: aborting due to 12 previous errors + diff --git a/tests/ui/const-generics/mgca/explicit_anon_consts_literals_hack.rs b/tests/ui/const-generics/mgca/explicit_anon_consts_literals_hack.rs new file mode 100644 index 000000000000..979d10331a59 --- /dev/null +++ b/tests/ui/const-generics/mgca/explicit_anon_consts_literals_hack.rs @@ -0,0 +1,22 @@ +//@ check-pass + +// We allow for literals to implicitly be anon consts still regardless +// of whether a const block is placed around them or not + +#![feature(min_generic_const_args, associated_const_equality)] +#![expect(incomplete_features)] + +trait Trait { + #[type_const] + const ASSOC: isize; +} + +fn ace>() {} +fn repeat_count() { + [(); 1]; +} +type ArrLen = [(); 1]; +struct Foo; +type NormalArg = (Foo<1>, Foo<-1>); + +fn main() {} diff --git a/tests/ui/const-generics/mgca/multi_braced_direct_const_args.rs b/tests/ui/const-generics/mgca/multi_braced_direct_const_args.rs new file mode 100644 index 000000000000..31f54abf31ef --- /dev/null +++ b/tests/ui/const-generics/mgca/multi_braced_direct_const_args.rs @@ -0,0 +1,25 @@ +//@ check-pass + +#![feature(min_generic_const_args)] +#![expect(incomplete_features)] + +struct Foo; + +trait Trait { + #[type_const] + const ASSOC: usize; +} + +type Arr = [(); {{{ N }}}]; +type Arr2 = [(); {{{ ::ASSOC }}}]; +type Ty = Foo<{{{ N }}}>; +type Ty2 = Foo<{{{ ::ASSOC }}}>; +struct Default; +struct Default2::ASSOC }}}>(T); + +fn repeat() { + let _1 = [(); {{{ N }}}]; + let _2 = [(); {{{ ::ASSOC }}}]; +} + +fn main() {} diff --git a/tests/ui/const-generics/mgca/type_const-not-constparamty.rs b/tests/ui/const-generics/mgca/type_const-not-constparamty.rs index 27b446e6a40d..11db82187b84 100644 --- a/tests/ui/const-generics/mgca/type_const-not-constparamty.rs +++ b/tests/ui/const-generics/mgca/type_const-not-constparamty.rs @@ -4,9 +4,9 @@ struct S; // FIXME(mgca): need support for ctors without anon const -// (we use double-braces to trigger an anon const here) +// (we use a const-block to trigger an anon const here) #[type_const] -const FREE: S = { { S } }; +const FREE: S = const { S }; //~^ ERROR `S` must implement `ConstParamTy` to be used as the type of a const generic parameter trait Tr { @@ -17,9 +17,9 @@ trait Tr { impl Tr for S { // FIXME(mgca): need support for ctors without anon const - // (we use double-braces to trigger an anon const here) + // (we use a const-block to trigger an anon const here) #[type_const] - const N: S = { { S } }; + const N: S = const { S }; //~^ ERROR `S` must implement `ConstParamTy` to be used as the type of a const generic parameter } diff --git a/tests/ui/const-generics/mgca/type_const-not-constparamty.stderr b/tests/ui/const-generics/mgca/type_const-not-constparamty.stderr index 6b13917a95cd..d07bbde1e62e 100644 --- a/tests/ui/const-generics/mgca/type_const-not-constparamty.stderr +++ b/tests/ui/const-generics/mgca/type_const-not-constparamty.stderr @@ -1,7 +1,7 @@ error[E0741]: `S` must implement `ConstParamTy` to be used as the type of a const generic parameter --> $DIR/type_const-not-constparamty.rs:9:13 | -LL | const FREE: S = { { S } }; +LL | const FREE: S = const { S }; | ^ | help: add `#[derive(ConstParamTy, PartialEq, Eq)]` to the struct @@ -13,7 +13,7 @@ LL | struct S; error[E0741]: `S` must implement `ConstParamTy` to be used as the type of a const generic parameter --> $DIR/type_const-not-constparamty.rs:22:14 | -LL | const N: S = { { S } }; +LL | const N: S = const { S }; | ^ | help: add `#[derive(ConstParamTy, PartialEq, Eq)]` to the struct diff --git a/tests/ui/const-generics/mgca/type_const-on-generic-expr.rs b/tests/ui/const-generics/mgca/type_const-on-generic-expr.rs index d38d5ab7a59f..577fee084dbd 100644 --- a/tests/ui/const-generics/mgca/type_const-on-generic-expr.rs +++ b/tests/ui/const-generics/mgca/type_const-on-generic-expr.rs @@ -2,10 +2,10 @@ #![feature(min_generic_const_args, generic_const_items)] #[type_const] -const FREE1: usize = std::mem::size_of::(); +const FREE1: usize = const { std::mem::size_of::() }; //~^ ERROR generic parameters may not be used in const operations #[type_const] -const FREE2: usize = I + 1; +const FREE2: usize = const { I + 1 }; //~^ ERROR generic parameters may not be used in const operations pub trait Tr { @@ -21,13 +21,13 @@ pub struct S; impl Tr for S { #[type_const] - const N1: usize = std::mem::size_of::(); + const N1: usize = const { std::mem::size_of::() }; //~^ ERROR generic parameters may not be used in const operations #[type_const] - const N2: usize = I + 1; + const N2: usize = const { I + 1 }; //~^ ERROR generic parameters may not be used in const operations #[type_const] - const N3: usize = 2 & X; + const N3: usize = const { 2 & X }; //~^ ERROR generic parameters may not be used in const operations } diff --git a/tests/ui/const-generics/mgca/type_const-on-generic-expr.stderr b/tests/ui/const-generics/mgca/type_const-on-generic-expr.stderr index 76638f27e96c..8cef77e5b229 100644 --- a/tests/ui/const-generics/mgca/type_const-on-generic-expr.stderr +++ b/tests/ui/const-generics/mgca/type_const-on-generic-expr.stderr @@ -1,44 +1,44 @@ error: generic parameters may not be used in const operations - --> $DIR/type_const-on-generic-expr.rs:5:45 + --> $DIR/type_const-on-generic-expr.rs:5:53 | -LL | const FREE1: usize = std::mem::size_of::(); - | ^ cannot perform const operation using `T` +LL | const FREE1: usize = const { std::mem::size_of::() }; + | ^ cannot perform const operation using `T` | = note: type parameters may not be used in const expressions = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations - --> $DIR/type_const-on-generic-expr.rs:8:38 + --> $DIR/type_const-on-generic-expr.rs:8:46 | -LL | const FREE2: usize = I + 1; - | ^ cannot perform const operation using `I` +LL | const FREE2: usize = const { I + 1 }; + | ^ cannot perform const operation using `I` | = help: const parameters may only be used as standalone arguments here, i.e. `I` = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations - --> $DIR/type_const-on-generic-expr.rs:24:46 + --> $DIR/type_const-on-generic-expr.rs:24:54 | -LL | const N1: usize = std::mem::size_of::(); - | ^ cannot perform const operation using `T` +LL | const N1: usize = const { std::mem::size_of::() }; + | ^ cannot perform const operation using `T` | = note: type parameters may not be used in const expressions = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations - --> $DIR/type_const-on-generic-expr.rs:27:39 + --> $DIR/type_const-on-generic-expr.rs:27:47 | -LL | const N2: usize = I + 1; - | ^ cannot perform const operation using `I` +LL | const N2: usize = const { I + 1 }; + | ^ cannot perform const operation using `I` | = help: const parameters may only be used as standalone arguments here, i.e. `I` = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations - --> $DIR/type_const-on-generic-expr.rs:30:27 + --> $DIR/type_const-on-generic-expr.rs:30:35 | -LL | const N3: usize = 2 & X; - | ^ cannot perform const operation using `X` +LL | const N3: usize = const { 2 & X }; + | ^ cannot perform const operation using `X` | = help: const parameters may only be used as standalone arguments here, i.e. `X` = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions diff --git a/tests/ui/const-generics/mgca/unbraced_const_block_const_arg_gated.rs b/tests/ui/const-generics/mgca/unbraced_const_block_const_arg_gated.rs new file mode 100644 index 000000000000..588fa2f913b6 --- /dev/null +++ b/tests/ui/const-generics/mgca/unbraced_const_block_const_arg_gated.rs @@ -0,0 +1,42 @@ +#![feature(adt_const_params)] + +#[derive(Eq, PartialEq, std::marker::ConstParamTy)] +struct Inner; + +struct Foo< + const PARAM_TY: Inner, + //~^ ERROR: unbraced const blocks as const args are experimental + const DEFAULT: usize = const { 1 }, + //~^ ERROR: unbraced const blocks as const args are experimental +>; + +type Array = [(); const { 1 }]; +type NormalTy = Inner; + //~^ ERROR: unbraced const blocks as const args are experimental + +fn repeat() { + [1_u8; const { 1 }]; +} + +fn body_ty() { + let _: Inner; + //~^ ERROR: unbraced const blocks as const args are experimental +} + +fn generic() { + if false { + generic::(); + //~^ ERROR: unbraced const blocks as const args are experimental + } +} + +const NON_TYPE_CONST: usize = const { 1 }; + +#[type_const] +//~^ ERROR: the `#[type_const]` attribute is an experimental feature +const TYPE_CONST: usize = const { 1 }; +//~^ ERROR: unbraced const blocks as const args are experimental + +static STATIC: usize = const { 1 }; + +fn main() {} diff --git a/tests/ui/const-generics/mgca/unbraced_const_block_const_arg_gated.stderr b/tests/ui/const-generics/mgca/unbraced_const_block_const_arg_gated.stderr new file mode 100644 index 000000000000..30509ddf9b46 --- /dev/null +++ b/tests/ui/const-generics/mgca/unbraced_const_block_const_arg_gated.stderr @@ -0,0 +1,73 @@ +error[E0658]: unbraced const blocks as const args are experimental + --> $DIR/unbraced_const_block_const_arg_gated.rs:7:33 + | +LL | const PARAM_TY: Inner, + | ^^^^^ + | + = note: see issue #132980 for more information + = help: add `#![feature(min_generic_const_args)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: unbraced const blocks as const args are experimental + --> $DIR/unbraced_const_block_const_arg_gated.rs:9:34 + | +LL | const DEFAULT: usize = const { 1 }, + | ^^^^^ + | + = note: see issue #132980 for more information + = help: add `#![feature(min_generic_const_args)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: unbraced const blocks as const args are experimental + --> $DIR/unbraced_const_block_const_arg_gated.rs:14:29 + | +LL | type NormalTy = Inner; + | ^^^^^ + | + = note: see issue #132980 for more information + = help: add `#![feature(min_generic_const_args)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: unbraced const blocks as const args are experimental + --> $DIR/unbraced_const_block_const_arg_gated.rs:22:24 + | +LL | let _: Inner; + | ^^^^^ + | + = note: see issue #132980 for more information + = help: add `#![feature(min_generic_const_args)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: unbraced const blocks as const args are experimental + --> $DIR/unbraced_const_block_const_arg_gated.rs:28:25 + | +LL | generic::(); + | ^^^^^ + | + = note: see issue #132980 for more information + = help: add `#![feature(min_generic_const_args)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: unbraced const blocks as const args are experimental + --> $DIR/unbraced_const_block_const_arg_gated.rs:37:33 + | +LL | const TYPE_CONST: usize = const { 1 }; + | ^^^^^ + | + = note: see issue #132980 for more information + = help: add `#![feature(min_generic_const_args)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the `#[type_const]` attribute is an experimental feature + --> $DIR/unbraced_const_block_const_arg_gated.rs:35:1 + | +LL | #[type_const] + | ^^^^^^^^^^^^^ + | + = note: see issue #132980 for more information + = help: add `#![feature(min_generic_const_args)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 7 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/const-generics/mgca/using-fnptr-as-type_const.rs b/tests/ui/const-generics/mgca/using-fnptr-as-type_const.rs index 554e078ccd49..d97b3a9f0929 100644 --- a/tests/ui/const-generics/mgca/using-fnptr-as-type_const.rs +++ b/tests/ui/const-generics/mgca/using-fnptr-as-type_const.rs @@ -9,6 +9,6 @@ trait Trait { //~^ ERROR using function pointers as const generic parameters is forbidden } -fn take(_: impl Trait) {} +fn take(_: impl Trait) {} fn main() {} diff --git a/tests/ui/generic-const-items/assoc-const-no-infer-ice-115806.rs b/tests/ui/generic-const-items/assoc-const-no-infer-ice-115806.rs index 7f4926fa2b71..a72aaedb980e 100644 --- a/tests/ui/generic-const-items/assoc-const-no-infer-ice-115806.rs +++ b/tests/ui/generic-const-items/assoc-const-no-infer-ice-115806.rs @@ -9,12 +9,12 @@ impl Pins for NoPin {} pub trait PinA { #[type_const] - const A: &'static () = &(); + const A: &'static () = const { &() }; } pub trait Pins {} -impl Pins for T where T: PinA {} +impl Pins for T where T: PinA {} //~^ ERROR conflicting implementations of trait `Pins<_>` for type `NoPin` pub fn main() {} diff --git a/tests/ui/generic-const-items/assoc-const-no-infer-ice-115806.stderr b/tests/ui/generic-const-items/assoc-const-no-infer-ice-115806.stderr index 34546349592f..f57fd74ad99d 100644 --- a/tests/ui/generic-const-items/assoc-const-no-infer-ice-115806.stderr +++ b/tests/ui/generic-const-items/assoc-const-no-infer-ice-115806.stderr @@ -4,8 +4,8 @@ error[E0119]: conflicting implementations of trait `Pins<_>` for type `NoPin` LL | impl Pins for NoPin {} | --------------------------- first implementation here ... -LL | impl Pins for T where T: PinA {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `NoPin` +LL | impl Pins for T where T: PinA {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `NoPin` | = note: downstream crates may implement trait `PinA<_>` for type `NoPin` diff --git a/tests/ui/generic-const-items/associated-const-equality.rs b/tests/ui/generic-const-items/associated-const-equality.rs index 6f5d4985ae53..37cf381e6824 100644 --- a/tests/ui/generic-const-items/associated-const-equality.rs +++ b/tests/ui/generic-const-items/associated-const-equality.rs @@ -17,7 +17,7 @@ impl Owner for () { #[type_const] const C: u32 = N; #[type_const] - const K: u32 = 99 + 1; + const K: u32 = const { 99 + 1 }; // FIXME(mgca): re-enable once we properly support ctors and generics on paths // #[type_const] // const Q: Maybe = Maybe::Nothing;