6.4.6 Атрибуты операторов
GCC позволяет задавать атрибуты для операторов. Подробнее о точном синтаксисе использования атрибутов см. в разделе Синтаксис атрибутов. Другие атрибуты доступны для функций (см. Объявление атрибутов функций), переменных (см. Задание атрибутов переменных), меток (см. Атрибуты меток), перечислителей (см. Атрибуты перечислителей) и типов (см. Задание атрибутов типов).
-
fallthrough -
Атрибут
fallthroughс пустым оператором служит оператором передачи управления. Он сообщает компилятору, что переход к следующей метке варианта или пользовательской метке в операторе switch является преднамеренным, поэтому предупреждение -Wimplicit-fallthrough не должно выдаваться. Атрибут fallthrough может встречаться не более одного раза в каждом списке атрибутов и не может сочетаться с другими атрибутами. Его можно использовать только в операторе switch (в противном случае компилятор выдаст ошибку), после предшествующего оператора и перед логически следующим вариантом или пользовательской меткой.В этом примере атрибут оператора
fallthroughиспользуется, чтобы указать, что предупреждение -Wimplicit-fallthrough не следует выдавать:switch (cond) { case 1: bar (1); __attribute__((fallthrough)); case 2: … } -
assume -
Атрибут
assumeс пустым оператором служит переносимым предположением. Он должен иметь один аргумент — условное выражение, которое не вычисляется. Если в точке его появления аргумент дал бы значение true, атрибут не оказывает никакого действия; в противном случае поведение не определено. Это вариант GNU стандартного атрибута ISO C++23assume, который можно использовать в любой версии C и C++.int foo (int x, int y) { __attribute__((assume(x == 42))); __attribute__((assume(++y == 43))); return x + y; }yфактически не увеличивается, и компилятор может, но не обязан, оптимизировать его до простогоreturn 42 + 42;. -
musttail -
Стандартный атрибут
gnu::musttailилиclang::musttailлибо атрибут GNUmusttailможно применить к операторуreturnс выражением возвращаемого значения, представляющим собой вызов функции. Он утверждает, что вызов должен быть хвостовым вызовом, не выделяющим дополнительное пространство в стеке, поэтому для реализации длительно работающих циклов безопасно использовать хвостовую рекурсию.[[gnu::musttail]] return foo();
__attribute__((musttail)) return bar();
Если компилятор не может сгенерировать хвостовой вызов
musttail, он сообщает об ошибке. На некоторых целевых платформах хвостовые вызовы могут вообще не поддерживаться. Атрибутmusttailутверждает, что время жизни автоматических переменных, параметров функции и временных объектов (если их уничтожение не является нетривиальным) может завершиться до фактической инструкции вызова, а любой доступ к ним из вызываемой функции считается поведением, не определённым стандартом. Включение -O1 или -O2 может повысить вероятность успешной генерации хвостовых вызовов.int foo (int *); void bar (int *); struct S { S (); ~S (); int s; }; int baz (int *x) { if (*x == 1) { int a = 42; /* The call is a tail call (would not be without the attribute). Dereferencing the pointer in the callee is undefined behavior, and there is a warning emitted for this by default (-Wmusttail-local-addr). */ [[gnu::musttail]] return foo (&a); } else if (*x == 2) { int a = 42; bar (&a); /* The call is a tail call (would not be without the attribute). If bar stores the pointer anywhere, dereferencing it in foo is undefined behavior. There is a warning emitted for this with -Wextra, which implies -Wmaybe-musttail-local-addr. */ [[gnu::musttail]] return foo (nullptr); } else { S s; /* The s variable requires non-trivial destruction which ought to be performed after the foo call returns, so this is rejected. */ [[gnu::musttail]] return foo (&s.s); } }Чтобы избежать предупреждения -Wmaybe-musttail-local-addr в приведённом выше случае
*x == 2и в аналогичном коде, рассмотрите возможность объявить переменные, которые могут экранировать, в отдельной области видимости, заканчивающейся до оператора return. Если это возможно, так будет ясно, что переменная не используется во время вызова. Итак:else if (*x == 2) { { int a = 42; bar (&a); } /* The call is a tail call (would not be without the attribute). If bar stores the pointer anywhere, dereferencing it in foo is undefined behavior even without tail call optimization, and there is no warning. */ [[gnu::musttail]] return foo (nullptr); }Таким способом нельзя избежать предупреждения, если переменная, которая может экранировать, является аргументом функции, поскольку аргументы находятся в области видимости на протяжении всей функции.
© Free Software Foundation
Licensed under the GNU Free Documentation License, Version 1.3.
https://gcc.gnu.org/onlinedocs/gcc-15.3.0/gcc/Statement-Attributes.html