Bug 60570 - expression in 'elif' directive mis-diagnosed as error when group will be skipped
Summary: expression in 'elif' directive mis-diagnosed as error when group will be skipped
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: preprocessor (show other bugs)
Version: 4.7.3
: P3 minor
Target Milestone: 5.0
Assignee: Marek Polacek
URL:
Keywords:
: 36453 (view as bug list)
Depends on:
Blocks:
 
Reported: 2014-03-18 20:13 UTC by seb.grindle
Modified: 2024-04-02 21:40 UTC (History)
4 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2015-01-22 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description seb.grindle 2014-03-18 20:13:18 UTC
Consider the following C99 program:

#if 1
int i;
#elif 1/0
#endif

With gcc 4.7.3:

   gcc -c test.c

we get

   test.c:3:8: error: division by zero in #if

According to 6.10.1p5, any sequence of tokens between the #elif and the newline is valid syntax since the group for which this line is the controlling condition will be skipped, yet gcc emits a divide by zero error.

(I don't know if this bug is present in later versions as 4.7.3 is the latest I have tested on.)

Seb
Comment 1 Andreas Schwab 2014-03-18 20:17:24 UTC
Dup of 19040?
Comment 2 seb.grindle 2014-03-18 20:29:42 UTC
19040 was sort of the opposite. Here we shouldn't get a error but do; there the report was of the form "this should produce a diagostic but doesn't"
Comment 3 jsm-csl@polyomino.org.uk 2014-03-18 22:12:54 UTC
http://www.open-std.org/jtc1/sc22/wg14/www/docs/dr_412.htm gives an 
approved change (presumably to appear in C11 TC2) to stop #elif 
conditionals from being evaluated when they don't need to be, so it looks 
like we should in fact change this (for all standard versions, given it's 
being deemed a defect).
Comment 4 moshansky 2015-01-22 02:57:54 UTC
Still present as of gcc version 4.8.4 20140526 (release) [ARM/embedded-4_8-branch revision 211358] (GNU Tools for ARM Embedded Processors).

Fails:
#if(1)
	#pragma message "This Should Work"
#elif(1/0)
	#pragma message "1/0 should not be attempted"
#endif

Workaround:
#if(1)
	#pragma message "This Should Work"
#else
	#elif(1/0)
		#pragma message "1/0 should is not attempted"
	#endif
#endif
Comment 5 Jakub Jelinek 2015-01-22 07:33:12 UTC
So shall we then partially revert r136209 aka PR36320?
I say partially, because I think at least the addition of is_if argument to _cpp_parse_expr should be preserved.
Comment 6 Marek Polacek 2015-01-22 09:37:15 UTC
It would appear so, in which case the following (untested, only quick hack) should work:

diff --git a/gcc/testsuite/gcc.dg/cpp/pr36320.c b/gcc/testsuite/gcc.dg/cpp/pr36320.c
index d136a69..ebd5191 100644
--- a/gcc/testsuite/gcc.dg/cpp/pr36320.c
+++ b/gcc/testsuite/gcc.dg/cpp/pr36320.c
@@ -4,5 +4,5 @@
 
 int z;
 #if 1
-#elif   /* { dg-error "with no expression" } */
+#elif
 #endif
diff --git a/libcpp/directives.c b/libcpp/directives.c
index ab4f15c..37cd109 100644
--- a/libcpp/directives.c
+++ b/libcpp/directives.c
@@ -2036,23 +2036,16 @@ do_elif (cpp_reader *pfile)
 	}
       ifs->type = T_ELIF;
 
-      if (! ifs->was_skipping)
+      /* See DR#412: "Only the first group whose control condition
+	 evaluates to true (nonzero) is processed; any following groups
+	 are skipped and their controlling directives are processed as
+	 if they were in a group that is skipped."  */
+      if (ifs->skip_elses)
+	pfile->state.skipping = 1;
+      else
 	{
-	  bool value;
-	  /* The standard mandates that the expression be parsed even
-	     if we are skipping elses at this point -- the lexical
-	     restrictions on #elif only apply to skipped groups, but
-	     this group is not being skipped.  Temporarily set
-	     skipping to false to get lexer warnings.  */
-	  pfile->state.skipping = 0;
-	  value = _cpp_parse_expr (pfile, false);
-	  if (ifs->skip_elses)
-	    pfile->state.skipping = 1;
-	  else
-	    {
-	      pfile->state.skipping = ! value;
-	      ifs->skip_elses = value;
-	    }
+	  pfile->state.skipping = ! _cpp_parse_expr (pfile, false);
+	  ifs->skip_elses = ! pfile->state.skipping;
 	}
 
       /* Invalidate any controlling macro.  */

together with a test like the following

#if 1
int i;
#elif 1/0
#endif

#if 1
int j;
#elif
#endif

#if 0
#elif 1/0	/* { dg-error "division by zero" } */
int k;
#endif

#if 0
#elif		/* { dg-error "with no expression" } */
int n;
#endif

#if 1
# if 1
int l;
# elif 1/0
# endif
#endif

#if 1
# if 0
# elif 1/0	/* { dg-error "division by zero" } */
# endif
#endif
Comment 7 Jakub Jelinek 2015-01-22 09:53:26 UTC
-#elif   /* { dg-error "with no expression" } */
+#elif

Perhaps turn it into dg-bogus instead?
Comment 8 Marek Polacek 2015-01-22 13:31:23 UTC
dg-bogus is better, yet.  FWIW, the patch has been successfully regtested/bootstrapped now.
Comment 9 Marek Polacek 2015-01-23 11:58:17 UTC
Author: mpolacek
Date: Fri Jan 23 11:57:43 2015
New Revision: 220035

URL: https://gcc.gnu.org/viewcvs?rev=220035&root=gcc&view=rev
Log:
	DR#412
	PR preprocessor/60570
	* directives.c (do_elif): Don't evaluate #elif conditionals
	when they don't need to be.

	* gcc.dg/cpp/pr36320.c: Turn dg-error into dg-bogus.
	* gcc.dg/cpp/pr60570.c: New test.

Added:
    trunk/gcc/testsuite/gcc.dg/cpp/pr60570.c
Modified:
    trunk/gcc/testsuite/ChangeLog
    trunk/gcc/testsuite/gcc.dg/cpp/pr36320.c
    trunk/libcpp/ChangeLog
    trunk/libcpp/directives.c
Comment 10 Marek Polacek 2015-01-23 11:58:50 UTC
Fixed for GCC 5.
Comment 11 Andrew Pinski 2024-04-02 21:40:43 UTC
*** Bug 36453 has been marked as a duplicate of this bug. ***