Spec-Zone.ru › GCC 15

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++23 assume, который можно использовать в любой версии 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 либо атрибут GNU musttail можно применить к оператору 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

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API