xref: /netbsd-src/tests/usr.bin/xlint/lint1/expr_precedence.c (revision 313458bc0b774f4f7e92ddc2fda95b8eb2022330)
1*313458bcSrillig /*	$NetBSD: expr_precedence.c,v 1.12 2024/05/01 07:40:11 rillig Exp $	*/
260f9e3d3Srillig # 3 "expr_precedence.c"
360f9e3d3Srillig 
460f9e3d3Srillig /*
560f9e3d3Srillig  * Tests for the precedence among operators.
660f9e3d3Srillig  */
760f9e3d3Srillig 
8b2baa501Srillig /* lint1-extra-flags: -X 351 */
9b2baa501Srillig 
1060f9e3d3Srillig int var;
1160f9e3d3Srillig 
1260f9e3d3Srillig /*
1360f9e3d3Srillig  * An initializer needs an assignment-expression; the comma must be
1460f9e3d3Srillig  * interpreted as a separator, not an operator.
1560f9e3d3Srillig  */
1660f9e3d3Srillig /* expect+1: error: syntax error '4' [249] */
1760f9e3d3Srillig int init_error = 3, 4;
1860f9e3d3Srillig 
1960f9e3d3Srillig /* expect+1: error: non-constant initializer [177] */
2060f9e3d3Srillig int init_syntactically_ok = var = 1 ? 2 : 3;
2160f9e3d3Srillig 
2260f9e3d3Srillig /*
23*313458bcSrillig  * The arguments of __attribute__ must be constant-expression, but for
24*313458bcSrillig  * simplicity of implementation, they are parsed just like function arguments,
25*313458bcSrillig  * even though this allows assignment-expression.
2660f9e3d3Srillig  */
2760f9e3d3Srillig void __attribute__((format(printf,
284c2e2660Srillig     /*
294c2e2660Srillig      * Inside of __attribute__((...)), symbol lookup works differently.  For
304c2e2660Srillig      * example, 'printf' is a keyword, and since all arguments to
314c2e2660Srillig      * __attribute__ are constant expressions, looking up global variables
324c2e2660Srillig      * would not make sense.  Therefore, 'var' is undefined.
334c2e2660Srillig      *
34512bf5dcSrillig      * See lex.c, function 'search', keyword 'in_gcc_attribute'.
354c2e2660Srillig      */
3660f9e3d3Srillig     var = 1,
3760f9e3d3Srillig     /* Syntactically ok, must be a constant expression though. */
3860f9e3d3Srillig     var > 0 ? 2 : 1)))
3960f9e3d3Srillig my_printf(const char *, ...);
40036149f3Srillig 
41036149f3Srillig void
assignment_associativity(int arg)42036149f3Srillig assignment_associativity(int arg)
43036149f3Srillig {
44036149f3Srillig 	int left, right;
45036149f3Srillig 
4651b2be3cSrillig 	/*
4751b2be3cSrillig 	 * Assignments are right-associative.  If they were left-associative,
4851b2be3cSrillig 	 * the result of (left = right) would be an rvalue, resulting in this
4951b2be3cSrillig 	 * error message: 'left operand of '=' must be lvalue [114]'.
5051b2be3cSrillig 	 */
51036149f3Srillig 	left = right = arg;
52036149f3Srillig 
53036149f3Srillig 	left = arg;
54036149f3Srillig }
553120116eSrillig 
563120116eSrillig void
conditional_associativity(_Bool cond1,_Bool cond2,int a,int b,int c)573120116eSrillig conditional_associativity(_Bool cond1, _Bool cond2, int a, int b, int c)
583120116eSrillig {
593120116eSrillig 	/* The then-expression can be an arbitrary expression. */
603120116eSrillig 	var = cond1 ? cond2 ? a : b : c;
613120116eSrillig 	var = cond1 ? (cond2 ? a : b) : c;
623120116eSrillig 
633120116eSrillig 	/* The then-expression can even be a comma-expression. */
643120116eSrillig 	var = cond1 ? cond2 ? a, b : (b, a) : c;
653120116eSrillig 
663120116eSrillig 	var = cond1 ? a : cond2 ? b : c;
673120116eSrillig 	/*
683120116eSrillig 	 * In almost all programming languages, '?:' is right-associative,
693120116eSrillig 	 * which allows for easy chaining.
703120116eSrillig 	 */
713120116eSrillig 	var = cond1 ? a : (cond2 ? b : c);
723120116eSrillig 	/*
733120116eSrillig 	 * In PHP, '?:' is left-associative, which is rather surprising and
743120116eSrillig 	 * requires more parentheses to get the desired effect.
753120116eSrillig 	 */
763120116eSrillig 	var = (cond1 ? a : cond2) ? b : c;
773120116eSrillig }
78