LINUX.ORG.RU

Как объяснить GCC, что switch полный?

 , ,


0

4

Имеем:

enum class MyEnum
{
   One,
   Two,
}

QString myfunc(const MyEnum e)
{
    switch (e) {
        case MyEnum:One : return "One";
        case MyEnum:Two : return "Two";
    }
}
* код не запускал

GCC 5.4.0 с радостью вещает мне, что:

warning: control reaches end of non-void function [-Wreturn-type]

При том, что clang обрабатывает верно.

Как убрать этот варнинг без глобального флага и без #pragma GCC diagnostic ignored "-Wreturn-type"?



Последнее исправление: RazrFalcon (всего исправлений: 2)

Как объяснить GCC, что switch полный?

Эмм.. так у тебя return по-дефолту не прописан, для случая если там будет нечто кроме «one» или «two»

Либо тебе тут вообще не нужен свитч.

devl547 👍👍
()
Ответ на: комментарий от pftBest

Этот баг будет в рантайме, и он будет сидеть и ждать дня, когда вы наконец-то отдадите ваш чудесный код в продакшн, после чего он благополучно появится, обрушит ваш сервер и уведёт клиента к другому поставщику услуг. Умные дядьки для этого научили конпеляторы делать проверки на этапе конпеляции.

jcd
()
enum class MyEnum
{
   One,
   Two,
}

QString myfunc(const MyEnum e)
{
    switch (e) {
        case MyEnum:One :return "One";

        case MyEnum:Two :
        default :
            return "Two";
    }
}

починил

SZT
()
Ответ на: комментарий от jcd

Для того, чтобы такого не происходило, умные дядьки придумали языки программирования с нормальными системами типов.

Softwayer
()
Ответ на: комментарий от Softwayer

ну нету энумов настоящих, зато удобно битмаски из них делать

в крайнем случае всегда есть reinterpret_cast

а добавить рантайм чеки - взвоют что прогнулись под хипстеров

anonymous
()

В стандарте есть:

96) This set of values is used to define promotion and conversion semantics for the enumeration type. It does not preclude an expression of enumeration type from having a value that falls outside this range.

И нигде ничего про undefined-behaviour. А std::byte определён просто как:

enum class byte : unsigned char {};

Похоже, что GCC прав и стоит использовать __builtin_unreachable() (и возможно перед ним поставить assert()).

xaizek
()
Ответ на: комментарий от SZT

unreachable в default делает своё дело, но это всё равно костыль, имхо. clang-то понимает это.

RazrFalcon
() автор топика
Ответ на: комментарий от devl547

Она там и не нужен, ибо другого значения быть не может (в теории может, естественно).

RazrFalcon
() автор топика
Ответ на: комментарий от jcd

Толку от компилятора, если всё равно unreachable? Ну или throw/abort.

RazrFalcon
() автор топика
Ответ на: комментарий от anonymous

Во-первых, настоящих енумов не было последние 40+ лет, и enum class преподносился как попытка их завезти — но если не видно разницы, зачем ещё одна конструкция в языке?

Во-вторых, если бы для этого был необходим reinterpret_cast, это можно было бы понять: на то он и небезопасный каст, чтобы с его помощью можно было сломать некоторые разумные инварианты, но ведь для каста числа к такому енуму достаточно static_cast, что выглядит совершенно неразумно.

Softwayer
()
Ответ на: комментарий от xaizek

Пичаль. Придётся городить костыль.

В гугле пугают, что default может повлиять на производительность. Мне особо не важно, но сам факт.

RazrFalcon
() автор топика
Ответ на: комментарий от RazrFalcon

Если у тебя может быть там только one или two, то почему б тупо не ограничится

QString myfunc(const MyEnum e)
{
    if (e == MyEnum:One)
    {
        return "One";
    }
    return "Two";
}
и на этом закончить?

SZT
()
Ответ на: комментарий от Softwayer

В сишке тоже самое, но без длинных слов, ака c-style cast.

Просто меня в своё время сильно удивило, что все «гарантии» const не имеют смысла, ибо ломаются простым кастом.

RazrFalcon
() автор топика
Ответ на: комментарий от RazrFalcon

Если там может быть что угодно, то конечно же switch должен в своих case или покрывать все возможные варианты, или в default должно быть что-то типа

