这种clang标准是否符合标准?

时间:2016-07-28 20:30:21

标签: c compiler-errors clang c11 restrict

这将是一个长期的语言律师问题,所以我想快速说明为什么我认为它是相关的。我正在开展一个严格的标准合规性至关重要的项目(编写一种编译成C的语言)。我要提供的示例似乎是clang部分的标准违规,因此,如果是这种情况,我想确认一下。

gcc说,带有指向限定限定指针的指针的条件不能与带有void指针的条件语句共存。另一方面,clang编译好的东西。这是一个示例程序:

#include <stdlib.h>

int main(void){
   int* restrict* A = malloc(8);
   A ? A : malloc(8);
   return 0;
   }

对于gcc,可以包含或不包含选项-std=c11-pedantic,同样适用于clang和选项-std=c11-Weverything。无论如何,clang编译没有错误,gcc给出以下内容:

tem-2.c: In function ‘main’:
tem-2.c:7:2: error: invalid use of ‘restrict’
  A ? A : malloc(8);
  ^

c11标准对条件陈述进行了以下说明,重点补充:

  

6.5.15条件运算符

     

...

     
      
  1. 以下其中一项适用于第二和第三个操作数:
  2.         

    - 两个操作数都有算术类型;

         

    - 两个操作数具有相同的结构或联合类型;

         

    - 两个操作数都有void类型;

         

    - 两个操作数都是指向兼容类型的限定或非限定版本的指针;

         

    - 一个操作数是指针,另一个是空指针常量;或

         

    - 一个操作数是指向对象类型的指针,另一个是指向合格或非限定版本的void的指针。

         

    ...

         
        
    1. 如果第二个和第三个操作数都是指针,或者一个是空指针常量和   other是指针,结果类型是指向使用所有类型限定符限定的类型的指针   两个操作数引用的类型。此外,如果两个操作数都是指针   兼容类型或兼容类型的不同限定版本,结果类型是   指向复合类型的适当限定版本的指针;如果一个操作数是一个   null指针常量,结果具有另一个操作数的类型;否则,一个操作数   是指向void或void的限定版本的指针,在这种情况下,结果类型是a   指向适当合格版本的void。
    2.         

      ...

我看到它的方式,上面的第一个粗体部分表示两种类型可以组合在一起,第二个粗体部分将结果定义为指向限制限定版本的void的指针。但是,如下所示,此类型不能存在,因此表达式被gcc正确识别为错误:

  

6.7.3类型限定词,第2段

     

引用类型为对象类型的指针类型以外的类型不应受限制。

现在,问题是&#34;不应该&#34;此示例程序违反了条件,因此需要产生错误,如下所示:

  

5.1.1.3诊断,第1段

     

符合要求的实施应产生至少一条诊断信息(在   如果是预处理翻译单元或翻译单元,则是实现定义的方式   包含违反任何语法规则或约束的行为,即使行为也是明确的   指定为未定义或实现定义。诊断消息不一定是   在其他情况下产生。

通过默默处理错误类型,似乎clang不符合标准。这让我想知道铿锵有什么其他的默默无闻。

我在x86-64 Ubuntu机器上使用gcc版本5.4.0和clang版本3.8.0。

2 个答案:

答案 0 :(得分:5)

是的,它看起来像一个bug。

您的问题更简要:void可以restrict合格吗?由于void显然不是指针类型,所以答案是否定的。因为这违反了约束,编译器应该提供诊断。

我能够通过clang表达式欺骗_Generic来承认自己的罪行

puts(_Generic(A ? A : malloc(8), void* : "void*"));

clang告诉我

static.c:24:18: error: controlling expression type 'restrict void *' not compatible with any generic association type
     puts(_Generic(A ? A : malloc(8), void* : "void*"));

表明此处clang确实尝试匹配无意义类型restrict void*

请向他们提交错误报告。

答案 1 :(得分:0)

虽然编译器可以通过完全忽略限定符来满足restrict周围的所有义务,但是想要跟踪它是什么或不允许执行的编译器需要跟踪哪些指针包含{{ {1}}指针。给出类似的东西:

restrict

由于int *foo; int *bar; int wow(int *restrict p) { foo = p; ... *p = 123; *foo = 456; *p++; *bar = 890; return *p; } 派生自p,编译器必须允许通过访问进行访问 foo通过foo对访问进行别名。编译器不需要做出这样的限制 对于通过p进行的访问,因为已知来保存从bar派生的地址。

围绕p的规则在指针可能或的情况下变得模糊 可能不是来自另一个人。肯定会允许编译器 如果它无法跟踪所有限定符,则忽略restrict限定符 从指针派生的指针;我不确定是否会有这样的情况 即使没有任何东西修改由...标识的存储,也会调用UB 指针。如果句法结构在结构上保证可以调用 UB,有一个编译器叫声可能比让它在一个行为中更有用 任意时尚(虽然编译器只是忽略任何restrict 它无法完全处理的限定符可能更有用)。