llvm / llvm-project

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

typeof_unqual does not remove qualifiers from qualified array types #92667

Closed Halalaluyafail3 closed 2 months ago

Halalaluyafail3 commented 4 months ago

Clang does not remove qualifiers from qualified array types, i.e. array types with qualified element types with typeof_unqual in some situations. See GCC bug 112841 which has the following example:

const char* const animals[] = {
"aardvark",
"bluejay",
 "catte",
};
int main (int argc, char* argv[]) {
 const char* animals2_array1[3];
 typeof_unqual(animals) animals2_array;
 animals2_array1[0] = 0;
 animals2_array[0] = 0;
 return 0;
}

Clang has typeof_unqual(animals) result in a const qualified type which results in the assignment animals2_array[0] = 0; failing.

llvmbot commented 4 months ago

@llvm/issue-subscribers-clang-frontend

Author: None (Halalaluyafail3)

Clang does not remove qualifiers from qualified array types, i.e. array types with qualified element types with typeof_unqual in some situations. See [GCC bug 112841](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=112841) which has the following example: ```cpp const char* const animals[] = { "aardvark", "bluejay", "catte", }; int main (int argc, char* argv[]) { const char* animals2_array1[3]; typeof_unqual(animals) animals2_array; animals2_array1[0] = 0; animals2_array[0] = 0; return 0; } ``` Clang has `typeof_unqual(animals)` result in a const qualified type which results in the assignment `animals2_array[0] = 0;` failing.
shafik commented 4 months ago

CC @AaronBallman

AaronBallman commented 4 months ago

This looks like the correct behavior to me. In the final version of C23, there's an example specific to this (C23 6.7.3.6p7 EXAMPLE 2):

EXAMPLE 2 The following program:

const _Atomic int purr = 0;
const int meow = 1;
const char* const animals[] = {
  "aardvark",
  "bluejay",
  "catte",
};
typeof_unqual(meow) main (int argc, char* argv[]) {
  typeof_unqual(purr) plain_purr;
  typeof(_Atomic typeof(meow)) atomic_meow;
  typeof(animals) animals_array;
  typeof_unqual(animals) animals2_array;
  return 0;
}

is equivalent to this program:

const _Atomic int purr = 0;
const int meow = 1;
const char* const animals[] = {
  "aardvark",
  "bluejay",
  "catte",
};
int main (int argc, char* argv[]) {
  int plain_purr;
  const _Atomic int atomic_meow;
  const char* const animals_array[3];
  const char* animals2_array[3];
  return 0;
}

Note: typeof(animals) animals_array; is equivalent to const char* const animals_array[3]; and typeof_unqual(animals) animals2_array; is equivalent to const char* animals2_array[3]; -- only the top-level const is stripped.

AaronBallman commented 4 months ago

Oh, wait a second, something odd is going on here: https://godbolt.org/z/4r6M49WrT

The static_assert passes, but the code still does not compile. So something is amiss.

MitalAshok commented 4 months ago

@AaronBallman Currently, only the top-level const was removed, leaving us with an invalid non-const array of const element type. So the array type matches the non-const type, but the element type does not (when checking if the modification is valid)

This also allowed strange things like https://godbolt.org/z/11xG499PG