aaron.ballman added a comment.

In D146148#4227088 <https://reviews.llvm.org/D146148#4227088>, @zahiraam wrote:

> In D146148#4224862 <https://reviews.llvm.org/D146148#4224862>, @rjmccall 
> wrote:
>
>> In D146148#4224094 <https://reviews.llvm.org/D146148#4224094>, 
>> @aaron.ballman wrote:
>>
>>> In D146148#4222306 <https://reviews.llvm.org/D146148#4222306>, @zahiraam 
>>> wrote:
>>>
>>>> In D146148#4221651 <https://reviews.llvm.org/D146148#4221651>, @rjmccall 
>>>> wrote:
>>>>
>>>>> Zahira, this is what I was asking you when I asked whether modifying the 
>>>>> math.h header was acceptable: whether you were prepared to accept that 
>>>>> the warning would only fire on system math.h headers that we'd modified, 
>>>>> or whether you cared about making it work with non-cooperative headers.  
>>>>> I wasn't asking if you were willing to change the test code.
>>>>
>>>> Okay sorry about the confusion. I think the diagnostic should fire when 
>>>> the user is including system's math.h and using float_t inside a scope 
>>>> cotaining a #pragma clang fp eval-method. 
>>>> I am not sure what you mean by "cooperative headers"?
>>>
>>> Ones that know about the special marking and use it (cooperative) or ones 
>>> that don't use the special marking (uncooperative). My intuition is that 
>>> we'll want this to work with any math.h because the problem still exists if 
>>> you use an older C standard library release with a newer Clang.
>>
>> Right.  It's not a great solution for standard stuff like this.
>>
>>>>> - We add a math.h compiler header that `#include_next`s the system math.h 
>>>>> and then adds the attribute.  I believe you can just add an attribute to 
>>>>> a typedef retroactively with something like `typedef float_t float_t 
>>>>> __attribute__((whatever))`.
>>>>
>>>> So when a user writes:
>>>>
>>>>   #include <math.h>
>>>>    int foo()
>>>>    {
>>>>       #pragma clang fp eval_method(source)
>>>>      return sizeof(float_t);
>>>>    }
>>>>
>>>> It would be as though the user wrote:
>>>>
>>>>   #include "math.h"
>>>>   int foo()
>>>>   {
>>>>      #pragma clang fp eval_method(source)
>>>>     return sizeof(float_t);
>>>>   }
>>>>
>>>> where the content of this new math header being:
>>>>
>>>>   #include_next <math.h>
>>>>   typedef float_t float_t __attribute__((whatever));
>>>>   typedef double_t double_t __attribute__((whatever));
>>>
>>> Correct.
>>
>> Right.  To be clear, this is a general thing that we already do to a bunch 
>> of other headers.  It doesn't require any special handling, the compiler's 
>> include directory is just the first entry on the search list for system 
>> headers.
>>
>>>>> - We do checks on every typedef declaration.  There's a 
>>>>> builtin-identifier trick that we do with library functions that we should 
>>>>> be able to generalize to typedefs, so you wouldn't need to actually do 
>>>>> string comparisons, you'd just check whether the `IdentifierInfo*` was 
>>>>> storing a special ID.  We'd set that up in `initializeBuiltins` at the 
>>>>> start of the translation unit, so the overhead would just be that we'd 
>>>>> create two extra `IdentifierInfo*`s in every TU.
>>>>>
>>>>> The builtin ID logic is currently specific to builtin *functions*, and I 
>>>>> don't think we'd want to hack typedef names into that.  But the same 
>>>>> storage in `IdentifierInfo*` is also used for identifying the ObjC 
>>>>> context-sensitive keywords, by just offsetting the builtin IDs by the 
>>>>> NUM_OBJC_KEYWORD.  You should be able to generalize that by also 
>>>>> introducing a concept of a builtin *type* name, so that e.g. IDs in 
>>>>> [0,NUM_OBJC_KEYWORDS) are ObjCKeywordKinds, IDs in [NUM_OBJC_KEYWORDS, 
>>>>> NUM_OBJC_KEYWORDS+NUM_BUILTIN_TYPES) are BuiltinTypeKinds (when you 
>>>>> subtract NUM_OBJC_KEYWORDS), and IDs in 
>>>>> [NUM_OBJC_KEYWORDS+NUM_BUILTIN_TYPES,∞) are builtin function IDs (when 
>>>>> you subtract NUM_OBJC_KEYWORDS+NUM_BUILTIN_TYPES).
>>>>
>>>> Need to look at this more closely to understand what you are suggesting.
>>>
>>> Basically, he's saying that instead of doing a string comparison against 
>>> the name of the typedef, we can ask the typedef for its `IdentifierInfo *` 
>>> for the name and do a pointer comparison against an `IdentiferInfo *` 
>>> that's cached.
>>
>> That's a trick we could do, but I'm actually suggesting a step better than 
>> that.  The way we handle builtin functions is that we have bits in the 
>> `IdentifierInfo` structure saying that the identifier is a builtin name.  
>> Those bits are generally ignored except by a few places in Sema that check 
>> for them during lookup.  We eagerly create those identifiers and set those 
>> bits at the start of the TU.  We could do the same trick for these names, so 
>> that when we're declaring a typedef at global scope we just check whether 
>> the name is special and trigger some special processing only if so.  It 
>> would add a very, very small overhead to processing every typedef 
>> declaration, comparable to the overhead we add to processing every function 
>> declaration in order to support the declaration of "builtin" library 
>> functions.
>>
>>>> @rjmccall do you have a preference for any one of these solutions? 
>>>> @aaron.ballman ?
>>>> Thanks.
>>>
>>> My slight preference is to modify math.h, but I'd also be okay with doing 
>>> the pointer comparison trick. I think there are less includes of math.h 
>>> than there are typedefs in a TU, so adding a tiny bit of compile time 
>>> overhead when including math.h seems to be a better tradeoff.
>>
>> Yes, adding a math.h to the compiler header seems like the cleanest thing if 
>> it doesn't cause integration headaches.  The redeclaration thing would be a 
>> problem if there are math.h's that don't declare these typedefs, for example 
>> (if there isn't a way to check for that).
>
> @rjmccall, @aaron.ballman and I looked over various math header files to see 
> when float_t/double_t started. It looks like it started with C99 but is 
> allowed with C89 with MS for example.
>
> In glibc the typedefs are guarded with an #ifdef __USE_ISOC99__.
>
> MS:
>
>   #if defined _M_IX86 && _M_IX86_FP < 2 && !defined _M_FP_FAST
>      typedef long double float_t;
>      typedef long double double_t;
>   #else
>      typedef float  float_t;
>      typedef double double_t;
>   #endif
>
> It's not guarded with the version of the standard. So, including math.h even 
> with std=c89 would have a float_t/double_t.
>
> MacOS, the definition of float_t is not guarded either. We would have the 
> same issue than with MS.
>
>   /*  Define float_t and double_t per C standard, ISO/IEC 9899:2011 7.12 2,   
>     
>       taking advantage of GCC's __FLT_EVAL_METHOD__ (which a compiler may     
>     
>       define anytime and GCC does) that shadows FLT_EVAL_METHOD (which a      
>     
>       compiler must define only in float.h).                                  
>   *\
>   /
>   #if __FLT_EVAL_METHOD__ == 0
>       typedef float float_t;
>       typedef double double_t;
>   #elif __FLT_EVAL_METHOD__ == 1
>       typedef double float_t;
>       typedef double double_t;
>   #elif __FLT_EVAL_METHOD__ == 2 || __FLT_EVAL_METHOD__ == -1
>
> It looks like we have an array of choices that might make the header method a 
> bit uncontrollable.
> So, if you all agree I will start looking at the identifier solution that you 
> are proposing above. 
> Thanks.

I think the identifier solution makes the most sense. The situation I'm mostly 
worried about is where the system math.h does not expose `float_t` but our 
math.h would then add it -- I don't think we've got the introspection 
capabilities to be able to determine if the typedef is or isn't present from 
within our math.h header file, and I don't think we want a pile of 
libc-specific macros guarding the typedefs.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D146148/new/

https://reviews.llvm.org/D146148

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to