[cfe-dev] Embedded conditionals not being evaluated correctly?

Michael Jackson mike.jackson at bluequartz.net
Thu Jul 29 10:30:44 PDT 2010


On Jul 29, 2010, at 1:03 PM, Douglas Gregor wrote:

>
> On Jul 29, 2010, at 9:03 AM, Michael Jackson wrote:
>
>> I have code that looks something like this:
>>
>>
>> bool evaluate(int i, int j) { return (i < j) ? true : false; }
>>
>> void function()
>> {
>> int i = 0;
>> int j = 1;
>> if ( evaluate(i, j) == true ) { }
>> else { std::cout << "This is BAD" << std::endl; }
>>
>> }
>>
>> when I compile this code with clang (latest SVN head) and then run  
>> it I will get
>> the "This is BAD" printed out which is obviously NOT correct. If I  
>> change the code
>> to introduce an intermediate variable:
>>
>> bool b = evaluate(i,j);
>> if ( b == true ) { }
>> else { std::cout << "This is BAD" << std::endl; }
>>
>> this this compiles and runs just fine.
>>
>> The fun part in all of this is that I am unable to create a small  
>> reproducible test case
>> for a bug report. I have used the OS X 10.6 gdb to debug through  
>> the code and verify what
>> should really be going on and that the executable is NOT matching  
>> what should be happening.
>>
>> If I compile my code with GCC then I get the expected results.
>
> Unfortunately, that's not much for us to go on, since we don't know  
> the code in question. It may not even be a Clang bug, if there's  
> undefined behavior or order-of-evaluation issues involved.
>
>> My question is simple: Are there known or questionable issues with  
>> clang++ and nested conditionals
>> that evaluate to C++ bool? I did some searches through the clang  
>> bugzilla but did not identify my problems.
>
>
> Does the actual condition involve temporary objects? The most likely  
> culprit would be our handling of temporaries, e.g., that we destroy  
> a temporary too soon, forget to destroy a temporary that matters, or  
> perform some kind of unsanctioned copy.
>
> 	- Doug

Just some more info on this. I have the following code:

MXA_REQUIRE(metaData->isValid(errorMessage) == false);

where MXA_REQUIRE is a macro:

#define MXA_REQUIRE( P ) \
   if ( (P) == false) \
   {MXA_TEST_THROW_EXCEPTION( #P)}

when the above is fully expanded it gives:
   if ( (metaData->isValid(errorMessage) == false) == false)
     {throw TestException( "metaData->isValid(errorMessage) == false",  
"/Users/mjackson/Workspace/MXADataModel/Tests/DataModelTest.cpp", 81);
   }

So I placed the following code in my program (Not the line numbers)
1:  bool b = metaData->isValid(errorMessage);
2:  std::cout << "b: " << (int)b << std::endl;
3:  if ( (metaData->isValid(errorMessage) == false) == false)
4:    {
5:       throw TestException( "metaData->isValid(errorMessage) ==  
false",
6:       "/Users/mjackson/Workspace/MXADataModel/Tests/ 
DataModelTest.cpp", 81);
7:  }

and I get the following output:
b: 0
TestRequiredMetaData()                                          FAILED
     Reason: metaData->isValid(errorMessage) == false
     File:   /Users/mjackson/Workspace/MXADataModel/Tests/ 
DataModelTest.cpp
     Line:   81

Which means that variable "b" evaluated correctly to "false" in line  
1. In line 3 something goes wrong and we get the following:
   if (( true == false) == false) which then triggers the exception to  
be thrown which is INCORRECT.

If I change line 3 to be:
3: f ( (b == false) == false)
  then I get the "correct" result. So Doug's ideas are probably  
correct. The issue I am still having is getting this down to a  
reproducible test case.

Thanks
Mike Jackson




More information about the cfe-dev mailing list