llvm / llvm-project

The LLVM Project is a collection of modular and reusable compiler and toolchain technologies.
http://llvm.org
Other
28k stars 11.56k forks source link

Clang rejects the valid member function definition with typedefed return type and global :: scope resolution operator #108655

Closed suikan4github closed 3 days ago

suikan4github commented 4 days ago

Overview

Clang shows an error when a class member function definiton has both :

This problem is not found with GCC.

Code to demonstrate

In the following code, uint32_t is typedefed inside stdint.h. Copy this code into foo.cpp.

#include <stdint.h>

class foo {
 public:
  uint32_t bar(unsigned int a);
  unsigned int baz(unsigned int a);
  uint32_t qux(uint32_t a);
};

// Fail to compile with Clang 18.1.3 x86_64-pc-linux-gnu
uint32_t ::foo::bar(unsigned int a) { return a; }

// No problem if not using typdef.
unsigned int ::foo::baz(unsigned int a) { return a; }

// No problem if not using global scope resolution operator.
uint32_t foo::qux(uint32_t a) { return a; }

int main() {
  foo my_foo;

  return (my_foo.bar(0));
}

To reproduce the problem, run the following command.

takemasa@vm2204:~/git/sandbox$ clang-18 foo.cpp
foo.cpp:11:1: error: 'uint32_t' (aka 'unsigned int') is not a class, namespace, or enumeration
   11 | uint32_t ::foo::bar(unsigned int a) { return a; }
      | ^
1 error generated.

Workaround

To avoid this problem, we should use non-typedefed return type in the function definiton.

unsigned int ::foo::baz(unsigned int a) { return a; }

Or, we should not to use the global :: scope operator in the function definition.

uint32_t foo::qux(uint32_t a) { return a; }

Environment and version

takemasa@vm2204:~/git/sandbox$ clang-18 --version
Ubuntu clang version 18.1.8 (++20240731024944+3b5b5c1ec4a3-1~exp1~20240731145000.144)
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /usr/bin
EugeneZelenko commented 4 days ago

Could you please try 19 or main branch? https://godbolt.org should be helpful.

llvmbot commented 4 days ago

@llvm/issue-subscribers-clang-frontend

Author: Seiichi "Suikan" Horie (suikan4github)

## Overview Clang shows an error when a class member function definiton has both : - Typedefed return type. - Global :: scope resolutoin operator. This problem is not found with GCC. ## Code to demonstrate In the following code, uint32_t is typedefed inside stdint.h. Copy this code into foo.cpp. ```cpp #include <stdint.h> class foo { public: uint32_t bar(unsigned int a); unsigned int baz(unsigned int a); uint32_t qux(uint32_t a); }; // Fail to compile with Clang 18.1.3 x86_64-pc-linux-gnu uint32_t ::foo::bar(unsigned int a) { return a; } // No problem if not using typdef. unsigned int ::foo::baz(unsigned int a) { return a; } // No problem if not using global scope resolution operator. uint32_t foo::qux(uint32_t a) { return a; } int main() { foo my_foo; return (my_foo.bar(0)); } ``` To reproduce the problem, run the following command. ```sh takemasa@vm2204:~/git/sandbox$ clang-18 foo.cpp foo.cpp:11:1: error: 'uint32_t' (aka 'unsigned int') is not a class, namespace, or enumeration 11 | uint32_t ::foo::bar(unsigned int a) { return a; } | ^ 1 error generated. ``` ## Workaround To avoid this problem, we should use non-typedefed return type in the function definiton. ```cpp unsigned int ::foo::baz(unsigned int a) { return a; } ``` Or, we should not to use the global :: scope operator in the function definition. ```cpp uint32_t foo::qux(uint32_t a) { return a; } ``` ## Environment and version - Ubuntu 22.04, 24.04 - Clang 18.1.8 ```sh takemasa@vm2204:~/git/sandbox$ clang-18 --version Ubuntu clang version 18.1.8 (++20240731024944+3b5b5c1ec4a3-1~exp1~20240731145000.144) Target: x86_64-pc-linux-gnu Thread model: posix InstalledDir: /usr/bin ```
suikan4github commented 4 days ago

