Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.std.c > #1377 > unrolled thread
| Started by | Jens Gustedt <jens.gustedt@loria.fr> |
|---|---|
| First post | 2012-06-17 02:16 +0200 |
| Last post | 2012-06-17 02:16 +0200 |
| Articles | 1 — 1 participant |
Back to article view | Back to comp.std.c
"controlling expression" of _Generic Jens Gustedt <jens.gustedt@loria.fr> - 2012-06-17 02:16 +0200
| From | Jens Gustedt <jens.gustedt@loria.fr> |
|---|---|
| Date | 2012-06-17 02:16 +0200 |
| Subject | "controlling expression" of _Generic |
| Message-ID | <4FDD21F3.7050309@loria.fr> |
Hello,
I am trying to understand the rules for the type of a controlling
expression in a generic selection. In the constraints, C11 states
> The controlling expression of a generic selection shall have type
> compatible with at most one of the types named in its generic
> association list.
in the semantics section, then there is
> The controlling expression of a generic selection is not evaluated.
There is no mention of promotion or conversion of any kind. So my
understanding is that the type of the expression is to be taken "as
is" no modification of types whatsoever is taking place.
In what I found there seem to be consensus that for the match of the
type to one of the generic associations, the qualification of the type
is relevant. This is so because two distinct associations must have
"incompatible types", and differing qualifiers make two types
incompatible.
There is less consensus about lvalues in general and array types in
particular. It is argued, that 6.3.2.1 (that talks about conversions)
mentions special conversion rules for general lvalues (called lvalue
conversion) and other rules for arrays when they occur as *operands*
of some operator. For the later the standard doesn't have a name, let
me call it array-to-pointer conversion.
For both conversions, 6.3.2.1 gives lists of exceptions where these
conversions don't occur. Grouping () and _Generic, being primary
expressions, are not in these lists.
If I understand correctly, a primary expression is not an operator and
so conversion rules that talk about operands of operators don't
apply.
Let's look into examples, and for convenience use this macro:
#define DETECT_TYPE(T, X) _Generic((X), default: false, T: true)
First, if we look at const qualified lvalues and rvalues:
DETECT_TYPE(int const, (int const){ 0 })
DETECT_TYPE(int const, (int const)0)
In my interpretation of _Generic (call it model 0: no promotion or
conversion) the result of both would be "true", both types would
match.
If _Generic would have to be interpreted as an operator (call it model
1), lvalue conversion would have to take place. Then the first
wouldn't match (lvalue conversion drops qualifiers) but the second
still would match, no conversion or promotion is taking place. The
consequence would be that with
int const a = 0;
DETECT_TYPE(int const, a)
would result in false but
DETECT_TYPE(int const, (int const)0)
would result in true. Quite surprising for the casual user, I think.
Integer promotion would make things even weirder.
DETECT_TYPE(short const, (short const)0)
Here (short const)0 would be promoted to int. Promotion rules don't
mention qualifiers so it has to be assumed that the resulting type
would have to be "int" without qualifiers.
clang is the only compiler that I have that has _Generic. It seems
to interpret some of this differently than I do. This test program
#include <stdio.h>
#include <stdbool.h>
#define DETECT_TYPE(T, X) _Generic((X), default: false, T: true)
int main(void) {
printf("%d expected 1: lvalue, no promotion\n", DETECT_TYPE(int const,
(int const){ 0 }));
printf("%d expected 1: rvalue, no promotion\n", DETECT_TYPE(int const,
(int const)0));
printf("%d expected 0: lvalue conversion\n", DETECT_TYPE(int const,
+((int const){ 0 })));
printf("%d expected 1: rvalue, no conversion\n", DETECT_TYPE(int
const, +((int const)0)));
printf("%d expected 1: lvalue, promotion?\n", DETECT_TYPE(short const,
(short const){ 0 }));
printf("%d expected 1: lvalue, promotion?\n", DETECT_TYPE(short const,
(short const)0));
printf("%d expected 0: lvalue conversion and promotion\n",
DETECT_TYPE(short const, +((short const){ 0 })));
printf("%d expected 0: promotion\n", DETECT_TYPE(short const, +((short
const)0)));
printf("%d expected 1: array, no array-to-pointer conversion\n",
DETECT_TYPE(int const[2], (int const[2]){ 0 }));
}
gives the following output that differs a three points from my expectation
1 expected 1: lvalue, no promotion
0 expected 1: rvalue, no promotion
0 expected 0: lvalue conversion
0 expected 1: rvalue, no conversion
1 expected 1: lvalue, promotion?
0 expected 1: lvalue, promotion?
0 expected 0: lvalue conversion and promotion
0 expected 0: promotion
1 expected 1: array, no array-to-pointer conversion
gcc doesn't have _Generic, yet, but some similar tools. If I stitch
them together to have something similar, I get
1 expected 1: lvalue, no promotion
1 expected 1: rvalue, no promotion
1 expected 0: lvalue conversion
1 expected 1: rvalue, no conversion
1 expected 1: lvalue, promotion?
1 expected 1: lvalue, promotion?
0 expected 0: lvalue conversion and promotion
0 expected 0: promotion
1 expected 1: array, no array-to-pointer conversion
I only see a difference for the interpretation of +((int const){ 0 })
The operand of the prefix + operator is an lvalue, so we first have to
do lvalue conversion. That drops the qualifiers and the type is just
int and the result of the macro should be 0.
Anybody has a more canonical interpretation of what is happening here?
Thanks
Jens
Back to top | Article view | comp.std.c
csiph-web