1#[derive(Clone, Copy, PartialEq, Eq, Debug)]
20pub enum Attribute {
21 Noreturn,
23 AlwaysInline,
25 NoInline,
27 Cold,
29 Hot,
31 Deprecated,
33 Fallthrough,
36 Packed,
38 Aligned,
40 Section,
42 Target,
45 Constructor,
47 Destructor,
49 Cleanup,
51 Mode,
53 Safe,
56 Weak,
61 Unsupported,
64 Ignored,
67}
68
69pub const UNSUPPORTED_ATTRIBUTES: &[(&str, &str)] = &[
74 (
75 "weakref",
76 "is not supported: Rust's `#[linkage]` is unstable, so weak linkage cannot be asked for",
77 ),
78 (
79 "alias",
80 "is not supported: write a function that forwards to the other one instead",
81 ),
82 (
83 "ifunc",
84 "is not supported: choosing an implementation at load time has no stable Rust counterpart",
85 ),
86 (
87 "vector_size",
88 "is not supported: the vector extensions need `core::simd`, which is unstable. \
89 The Intel intrinsics are the SIMD cinrs has: <immintrin.h> declares them and a call \
90 becomes the `core::arch` function of the same name",
91 ),
92 (
93 "scalar_storage_order",
94 "is not supported: it reverses the byte order of every scalar in the record, and \
95 nothing in the generated Rust could carry that",
96 ),
97];
98
99pub fn attribute(name: &str) -> Option<Attribute> {
102 let bare = name
103 .strip_prefix("__")
104 .and_then(|rest| rest.strip_suffix("__"))
105 .unwrap_or(name);
106 if UNSUPPORTED_ATTRIBUTES.iter().any(|(n, _)| *n == bare) {
107 return Some(Attribute::Unsupported);
108 }
109 Some(match bare {
110 "noreturn" => Attribute::Noreturn,
111 "always_inline" => Attribute::AlwaysInline,
112 "noinline" => Attribute::NoInline,
113 "cold" => Attribute::Cold,
114 "hot" => Attribute::Hot,
115 "deprecated" => Attribute::Deprecated,
116 "fallthrough" => Attribute::Fallthrough,
117 "packed" => Attribute::Packed,
118 "aligned" | "alignas" => Attribute::Aligned,
119 "section" => Attribute::Section,
120 "target" => Attribute::Target,
121 "constructor" => Attribute::Constructor,
122 "destructor" => Attribute::Destructor,
123 "cleanup" => Attribute::Cleanup,
124 "mode" => Attribute::Mode,
125 "weak" => Attribute::Weak,
126 "cinrs_safe" => Attribute::Safe,
129 _ if IGNORED_ATTRIBUTES.contains(&bare) => Attribute::Ignored,
130 _ => return None,
131 })
132}
133
134pub const CINRS_ATTRIBUTES: &[&str] = &["safe"];
141
142pub fn cinrs_attribute(name: &str) -> Option<Attribute> {
147 match name {
148 "safe" => Some(Attribute::Safe),
149 _ => None,
150 }
151}
152
153pub fn unsupported_reason(name: &str) -> Option<&'static str> {
155 let bare = name
156 .strip_prefix("__")
157 .and_then(|rest| rest.strip_suffix("__"))
158 .unwrap_or(name);
159 UNSUPPORTED_ATTRIBUTES
160 .iter()
161 .find(|(n, _)| *n == bare)
162 .map(|(_, reason)| *reason)
163}
164
165const IGNORED_ATTRIBUTES: &[&str] = &[
168 "access",
169 "alloc_align",
170 "alloc_size",
171 "artificial",
172 "assume_aligned",
173 "cdecl",
174 "const",
175 "designated_init",
176 "error",
177 "externally_visible",
178 "fastcall",
179 "flatten",
180 "format",
181 "format_arg",
182 "gnu_inline",
183 "leaf",
184 "malloc",
185 "may_alias",
186 "maybe_unused",
187 "no_instrument_function",
188 "no_sanitize",
189 "no_split_stack",
190 "noclone",
191 "nodiscard",
192 "noipa",
193 "nonnull",
194 "nonstring",
195 "nothrow",
196 "optimize",
197 "pure",
198 "reproducible",
199 "returns_nonnull",
200 "returns_twice",
201 "sentinel",
202 "stdcall",
203 "target_clones",
204 "transparent_union",
205 "unavailable",
206 "unsequenced",
207 "unused",
208 "used",
209 "visibility",
210 "warn_unused_result",
211 "warning",
212];
213
214pub fn has_attribute(name: &str) -> bool {
223 attribute(name).is_some_and(|a| !matches!(a, Attribute::Unsupported | Attribute::Weak))
224}
225
226pub fn has_c_attribute(name: &str) -> u64 {
232 let standard = matches!(
233 name,
234 "deprecated"
235 | "fallthrough"
236 | "maybe_unused"
237 | "nodiscard"
238 | "noreturn"
239 | "unsequenced"
240 | "reproducible"
241 );
242 if standard { 202_311 } else { 0 }
243}
244
245pub fn has_builtin(name: &str) -> bool {
251 if crate::sema::is_atomic_builtin(name) {
252 return true;
253 }
254 let Some(rest) = name.strip_prefix("__builtin_") else {
255 return false;
256 };
257 SPECIAL_BUILTINS.contains(&rest)
258 || LIBRARY_BUILTINS.contains(&rest)
259 || long_double_math(rest).is_some()
260}
261
262pub fn has_feature(name: &str) -> bool {
273 SUPPORTED_FEATURES.contains(&name)
274}
275
276const SUPPORTED_FEATURES: &[&str] = &[
278 "c_alignas",
279 "c_alignof",
280 "c_atomic",
281 "c_attributes",
282 "c_generic_selection",
283 "c_generic_selections",
284 "c_static_assert",
285 "cinrs",
286];
287
288pub const SPECIAL_BUILTINS: &[&str] = &[
293 "add_overflow",
294 "add_overflow_p",
295 "alloca",
296 "alloca_with_align",
297 "assume",
298 "assume_aligned",
299 "bswap16",
300 "bswap32",
301 "bswap64",
302 "choose_expr",
303 "cimag",
304 "cimagf",
305 "cimagl",
306 "classify_type",
307 "clrsb",
308 "clrsbl",
309 "clrsbll",
310 "clz",
311 "clzl",
312 "clzll",
313 "complex",
314 "conj",
315 "conjf",
316 "conjl",
317 "constant_p",
318 "copysign",
319 "copysignf",
320 "copysignl",
321 "cpu_init",
326 "cpu_supports",
327 "cproj",
328 "cprojf",
329 "cprojl",
330 "creal",
331 "crealf",
332 "creall",
333 "ctz",
334 "ctzl",
335 "ctzll",
336 "dynamic_object_size",
337 "expect",
338 "expect_with_probability",
339 "fabs",
340 "fabsf",
341 "fabsl",
342 "ffs",
343 "ffsl",
344 "ffsll",
345 "fpclassify",
346 "huge_val",
347 "huge_valf",
348 "huge_valf32",
349 "huge_valf32x",
350 "huge_valf64",
351 "huge_valf64x",
352 "huge_vall",
353 "inf",
354 "inff",
355 "inff32",
356 "inff32x",
357 "inff64",
358 "inff64x",
359 "infl",
360 "isfinite",
361 "isgreater",
362 "isgreaterequal",
363 "isinf",
364 "isinf_sign",
365 "isinff",
366 "isinfl",
367 "isless",
368 "islessequal",
369 "islessgreater",
370 "isnan",
371 "isnanf",
372 "isnanl",
373 "isnormal",
374 "issignaling",
375 "isunordered",
376 "mul_overflow",
377 "mul_overflow_p",
378 "nan",
379 "nanf",
380 "nanf32",
381 "nanf32x",
382 "nanf64",
383 "nanf64x",
384 "nanl",
385 "nans",
386 "nansf",
387 "nansf32",
388 "nansf32x",
389 "nansf64",
390 "nansf64x",
391 "nansl",
392 "object_size",
393 "offsetof",
394 "parity",
395 "parityl",
396 "parityll",
397 "popcount",
398 "popcountl",
399 "popcountll",
400 "prefetch",
401 "signbit",
402 "signbitf",
403 "signbitl",
404 "sub_overflow",
405 "sub_overflow_p",
406 "trap",
407 "types_compatible_p",
408 "unreachable",
409 "va_arg",
410 "va_copy",
411 "va_end",
412 "va_start",
413 "FILE",
414 "FUNCTION",
415 "LINE",
416];
417
418pub fn long_double_math(rest: &str) -> Option<&'static str> {
426 let base = rest.strip_suffix('l')?;
427 LONG_DOUBLE_MATH.iter().copied().find(|name| *name == base)
428}
429
430const LONG_DOUBLE_MATH: &[&str] = &[
435 "acos",
436 "asin",
437 "atan",
438 "atan2",
439 "cbrt",
440 "ceil",
441 "cos",
442 "cosh",
443 "erf",
444 "erfc",
445 "exp",
446 "exp2",
447 "expm1",
448 "fdim",
449 "floor",
450 "fma",
451 "fmax",
452 "fmin",
453 "fmod",
454 "frexp",
455 "hypot",
456 "ldexp",
457 "lgamma",
458 "log",
459 "log10",
460 "log1p",
461 "log2",
462 "modf",
463 "nearbyint",
464 "nextafter",
465 "pow",
466 "remainder",
467 "rint",
468 "round",
469 "scalbn",
470 "sin",
471 "sinh",
472 "sqrt",
473 "tan",
474 "tanh",
475 "tgamma",
476 "trunc",
477];
478
479pub fn typed_overflow(rest: &str) -> Option<&'static str> {
485 let rest = rest.strip_prefix('s').or_else(|| rest.strip_prefix('u'))?;
486 let (op, rest) = if let Some(rest) = rest.strip_prefix("add") {
487 ("add", rest)
488 } else if let Some(rest) = rest.strip_prefix("sub") {
489 ("sub", rest)
490 } else {
491 ("mul", rest.strip_prefix("mul")?)
492 };
493 matches!(rest, "_overflow" | "l_overflow" | "ll_overflow").then_some(op)
494}
495
496pub const LIBRARY_BUILTINS: &[&str] = &[
502 "_Exit",
503 "abort",
504 "abs",
505 "acos",
506 "acosf",
507 "asin",
508 "asinf",
509 "atan",
510 "atan2",
511 "atan2f",
512 "atanf",
513 "atof",
514 "atoi",
515 "atol",
516 "atoll",
517 "bcmp",
518 "bcopy",
519 "bzero",
520 "calloc",
521 "cbrt",
522 "cbrtf",
523 "ceil",
524 "ceilf",
525 "cos",
526 "cosf",
527 "cosh",
528 "coshf",
529 "erf",
530 "erfc",
531 "exit",
532 "exp",
533 "exp2",
534 "exp2f",
535 "expf",
536 "expm1",
537 "expm1f",
538 "fdim",
539 "fdimf",
540 "floor",
541 "floorf",
542 "fma",
543 "fmaf",
544 "fmax",
545 "fmaxf",
546 "fmin",
547 "fminf",
548 "fmod",
549 "fmodf",
550 "fprintf",
551 "fputc",
552 "fputs",
553 "free",
554 "frexp",
555 "frexpf",
556 "hypot",
557 "hypotf",
558 "imaxabs",
559 "index",
560 "isalnum",
561 "isalpha",
562 "isblank",
563 "iscntrl",
564 "isdigit",
565 "isgraph",
566 "islower",
567 "isprint",
568 "ispunct",
569 "isspace",
570 "isupper",
571 "isxdigit",
572 "labs",
573 "ldexp",
574 "ldexpf",
575 "lgamma",
576 "llabs",
577 "log",
578 "log10",
579 "log10f",
580 "log1p",
581 "log1pf",
582 "log2",
583 "log2f",
584 "logf",
585 "malloc",
586 "memchr",
587 "memcmp",
588 "memcpy",
589 "memmove",
590 "mempcpy",
591 "memset",
592 "modf",
593 "modff",
594 "nearbyint",
595 "nearbyintf",
596 "nextafter",
597 "nextafterf",
598 "pow",
599 "powf",
600 "printf",
601 "putchar",
602 "puts",
603 "realloc",
604 "remainder",
605 "remainderf",
606 "rindex",
607 "rint",
608 "rintf",
609 "round",
610 "roundf",
611 "scalbn",
612 "scalbnf",
613 "sin",
614 "sinf",
615 "sinh",
616 "sinhf",
617 "snprintf",
618 "sprintf",
619 "sqrt",
620 "sqrtf",
621 "stpcpy",
622 "stpncpy",
623 "strcasecmp",
624 "strcat",
625 "strchr",
626 "strcmp",
627 "strcoll",
628 "strcpy",
629 "strcspn",
630 "strdup",
631 "strlen",
632 "strncasecmp",
633 "strncat",
634 "strncmp",
635 "strncpy",
636 "strpbrk",
637 "strrchr",
638 "strspn",
639 "strstr",
640 "strtod",
641 "strtof",
642 "strtol",
643 "strtoll",
644 "strtoul",
645 "strtoull",
646 "tan",
647 "tanf",
648 "tanh",
649 "tanhf",
650 "tgamma",
651 "tolower",
652 "toupper",
653 "trunc",
654 "truncf",
655];