Странный синтаксис конструкции и деструктора в GCC & clang (void * return type) - PullRequest
0 голосов
/ 04 ноября 2018

При написании кода на C ++ (компилирование с использованием clang, x86_64 linux) я случайно написал следующую конструкцию:

class Class {
    *Class() {}
};

т.е. со звездочкой (*) перед именем конструктора.

Пытаясь немного больше, я заметил, что вы можете поставить произвольное количество * впереди; и это также работает для деструкторов, т. е.

class Class {
    ********Class() {}
    ********~Class() {}
};

Clang компилирует его без ошибок и предупреждений.

GCC однако выдает предупреждение

управление достигает конца не пустой функции

, что наводит меня на мысль, что я на самом деле объявляю конструктор / деструктор с типом возврата void* (или void********). И написание любого типа оператора возврата со значением дает ошибку (как и ожидалось):

return nullptr;
return {};
...

Интересно, что сгенерированный битовый код LLVM IR правильно содержит функцию void:

define void @_ZN5ClassC2Ev(%struct.Class* %this) {...}
define void @_ZN5ClassD2Ev(%struct.Class* %this) {...}

Поиск любой информации по этому вопросу не дал никаких результатов. Итак, мой вопрос: соответствует ли этот стандарт C ++ или ошибка во внешнем интерфейсе компилятора GCC & Clang? Или, может быть, какая-то функция совместимости? Если правильно, то какой вариант использования для этого.

1 Ответ

0 голосов
/ 04 ноября 2018

Похоже, ошибка. Потому что это не соответствует стандартам. Стандартный способ объявления или определения конструктора - [class.ctor] / 1 :

Конструкторы не имеют имен. В объявлении конструктора Объявление - это функция объявления в форме

ptr-declarator ( parameter-declaration-clause ) noexcept-specifier<sub>opt</sub> attribute-specifier-seq<sub>opt</sub>

, где ptr-декларатор состоит исключительно из id-выражения , необязательный атрибут-спецификатор-seq и необязательное окружение круглые скобки, а id-выражение имеет одну из следующих форм:

  • в объявлении члена, которое принадлежит спецификации члена класса, но не является объявлением друга, id-выражение является injected-class-name класса, включающего сразу;
  • в объявлении члена, которое принадлежит спецификации члена шаблона класса, но не является объявлением друга, id-выражение имеет вид имя класса, которое называет текущее создание экземпляра немедленно включающий шаблон класса; или
  • в объявлении в области пространства имен или в объявлении друга, id-выражение - это квалифицированный идентификатор, который присваивает имя конструктору ([Class.qual]).

Имя класса не должно быть именем типа определения. В конструкторе объявление, каждый decl-спецификатор в необязательном decl-specier-seq должен быть другом, встроенным, явным или constexpr.

Как вы можете видеть в части, которую я подчеркнул, ptr-declarator должно быть только id-выражением. Или в более простых и немного менее точных терминах, это должно быть просто имя класса.

Так почему вы можете добавить звездочку в Clang и GCC? Казалось бы, у них есть ошибка, и здесь не применяются семантические ограничения для ptr-declarator. Эти ограничения важны, потому что чистая грамматика допускает звездочку. Он находится в [dcl.decl] / 4 (скопировано только частично):

Деклараторы имеют синтаксис

ptr-declarator:
    noptr-declarator
    ptr-operator ptr-declarator

ptr-operator:
    * attribute-specifier-seq<sub>opt</sub> cv-qualifier-seq<sub>opt</sub>
    & attribute-specifier-seq<sub>opt</sub>
    && attribute-specifier-seq<sub>opt</sub>
    nested-name-specifier * attribute-specifier-seq<sub>opt</sub> cv-qualifier-seq<sub>opt</sub>

Видите, что ptr-operator бит синтаксиса? Это то, что говорит, что * может появиться там, где вы его положили. Или & и даже &&. Но семантика, помещенная в декларацию, в первом абзаце, который я привел, делает его незаконным.

Итак, нужно сделать вывод, что это ошибка в GCC и Clang.

...