Могу ли я рассчитывать на мой компилятор для диагностики несоответствия типов в TU? - PullRequest
4 голосов
/ 16 мая 2011

При поиске в спецификации выясняется, что моему компилятору не требуется диагностировать такие ошибки, как

extern int a;
extern float a;

Ранее я думал, что мой компилятор должен это диагностировать, но в спецификации говорится (выделениедобавлено мной)

После всех корректировок типов (во время которых typedefs (7.1.3) заменяются их определениями) типы, указанные во всех объявлениях, ссылающихся на данную переменную или функцию, должны быть идентичнымиза исключением того, что объявления для объекта массива могут указывать типы массивов, которые отличаются наличием или отсутствием привязки основного массива (8.3.4). Нарушение этого правила для идентификации типа не требует диагностики.

И на самом деле я обнаружил случаи, когда компиляторам все равно.Например, GCC и clang принимают следующее

void g() { int f(); } 
void h() { float f(); }

Поскольку нарушение правила, для которого не требуется диагностика, означает, что вся программа больше не требует диагностики, это означает, что следующие неправильно сформированныеПрограмма также не требует диагностики (см. 1.4p2).К счастью, и GCC, и Clang их диагностируют.

int f();
float f();

Поведение этого кода во время перевода фактически не определено.Что является причиной этого?Почему спецификация может не требовать отклонения таких случаев и требовать их диагностики?

Ответы [ 4 ]

1 голос
/ 17 мая 2011

Я думаю, что правило, которое вы цитируете, касается всей программы. Диагностика не требуется, если один TU имеет extern int a;, а другой - extern float a;, поскольку отдельный перевод делает невозможным - проблему можно обнаружить только в лучшем случае во время соединения.

Но если оба объявления происходят в пределах одного TU, я уверен, что требуется диагностика. Возможно на 3.3 / 4? Это (примерно) требует, чтобы все объявления имени в одной области видимости ссылались на одну и ту же сущность.

0 голосов
/ 16 мая 2011

По словам Пита Беккера, когда у вас есть список правил, таких как маркеры в §1.4 / 2, они (по крайней мере обычно) должны читаться по порядку, причем более ранние правила имеют приоритет над более поздними правилами.

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

К сожалениюЯ никогда не видел никаких явных утверждений на этот счет в самом стандарте, только в старых сообщениях Usenet от Пита (и, если память не изменяет, возможно, также от Эндрю Кенига, который был редактором до Пита).

0 голосов
/ 16 мая 2011

Это похоже на сложную математическую задачу.Я предполагаю, что причина в том, что с двумя разными typedef вы можете получить один и тот же тип в двух разных выражениях.Однако, когда компилятор хранит структуры данных, требующая проверки потребует, чтобы компилятор "оценил" выражение типа до его нормальной формы.Теорема Черча-Россера должна использоваться внутри компилятора, чтобы доказать, что эти два выражения эквивалентны.Операция, используемая в typedefs, является просто старой заменой, поэтому потребуется полный список пользователя.Так что, думаю, они сделали это необязательно.Я думаю, что они не хотят добавлять лямбда-исчисление, которое потребуется в следующий раз.

typedef A<int> C;
typedef int D;
typedef A<D> E;
extern C v;
extern E v;

Теперь, без оценки обоих значений до A<int>, нет способа проверить, относятся ли они к одному типу.

0 голосов
/ 16 мая 2011

Для вашего первого примера Visual studio (по праву) запускает:

d:\experiments\test1\test1\test1.cpp(7) : error C2371: 'a' : redefinition; different basic types
        d:\experiments\test1\test1\test1.cpp(6) : see declaration of 'a'

В вашем втором примере нет ничего плохого, поскольку определения функций локальны, поэтому они могут делать все, что захотят.

Ваш третий пример (по праву) вызывает ошибку в Visual Studio:

d:\experiments\test1\test1\test1.cpp(7) : error C2556: 'float f(void)' : overloaded function differs only by return type from 'int f(void)'
        d:\experiments\test1\test1\test1.cpp(6) : see declaration of 'f'
d:\experiments\test1\test1\test1.cpp(7) : error C2371: 'f' : redefinition; different basic types

Я уверен, что спецификация говорит, что вы не можете иметь несколько переменных с одинаковыми именами в одной и той же области видимости, и определения функций в одной и той же области видимости должныотличаются больше, чем их тип возврата.

...