compiler icon indicating copy to clipboard operation
compiler copied to clipboard

__attribute__((attr-list)) or [[attr-list]]

Open YashasSamaga opened this issue 7 years ago • 15 comments

#pragma is a preprocessor directive; hence, apart from being ugly (for me at least), it puts limitations on its usage. For example, pragma cannot be used inside substitution pattern of a #define (of a ??; what is the correct technical term?).

If something like the __attribute__(()) in GCC (or __declspec in Microsoft; not symmetric and not as readable as the other two in my opinion) is added, this would get rid of those limitations and also improve readability of the code.

Design ideas

Basic Examples:

Some the attributes used in this section do not exist in the current compiler. I have used them to just present the possible syntax so that viewers can get an idea of how it would look when used in code (some cases such as statement attributes do not have any options that could be used in the current version of the compiler but they could be added in the future so let's consider those as well).

  • function attributes stock __attribute__((naked)) myfunc () { } stock myfunc () __attribute__((naked)) { }

  • function argument attributes stock myfunc(__attribute__((unused)) myarg, normal_arg) { } stock myfunc(myarg __attribute__((unused)) , normal_arg) { }

  • variable attributes new __attribute__((unused)) var; new var __attribute__((unused));

  • label attributes __attribute__((omit-defaults)) mylabel: (potential solution for a part of #266 ) mylabel: __attribute__((omit-default));

  • enumerator attributes

    enum {
      __attribute__((deprecated)) score,
      points __attribute__((deprecated)),
    };
    
    enum __attribute__((unused)) { }
    enum [[unused]] { }
    
  • statement attributes __attribute__((nodestruct)) return 0;

Empty attributes:

stock __attribute__(()) myfunc() { } new __attribute__(()) myvar;

This might provide more flexibility when attributes are a part of substitution pattern.

Trailing/leading commas:

stock __attribute__((deprecated,)) myfunc() { } new __attribute__((,used)) myvar;

This might provide more flexibility when attributes are a part of substitution pattern.

Multiple attribute lists:

stock __attribute__((naked)) __attribute__((deprecated)) myfunc () {}

Multiple attributes in a single attributes list:

stock __attribute__((naked, deprecated)) myfunc() {}

Attribute parameters:

stock __attribute__((naked(32))) myfunc () {}

stock __attribute__((deprecated("because bla"))) myfunc () {}

Changes:

  • removed [[]] syntax
    • Were this done, attribute or another function-like macro would be VASTLY preferable to [[]] for backwards-compatibility. It would be very easy to strip them in the old compiler with:

      #define __attribute__(%0)

      Removing [[]] in a conditional manner would be nigh-on impossible.

YashasSamaga avatar Jan 19 '18 13:01 YashasSamaga

https://github.com/pawn-lang/YSI-Includes/blob/d31e1916454e984bc927eee2102532ed25d5fa77/YSI_Internal/y_distribute.inc#L111-L130

https://github.com/pawn-lang/YSI-Includes/blob/b2993bdaed33642c3c48f94ed063eb84ef4c91f7/YSI_Visual/y_commands/impl.inc#L145-L148

Were this done, __attribute__ or another function-like macro would be VASTLY preferable to [[]] for backwards-compatibility. It would be very easy to strip them in the old compiler with:

#define __attribute__(%0)

Removing [[]] in a conditional manner would be nigh-on impossible.

There is also __pragma in MSVC (I don't know about others), which would be good for consistency in the same way as #emit/__emit() mirror each other.

Y-Less avatar Jan 19 '18 13:01 Y-Less

I'm up for __pragma as much as I like the __attribute__ syntax/name I agree with Y_Less on the #emit/__emit() point.

This looks like a promising idea though! Being able to inline these will be far superior to the directive method.

Southclaws avatar Jan 19 '18 13:01 Southclaws

Actually, it should really be __Pragma which would match the other new compiler symbols __Pawn and __PawnBuild.

Y-Less avatar Jul 10 '18 14:07 Y-Less

Not that I like that naming scheme...

Y-Less avatar Jul 10 '18 14:07 Y-Less

There are no operators named in the CamelCase style yet, do we really have to make one? Regarding __PawnBuild, it was obviously named for consistency with __Pawn, and __Pawn is not even a new symbol, it's from the original compiler and was named that way for who knows what reason (maybe because the original Pawn author thought the name of that constant should start from a capital letter if it contains the language name?) The point is, even if constants in CamelCase exist in the compiler, it doesn't mean we have to name the other new things in the same style.

Daniel-Cortez avatar Jul 10 '18 16:07 Daniel-Cortez

That's pretty much exactly what that means. Things in the compiler should be consistent, not named a dozen different ways.

Y-Less avatar Jul 11 '18 01:07 Y-Less

Though I did mention somewhere else that as long as there is consistency, maybe __PawnBuild could be changed instead.

Y-Less avatar Jul 11 '18 01:07 Y-Less

Plus the fact that __Pawn was in the original compiler only adds to its use as precedent.

Y-Less avatar Jul 11 '18 01:07 Y-Less

  1. Do we have enough consensus for this to be implemented?

  2. Should every option that is available through __TBD be made available through #pragma and vice-versa? (TBD = to be decided)

  3. What options must be provided?

YashasSamaga avatar Jul 11 '18 14:07 YashasSamaga

  1. Yes! This is really useful for library writers. The attributes can be placed inside substitution patterns of #defines.

  2. In my opinion, we could keep these two features entirely separate. The #pragma is used to modify general compiler settings such as compatibility mode, rational number support, etc. and this new method be used for attributes that actually affect symbols.

  3. #pragma options __TBD options
    option deprecated
    compat unused
    rational nodestruct
    amxlimit naked
    amxram
    codepage
    ctrlchar
    compress
    dynamic
    library
    overlay
    pack
    semicolon
    tabsize

    The deprecated, unused and naked options will remain with #pragma for backward compatibility. The new attributes such as nodestruct could be supported only by __TBD.

YashasSamaga avatar Jul 11 '18 14:07 YashasSamaga

I'd like to work on implementing at least some of the attributes, but I have a few questions:

  • Do we have a consensus on what keyword to use? If it's __attribute__, would it be OK to implement it without the trailing underscores (__attribute), or do they have a special meaning?
  • Is it necessary to wrap the attributes in two pairs of parentheses? Shouldn't one pair be enough? Or maybe we could even make them optional if the user needs to specify only one attribute?
  • Now that we have #pragma unread and #pragma unwritten, maybe we should have similar attributes as well?
  • Should we make attribute unused applicable for functions, so its functionality would be similar to the stock specifier?
  • Should we warn the user if an attribute is repeated (e.g. __TBD(unused, unused) or __TBD(deprecated "some text") symbol __TBD(deprecated "other text"))?

Daniel-Cortez avatar May 09 '20 13:05 Daniel-Cortez

Is it necessary to wrap the attributes in two pairs of parentheses? Shouldn't one pair be enough? Or maybe we could even make them optional if the user needs to specify only one attribute?

I picked up the syntax from GCC. It seems the double brackets are there for compatibility with other compilers.

Should we warn the user if an attribute is repeated (e.g. __TBD(unused, unused) or __TBD(deprecated "some text") symbol __TBD(deprecated "other text"))?

Ignoring would offer more flexibility while writing preprocessor code.

YashasSamaga avatar May 09 '20 13:05 YashasSamaga

OK, I see no reason why this should be different to #pragma; aAll the talk about what should be available to which is just IMHO a pointless complication. Or at the very least make the options available to __TBD a strict subset of those available to #pragma, because @YashasSamaga is right about some only being needed once at the top, but there's no reason not to keep #pragma as an option for the rest. #pragma is still the main canonical way to do things, and so should retain full capabilities, with this extension available mainly for advanced use cases like libraries.

As to syntax, I'd propose:

__Pragma("options here")

For several reasons:

  1. Basing it on a hack in another language to enable backwards compatibility with obsolete compilers for said other language is just right out as an option IMHO.

  2. This is now a first-class part of the language, unlike #pragma, so it should conform to all the rules of pawn as much as possible. Doing __Pragma(unused a) is just brand new syntax for one tiny use-case, and then you get all the questions about how those contents themselves interact with macros. Putting the commands in a string totally removes questions about how the two different languages (pawn and pragma commands) interact. Basically, quasi-quoting. This also means that the existing #pragma code can be reused in it's entirety on the finally parsed string.

  3. __Pragma (or __pragma) fits with other conventions in the language - #emit and __emit, __Pawn, and more.

This keeps the two systems as close as possible, which helps with coding, testing, teaching, and learning. Making them very different IMHO serves no purpose and just complicates things as then you have to go out of your way to explain the differences, and explain why expressions in the ()s don't match expressions anywhere else in the language.

Y-Less avatar May 09 '20 16:05 Y-Less

I picked up the syntax from GCC. It seems the double brackets are there for compatibility with other compilers.

Then this shouldn't be a problem for us, as Pawn macros work in a different way and we can easily define a compatibility macro like this:

#define __TBD(%0)

OK, I see no reason why this should be different to #pragma; aAll the talk about what should be available to which is just IMHO a pointless complication.

So, in other words, all repeated options, attributes being inapplicable to certain kinds of symbols (e.g. naked is only applicable to functions, but not variables, arrays or constants), and any other kinds of errors should be silently ignored in __TBD? Did I understand you correctly? My main concern was that originally Pawn was positioned as a safe language with maximum control over errors. But on the other hand, this is not the original Pawn...

Or at the very least make the options available to __TBD a strict subset of those available to #pragma, because @YashasSamaga is right about some only being needed once at the top, but there's no reason not to keep #pragma as an option for the rest.

I never said anything about __TBD having all options from #pragma. Or was this about me suggesting the inclusion of unread and unwritten into the list of available options, and you meant that the list should consist only from what @YashasSamaga posted 2 years ago (deprecated, unused, nodestruct, naked)? If not, then what is the exact list of options that you see fitting for __TBD?

Putting the commands in a string totally removes questions about how the two different languages (pawn and pragma commands) interact.

... but brings other questions, such as:

  1. What should we use as delimiters for attributes - commas with optional whitespaces before/after them, as proposed initially
__TBD("unused, nodestruct")

, or just whitespaces are enough?

__TBD("unused nodestruct")
  1. How are we going to handle the string arguments for attributes (f.e., the deprecation message)? Like this:
__TBD("deprecated \"- please use OtherFunction() instead\"")

, this:

__TBD("deprecated(- please use OtherFunction() instead)")

, or this (combined):

__TBD("deprecated(\"- please use OtherFunction() instead\")")

?

__Pragma (or __pragma) fits with other conventions in the language

So you mean it's alright if I implement the keyword as __pragma, in lowercase? Because I see no reason why __Pragma would be better, especially since currently we have no operators named in CamelCase.

Daniel-Cortez avatar May 10 '20 16:05 Daniel-Cortez

What should we use as delimiters for attributes - commas with optional whitespaces before/after them, as proposed initially

Why would you delimit attributes? You can't do that with #pragma:

#pragma unused, nodestruct

How are we going to handle the string arguments for attributes (f.e., the deprecation message)? Like this:

Again, same as in #pragma:

#pragma deprecated doesn't need quotes

especially since currently we have no operators named in CamelCase.

__Pawn, __PawnBuild. But they are they only two, so probably the outliers rather than the pattern.

Y-Less avatar May 11 '20 10:05 Y-Less