I have tried the trunk with [Compiler Explorer](https://godbolt.org/#g:!((g:!((g:!((h:codeEditor,i:(filename:'1',fontScale:14,fontUsePx:'0',j:1,lang:c%2B%2B,selection:(endColumn:1,endLineNumber:24,positionColumn:1,positionLineNumber:24,selectionStartColumn:1,selectionStartLineNumber:24,startColumn:1,startLineNumber:24),source:'%23include+%3Cstdint.h%3E%0A%0Aclass+foo+%7B%0A+public:%0A++uint32_t+bar(unsigned+int+a)%3B%0A++unsigned+int+baz(unsigned+int+a)%3B%0A++uint32_t+qux(uint32_t+a)%3B%0A%7D%3B%0A%0A//+Fail+to+compile+with+Clang+18.1.3+x86_64-pc-linux-gnu%0Auint32_t+::foo::bar(unsigned+int+a)+%7B+return+a%3B+%7D%0A%0A//+No+problem+if+not+using+typdef.%0Aunsigned+int+::foo::baz(unsigned+int+a)+%7B+return+a%3B+%7D%0A%0A//+No+problem+if+not+using+global+scope+resolution+operator.%0Auint32_t+foo::qux(uint32_t+a)+%7B+return+a%3B+%7D%0A%0Aint+main()+%7B%0A++foo+my_foo%3B%0A%0A++return+(my_foo.bar(0))%3B%0A%7D%0A'),l:'5',n:'1',o:'C%2B%2B+source+%231',t:'0')),k:50,l:'4',n:'0',o:'',s:0,t:'0'),(g:!((g:!((h:compiler,i:(compiler:clang_trunk,filters:(b:'0',binary:'1',binaryObject:'1',commentOnly:'0',debugCalls:'1',demangle:'0',directives:'0',execute:'1',intel:'0',libraryCode:'0',trim:'1',verboseDemangling:'0'),flagsViewOpen:'1',fontScale:14,fontUsePx:'0',j:1,lang:c%2B%2B,libs:!(),options:'',overrides:!(),selection:(endColumn:1,endLineNumber:1,positionColumn:1,positionLineNumber:1,selectionStartColumn:1,selectionStartLineNumber:1,startColumn:1,startLineNumber:1),source:1),l:'5',n:'0',o:'+x86-64+clang+(trunk)+(Editor+%231)',t:'0')),k:50,l:'4',m:51.14068441064639,n:'0',o:'',s:0,t:'0'),(g:!((h:output,i:(compilerName:'x86-64+clang+(trunk)',editorid:1,fontScale:14,fontUsePx:'0',j:1,wrap:'1'),l:'5',n:'0',o:'Output+of+x86-64+clang+(trunk)+(Compiler+%231)',t:'0')),header:(),l:'4',m:48.85931558935361,n:'0',o:'',s:0,t:'0')),k:50,l:'3',n:'0',o:'',t:'0')),l:'2',n:'0',o:'',t:'0')),version:4) . Problem exists.

image

EugeneZelenko commented 4 days ago

@suikan4github: just use link, so other people could run verify.

suikan4github commented 4 days ago

@EugeneZelenko You can see the link.

EugeneZelenko commented 4 days ago

@suikan4github: I meant that screenshot is not needed.

shafik commented 3 days ago

clang is correct, this is a duplicate of: https://github.com/llvm/llvm-project/issues/25556

Please file a bug w/ gcc and edg: https://godbolt.org/z/9o91nnPbh

MSVC also gets this right.

Note as explained in the dup using () disambiguates:

uint32_t (::foo::bar)(unsigned int a) { return a; }

Also note int is a keyword and not an identifier.