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 ★★★★★
() автор топика
Ответ на: комментарий от anonymous

Да это понятно. Но это уже false-positive.

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 ★★★★★
()
Ответ на: комментарий от a1batross

Отдельный флаг чисто для gcc - боль.

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

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

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

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

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

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

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

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

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