9front - general discussion about 9front
 help / color / mirror / Atom feed
* cc: fix c99 integer conversions
@ 2020-07-24  4:09 ori
  2020-08-02 16:38 ` [9front] " ori
  0 siblings, 1 reply; 3+ messages in thread
From: ori @ 2020-07-24  4:09 UTC (permalink / raw)
  To: 9front

The C99 standard, section 6.4.4.1 paragraph 5 says that integer
constants should be converted as follows:

If they fit in an int, they should be an int.

If they're written in decimal, they should be converted
to the smallest signed type that can hold the value.

If they're written as oct or hex, they should be converted
to the smallest signed *or* unsigned type that can hold the
value.

Right now, we don't widen to vlong when appropriate. This
fixes the issue.

This bug/quirk was discovered by Amavect, and they wrote
the test code:

/* integer constant type test
 * reference: C standard 6.4.4.1
 * not really compliant lol
 * ori & Amavect
 */
#include <u.h>
#include <libc.h>

void
main(void)
{
	print("%ullX ", 0xFF66554433221100);  /* uvlong */
	print("%llX ",  0x0000000180000000);  /* vlong */
	print("\n");
	print("%X ",   0x7FFFFFFF);   /* int */
	print("%uX ",  0x80000000);   /* uint */
	print("%uX ",  0xFFFFFFFF);   /* uint */
	print("%llX ", 0x100000000);  /* vlong */
	print("\n");
	
	/* vlong (C standard)
	 * if it parses as uint, it's technically wrong to the standard
	 * even though it works just fine
	 * ideally, - is part of an integer constant,
	 * but that's just not in the standard.
	 */
	print("%lld ", -2147483648);
	print("%d",  -0x80000000);  /* uint, no warning for int format */
	
	print("\n");
	print("%llX ",  0x7FFFFFFFFFFFFFFF);  /* vlong */
	print("%ullX ", 0x8000000000000000);  /* uvlong */
	print("%ullX ", 0xFFFFFFFFFFFFFFFF);  /* uvlong */
	print("%ullX", ~1ULL);  /* uvlong */
	print("\n");
	
	/* uvlong (C standard)
	 * C standard specifies an extended integer type
	 * uvlong is our extended vlong :)
	 */
	print("%lld ", -9223372036854775808); /* no warning for vlong format */
	print("%lld", -0x8000000000000000);   /* uvlong, no warning for vlong format */
	print("\n");
	
}


And here's a patch that makes our integer conversions comply
with c99:

diff -r 639ad985a75b sys/src/cmd/cc/lex.c
--- a/sys/src/cmd/cc/lex.c	Mon Jul 20 18:58:52 2020 -0700
+++ b/sys/src/cmd/cc/lex.c	Thu Jul 23 21:04:15 2020 -0700
@@ -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,8 @@
 		yyerror("overflow in constant");
 
 	vv = yylval.vval;
-	if(c1 & Numvlong) {
+	w = (c1 & Numdec) ? 31 : 32;
+	if(c1 & Numvlong || (uvlong)vv >= 1ULL<<w){
 		if((c1 & Numuns) || convvtox(vv, TVLONG) < 0) {
 			c = LUVLCONST;
 			t = TUVLONG;



^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [9front] cc: fix c99 integer conversions
  2020-07-24  4:09 cc: fix c99 integer conversions ori
@ 2020-08-02 16:38 ` ori
  2020-08-02 18:28   ` ori
  0 siblings, 1 reply; 3+ messages in thread
From: ori @ 2020-08-02 16:38 UTC (permalink / raw)
  To: 9front

> The C99 standard, section 6.4.4.1 paragraph 5 says that integer
> constants should be converted as follows:
> 
> If they fit in an int, they should be an int.
> 
> If they're written in decimal, they should be converted
> to the smallest signed type that can hold the value.
> 
> If they're written as oct or hex, they should be converted
> to the smallest signed *or* unsigned type that can hold the
> value.
> 
> Right now, we don't widen to vlong when appropriate. This
> fixes the issue.
> 
> This bug/quirk was discovered by Amavect, and they wrote
> the test code:
> 

New revision of the patch, which doesn't touch types with
explicit suffixes, and warns when you fall off of the int
sizes, to catch behavior changes in existing code. There's
just one place in our tree where the change matters, so
this patch shuts up that one warning.

I'm also happy to remove the warning, since it doesn't
seem to be an issue in practice.

diff -r 39206a734718 sys/src/cmd/8c/txt.c
--- a/sys/src/cmd/8c/txt.c	Sat Aug 01 10:54:03 2020 -0700
+++ b/sys/src/cmd/8c/txt.c	Sun Aug 02 09:36:22 2020 -0700
@@ -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;
 
diff -r 39206a734718 sys/src/cmd/cc/lex.c
--- a/sys/src/cmd/cc/lex.c	Sat Aug 01 10:54:03 2020 -0700
+++ b/sys/src/cmd/cc/lex.c	Sun Aug 02 09:36:22 2020 -0700
@@ -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. Decimap 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;



^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [9front] cc: fix c99 integer conversions
  2020-08-02 16:38 ` [9front] " ori
@ 2020-08-02 18:28   ` ori
  0 siblings, 0 replies; 3+ messages in thread
From: ori @ 2020-08-02 18:28 UTC (permalink / raw)
  To: 9front

> +	 * c99 is silly. Decimap constants stay signed,

Obviously, with this typo fixed.



^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2020-08-02 18:28 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-07-24  4:09 cc: fix c99 integer conversions ori
2020-08-02 16:38 ` [9front] " ori
2020-08-02 18:28   ` ori

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).