shithub: riscv

Download patch

ref: 3ba1d83d2026ebac616ab17a2126df97c0a7a24c
parent: ac4e21f52d8458732b6e18d6ca481ab880c6c9be
author: Ori Bernstein <ori@eigenstate.org>
date: Sat Aug 8 07:39:25 EDT 2020

cc: promote integer constants according to c99 spec.

C99 integer constants with no type suffix promote differently
depending on the way that they're written: hex and oct consts
promote as int => uint => long => ulong => vlong => uvlong.
Decimal constants are always signed.

We used to promote all values to uint on overflow, and never
went wider. This change fixes that, and adds a warning when
a decimal constant that would have been promoted to uint in
the past gets promoted to int.

--- a/sys/src/cmd/8c/txt.c
+++ b/sys/src/cmd/8c/txt.c
@@ -865,7 +865,7 @@
 		gmove(f, &fregnode0);
 		gins(AFADDD, nodfconst(-2147483648.), &fregnode0);
 		gins(AFMOVLP, f, &nod);
-		gins(ASUBL, nodconst(-2147483648), &nod);
+		gins(ASUBL, nodconst(-0x80000000), &nod);
 		gmove(&nod, t);
 		return;
 
--- a/sys/src/cmd/cc/lex.c
+++ b/sys/src/cmd/cc/lex.c
@@ -444,7 +444,7 @@
 yylex(void)
 {
 	vlong vv;
-	long c, c1, t;
+	long c, c1, t, w;
 	char *cp;
 	Rune rune;
 	Sym *s;
@@ -844,7 +844,16 @@
 		yyerror("overflow in constant");
 
 	vv = yylval.vval;
-	if(c1 & Numvlong) {
+	/*
+	 * c99 is silly: decimal constants stay signed,
+	 * hex and octal go unsigned before widening.
+	 */
+	w = 32;
+	if((c1 & (Numdec|Numuns)) == Numdec)
+		w = 31;
+	if(c1 & Numvlong || (c1 & Numlong) == 0 && (uvlong)vv >= 1ULL<<w){
+		if((c1&(Numdec|Numvlong)) == Numdec && vv < 1ULL<<32)
+			warn(Z, "int constant widened to vlong: %s", symb);
 		if((c1 & Numuns) || convvtox(vv, TVLONG) < 0) {
 			c = LUVLCONST;
 			t = TUVLONG;