cerr << "error blah-blah unexpected crap!\n";
exit (-1);

SZT
()

Ну поставь в конце функции return. Что ты теряешь-то?
Мне кажется что ты слишком много хочешь от компилятора.

MimisGotAPlan
()
Ответ на: комментарий от SZT

Делать в плюсовом коде exit — это довольно интересный дизайн

Softwayer
()
Ответ на: комментарий от SZT

Нее, default не катит. Если добавить default: unreachable, то тогда компилятор не проверяет, что все значения enum'а были использованы.

В общем втыкнул Q_UNREACHABLE(); в конец метода и дело с концом.

RazrFalcon
() автор топика
enum class MyEnum
{
   One,
   Two,
}

QString myfunc(const MyEnum e)
{
    switch (e) {
        case MyEnum:One : return "One";
        case MyEnum:Two : return "Two";
    }
}

int main()
{
    int arbitraryValue = 12345;
    auto result = myfunc((MyEnum)arbitraryValue); // we have trouble
    return 0;
}
andreyu
()
Ответ на: комментарий от MimisGotAPlan

Помнится мне, что некоторые версии компиляторов ругались, если не видели в конце функции return, хотя туда управление никак не могло дойти. Switch-case со всеми вариантами + default. А другие версии компиляторов ругались, если в конце такой функции был return. Всем не угодишь.

i-rinat ☕☕☕☕
()
#include <iostream>
#include <string>

enum class MyEnum
{
   One,
   Two,
};

std::string myfunc(const MyEnum e)
{
    switch (e) {
        case MyEnum::One : return "One";
        case MyEnum::Two : return "Two";
    }
}

int main()
{
    std::string r = myfunc((MyEnum)123);
    std::cout << r;
    return 0;
}

и привет segfault. Так что gcc делает правильно, т.к. не знает как ты потом будешь эту функцию вызывать.

sergej
()

По той же причине, по которой на вот такой код компилятор поругается с тем же -Wreturn-type:

if( foo ) return 1;
else return 0;

a1batross
()
Ответ на: комментарий от a1batross

А, долблюсь в глаза.

enum-ов на самом деле не существуют. Они все — целые значение. Поэтому туда может попасть всё что угодно. Поэтому default: лучше делать, чем нет.

a1batross
()
Ответ на: комментарий от a1batross

Как уже писал выше: default отключает проверку использования всех значений, а она мне нужна.

RazrFalcon
() автор топика

return «One»

С какой версии это начало требовать QStringLiteral? С пятой?

KennyMinigun
()
Ответ на: комментарий от KennyMinigun

Наверное, в новых версиях уже нет. Но когда-то было, что компилятор подобные конструкции считал неполными. С тех пор, всегда пишу так: if( foo ) return 1;\n return 0;

RazrFalcon, ну тогда выключи ворнинг и дальше радуйся жизни. Ты-то знаешь, что там ошибки нет. Ну или как в первом комментарии подсказали — просто дописать return "". И не костыль, потому что защитит от каста.

a1batross
()

ну всё правильно говорит

У тебя в теории в аргумент myfunc можно передать всё что угодно. Что будет тогда, ммм?

reprimand
()
Ответ на: комментарий от a1batross

enum-ов на самом деле не существуют. Они все — целые значение.

ЕМНИП, стандарт не рекомендует их воспринимать как целое, несмотря на то, что по факту это так. А нарушать стандарт не стоит.

Но даже если не нарушать, у ТС-а компилятор всё правильно говорит.

reprimand
()
Ответ на: комментарий от RazrFalcon

Я не передаю туда мусор

то, что ты не передаёшь туда мусор не значит что его туда нельзя передать

наличие процедуры в твоём коде означает что её можно вызвать, а то КАК ты её вызываешь уже другой вопрос. В конце концов, твой код можно слинковать в объектный файл (или .so) и кто-то может дёрнуть твою процедуру оттуда

Кстати, попробуй добавить «inline static» перед «QString myfunc(const MyEnum e)», авось компилятор пропустит

reprimand
()
Ответ на: комментарий от reprimand

попробуй добавить «inline static» перед

Это просто пример, а не реальный код.

RazrFalcon
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.