File: generic-selection-type-extension.c

package info (click to toggle)
llvm-toolchain-19 1%3A19.1.7-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 1,998,520 kB
  • sloc: cpp: 6,951,680; ansic: 1,486,157; asm: 913,598; python: 232,024; f90: 80,126; objc: 75,281; lisp: 37,276; pascal: 16,990; sh: 10,009; ml: 5,058; perl: 4,724; awk: 3,523; makefile: 3,167; javascript: 2,504; xml: 892; fortran: 664; cs: 573
file content (136 lines) | stat: -rw-r--r-- 6,837 bytes parent folder | download | duplicates (7)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
// RUN: %clang_cc1 -std=c2x -fsyntax-only -verify -Wno-unused %s
// RUN: %clang_cc1 -fsyntax-only -verify -Wno-unused -x c++ -std=c++17 %s

// Test that the semantic behavior of the extension allowing the user to pass a
// type as the first argument to _Generic.

// Test that we match on basic types.
static_assert(_Generic(int, int : 1, default : 0) == 1);
static_assert(_Generic(_BitInt(12), int : 1, _BitInt(10) : 2, _BitInt(12) : 3) == 3);

// Test that we correctly fall back to the default association appropriately.
static_assert(_Generic(int, long : 1, default : 0) == 0);

// Ensure we correctly match constant arrays by their extent.
static_assert(_Generic(int[12], int[0] : 0, int * : 0, int[12] : 1, default : 0) == 1);

// Ensure we correctly match function types by their signature.
static_assert(_Generic(int(int), void(void) : 0, int(void) : 0, void(int) : 0, int(int) : 1, default : 0) == 1);

// Test that we still diagnose when no associations match and that the
// diagnostic includes qualifiers.
static_assert(_Generic(const int, long : 1)); // expected-error {{controlling expression type 'const int' not compatible with any generic association type}}

// Test that qualifiers work as expected and do not issue a diagnostic when
// using the type form.
static_assert(_Generic(const int, int : 0, const int : 1) == 1);
static_assert(_Generic(int volatile _Atomic const, int : 0, const int : 0, volatile int : 0, _Atomic int : 0, _Atomic const volatile int : 1) == 1);

// Test that inferred qualifiers also work as expected.
const int ci = 0;
static_assert(_Generic(__typeof__(ci), int : 0, const int : 1) == 1);
// And that the expression form still complains about qualified associations
// and matches the correct association.
static_assert(_Generic(ci, int : 1, const int : 0) == 1); // expected-warning {{due to lvalue conversion of the controlling expression, association of type 'const int' will never be selected because it is qualified}}

// The type operand form of _Generic allows incomplete and non-object types,
// but the expression operand form still rejects them.
static_assert(_Generic(struct incomplete, struct incomplete : 1, default : 0) == 1);
static_assert(_Generic(struct another_incomplete, struct incomplete : 1, default : 0) == 0);
static_assert(_Generic(1, struct also_incomplete : 1, default : 0) == 0); // expected-error {{type 'struct also_incomplete' in generic association incomplete}}

void foo(int);
static_assert(_Generic(__typeof__(foo), void(int) : 1, default : 0) == 1);
static_assert(_Generic(foo, void(int) : 1, default : 0) == 0); // expected-error {{type 'void (int)' in generic association not an object type}}

// Ensure we still get a diagnostic for duplicated associations for the type
// form, even when using qualified type, and that the diagnostic includes
// qualifiers.
static_assert(_Generic(const int,
                         const int : 1, // expected-note {{compatible type 'const int' specified here}}
                         int : 2,
                         const int : 3  // expected-error {{type 'const int' in generic association compatible with previously specified type 'const int'}}
                      ) == 1);

// Verify that we are matching using the canonical type of the type operand...
typedef int Int;
typedef const Int CInt;
typedef CInt OtherCInt;
static_assert(_Generic(volatile CInt, const volatile int : 1, default : 0) == 1);
static_assert(_Generic(const int, CInt : 1, default : 0) == 1);

// ...and that duplicate associations are doing so as well.
static_assert(_Generic(const int,
                         CInt : 1,     // expected-note {{compatible type 'CInt' (aka 'const int') specified here}}
                         const volatile int : 2,
                         OtherCInt : 3 // expected-error {{type 'OtherCInt' (aka 'const int') in generic association compatible with previously specified type 'CInt' (aka 'const int')}}
                      ) == 1);

// Also test that duplicate array or function types are caught.
static_assert(_Generic(const int,
                         int[12] : 0,  // expected-note {{compatible type 'int[12]' specified here}}
                         int[12] : 0,  // expected-error {{type 'int[12]' in generic association compatible with previously specified type 'int[12]'}}
                         int(int) : 0, // expected-note {{compatible type 'int (int)' specified here}}
                         int(int) : 0, // expected-error {{type 'int (int)' in generic association compatible with previously specified type 'int (int)'}}
                         default : 1
                      ) == 1);


// Tests that only make sense for C++:
#ifdef __cplusplus
// Ensure that _Generic works within a template argument list.
template <typename Ty, int N = _Generic(Ty, int : 0, default : 1)>
constexpr Ty bar() { return N; }

static_assert(bar<int>() == 0);
static_assert(bar<float>() == 1);

// Or that it can be used as a non-type template argument.
static_assert(bar<int, _Generic(int, int : 1, default : 0)>() == 1);

// Ensure that a dependent type works as expected.
template <typename Ty>
struct Dependent {
  // If we checked the type early, this would fail to compile without any
  // instantiation. Instead, it only fails with the bad instantiation.
  static_assert(_Generic(Ty, int : 1)); // expected-error {{controlling expression type 'double' not compatible with any generic association type}} \
                                           expected-note@#BadInstantiation {{in instantiation of template class 'Dependent<double>' requested here}}
};

template struct Dependent<int>; // Good instantiation
template struct Dependent<double>; // #BadInstantiation

// Another template instantiation test, this time for a variable template with
// a type-dependent initializer.
template <typename Ty>
constexpr auto Val = _Generic(Ty, Ty : Ty{});

static_assert(Val<int> == 0);
static_assert(__is_same(decltype(Val<Dependent<int>>), const Dependent<int>));

// Ensure that pack types also work as expected.
template <unsigned Arg, unsigned... Args> struct Or {
  enum { result = Arg | Or<Args...>::result };
};

template <unsigned Arg> struct Or<Arg> {
  enum { result = Arg };
};

template <class... Args> struct TypeMask {
  enum {
   result = Or<_Generic(Args, int: 1, long: 2, short: 4, float: 8)...>::result
  };
};

static_assert(TypeMask<int, long, short>::result == 7, "fail");
static_assert(TypeMask<float, short>::result == 12, "fail");
static_assert(TypeMask<int, float, float>::result == 9, "fail");

template <typename... T>
void f() {
  // Because _Generic only accepts a single type argument, it does not make
  // sense for it to accept a pack, so a pack is rejected while parsing.
  _Generic(T..., int : 1); // expected-error {{expected ','}}
}
#endif // __cplusplus