Welcome, Guest. Please login or register.

Author Topic: Dear God, WHY?!?!  (Read 7508 times)

Description:

0 Members and 1 Guest are viewing this topic.

Offline KarlosTopic starter

  • Sockologist
  • Global Moderator
  • Hero Member
  • *****
  • Join Date: Nov 2002
  • Posts: 16878
  • Country: gb
  • Thanked: 5 times
    • Show only replies by Karlos
Dear God, WHY?!?!
« on: August 08, 2009, 02:03:22 PM »
So, for the first weekend in ages, I'm actually getting to do some amiga coding.

I have some code that is attempting to span the bridge between gcc 2.95 (on the classic) and 4 (on the A1) as well as under linux.

Unfortunately, somebody decided that GCC 4's preprocessor (and working back through older versions, 3's too probably) needed to be really broken.

I have a macro that uses one of two ways of throwing an exception, depeding on compilation options:

method 1:

#define THROW_NESTED_EXCEPTION(cname, except) EXNGPrivate::throw##cname##except

method 2:

#define THROW_NESTED_EXCEPTION(cname, except) throw cname##::##except

This is the (expected) expansion behaviour that you get with 2.95.x

method1:

THROW_NESTED_EXCEPTION(Foo, InvalidBar()); -> EXNGPrivate::throwFooInvalidBar();

method2:

THROW_NESTED_EXCEPTION(Foo, InvalidBar()); -> throw Foo::InvalidBar();

Both work exactly as expected. Method 1 expands into a debugging function call that handles throwing the exception in a different way (for example, logging that the exception is about to be raised, then raising it).

Under GCC 4, I have ran into this nugget of sheer, unadulterated rubbish when compiling with method 2:

THROW_NESTED_EXCEPTION(Application, TooFewArguments());

/extropia/exng2/libsource/systemlib/startup.cpp:93:1: error: pasting "Application" and "::" does not give a valid preprocessing token
/extropia/exng2/libsource/systemlib/startup.cpp:93:1: error: pasting "::" and "TooFewArguments" does not give a valid preprocessing token

In other words, the preprocessor cannot paste together the macro arguments with the scope of resolution operator without considering the interim result as an invalid token. Why for pity's sake?

Searching for this class of error, I find thousands of links (mostly about pasting with "." however) but no actual explanation as to why this is considered an error.

I'm not attempting to stringify (#) the arguments, I just want it to concatenate the arguments in the specified manner and emit the damn code.

Anybody come across this behaviour before?
« Last Edit: August 08, 2009, 02:09:24 PM by Karlos »
int p; // A
 

Offline KarlosTopic starter

  • Sockologist
  • Global Moderator
  • Hero Member
  • *****
  • Join Date: Nov 2002
  • Posts: 16878
  • Country: gb
  • Thanked: 5 times
    • Show only replies by Karlos
Re: Dear God, WHY?!?!
« Reply #1 on: August 08, 2009, 03:14:40 PM »
OK, after some caffeine, experimentation and a fair amount of swearing, I have discovered the following:

Code: [Select]
#include <cstdio>

#define PP_CONCAT(a,b) a##::##b

namespace Foo {
  void bar()
  {
    std::puts(&quot;gcc 4 sux&quot;);
  }
};

int main()
{
  PP_CONCAT(Foo,bar());
  return 0;
}

just cannot be made to work with the preprocessor as of gcc 2.97. Since 3 and beyond, this results in an "invalid preprocessor token", regardless of the options you pass through to the preprocessor (including -traditional-cpp).

However, I have found that the following does appear to work:

Code: [Select]
#include

#define PP_CONCAT(a,b,c) a##c::c##b

namespace Foo {
  void bar()
  {
    std::puts("gcc 4 sux");
  }
};

int main()
{
  PP_CONCAT(Foo,bar(),);

  return 0;
}

So, defining an additional argument to the macro to be pasted between the first and the scope of resolution operator seemingly works when you omit to pass anything for that argument.

That is pretty damned weird
« Last Edit: August 08, 2009, 03:31:32 PM by Karlos »
int p; // A
 

Offline lsmart

  • Sr. Member
  • ****
  • Join Date: Jun 2009
  • Posts: 433
    • Show only replies by lsmart
Re: Dear God, WHY?!?!
« Reply #2 on: August 08, 2009, 03:18:39 PM »
Hmm, sounds strange. Are you sure you are compiling as C++ instead of vanilla C (i.e. have you invoked g++)? What compiler options are you using?
 

Offline KarlosTopic starter

  • Sockologist
  • Global Moderator
  • Hero Member
  • *****
  • Join Date: Nov 2002
  • Posts: 16878
  • Country: gb
  • Thanked: 5 times
    • Show only replies by Karlos
Re: Dear God, WHY?!?!
« Reply #3 on: August 08, 2009, 03:20:39 PM »
And with that:

Code: [Select]

# if defined(__GNUC__) && (__GNUC__ < 3) && (__GNUC_MINOR__ <= 97)
# define THROW_NESTED_EXCEPTION(cname, except) throw cname##::##except
# else
# define THROW_NESTED_EXCEPTION_REAL(cname, except, dummy) throw cname##dummy::dummy##except
# define THROW_NESTED_EXCEPTION(a, b) THROW_NESTED_EXCEPTION_REAL(a, b, )
# endif


Talk about having to jump through hoops.
int p; // A
 

Offline KarlosTopic starter

  • Sockologist
  • Global Moderator
  • Hero Member
  • *****
  • Join Date: Nov 2002
  • Posts: 16878
  • Country: gb
  • Thanked: 5 times
    • Show only replies by Karlos
Re: Dear God, WHY?!?!
« Reply #4 on: August 08, 2009, 03:22:46 PM »
Quote from: lsmart;518496
Hmm, sounds strange. Are you sure you are compiling as C++ instead of vanilla C (i.e. have you invoked g++)? What compiler options are you using?

Absolutely sure.

On the gcc4 build:

CXXFLAGS = -O3 -Wall -W -Wno-unused-parameter -I$(INCDIR) -I$(INCDIR)platforms/$(PLATFORM) -fPIC -DXP_PLATFORM="$(PLATFORM)/"

the line in the makefile:
   $(CXX) -shared -Wl,-soname,$(LIB).$(VER) -o $(LIBDIR)$(LIB).$(VER).$(REV) $(OBJ);

I should point out that the target in this case is a .so (both for linux and OS4.1)

It would appear that "modern ISO compliant C preprocessors" simply don't like pasting together bits of text with operators. Try googling for the error, people all over have had it.
« Last Edit: August 08, 2009, 03:24:40 PM by Karlos »
int p; // A
 

Offline Jose

  • Hero Member
  • *****
  • Join Date: Feb 2002
  • Posts: 2871
    • Show only replies by Jose
Re: Dear God, WHY?!?!
« Reply #5 on: August 08, 2009, 03:31:41 PM »
Well, I once tried to make a serialization library for C based on the preprocessor. Lost a bunch of moths trying it and ended up completely frustrated cause preprocessors vary in implementations and even crash when you through complicated things at them. Never understood how the boost library can be so based on the preprocessor.
\\"We made Amiga, they {bleep}ed it up\\"
 

Offline Jose

  • Hero Member
  • *****
  • Join Date: Feb 2002
  • Posts: 2871
    • Show only replies by Jose
Re: Dear God, WHY?!?!
« Reply #6 on: August 08, 2009, 03:34:08 PM »
Maybe the "::" could be passed as an argument, but if you got it working that weird way it's already good.
\\"We made Amiga, they {bleep}ed it up\\"
 

Offline KarlosTopic starter

  • Sockologist
  • Global Moderator
  • Hero Member
  • *****
  • Join Date: Nov 2002
  • Posts: 16878
  • Country: gb
  • Thanked: 5 times
    • Show only replies by Karlos
Re: Dear God, WHY?!?!
« Reply #7 on: August 08, 2009, 04:35:38 PM »
Quote from: Jose;518504
Maybe the "::" could be passed as an argument, but if you got it working that weird way it's already good.

Tried that, no joy.

After some experimentation I have discovered that pretty much any C/C++ operator (especially ., -> etc) doesn't like being used in ## concatenation. Which is completely stupid.

IMO, that's totally and utterly broken. It should not be up the the preprocessor to dictate what constitutes "valid" output from concatenating two pieces of text. It should just do the job and if the result is meaningless garbage, that's up to the compiler to diagnose.

It isn't the first issue I have had with gcc 4's preprocessor. It has issues with computed includes too.
int p; // A
 

Offline ChaosLord

  • Hero Member
  • *****
  • Join Date: Nov 2003
  • Posts: 2608
    • Show only replies by ChaosLord
    • http://totalchaoseng.dbv.pl/news.php
Re: Dear God, WHY?!?!
« Reply #8 on: August 08, 2009, 07:26:38 PM »
Quote from: Jose;518503
Lost a bunch of moths trying it and ended up completely frustrated cause preprocessors vary in implementations and even crash when you through complicated things at them. Never understood how the boost library can be so based on the preprocessor.

I had/have the same problem.
Wanna try a wonderfull strategy game with lots of handdrawn anims,
Magic Spells and Monsters, Incredible playability and lastability,
English speech, etc. Total Chaos AGA
 

Offline ChaosLord

  • Hero Member
  • *****
  • Join Date: Nov 2003
  • Posts: 2608
    • Show only replies by ChaosLord
    • http://totalchaoseng.dbv.pl/news.php
Re: Dear God, WHY?!?!
« Reply #9 on: August 08, 2009, 07:28:25 PM »
@Karlos

Use a different preprocessor.
Wanna try a wonderfull strategy game with lots of handdrawn anims,
Magic Spells and Monsters, Incredible playability and lastability,
English speech, etc. Total Chaos AGA
 

Offline KarlosTopic starter

  • Sockologist
  • Global Moderator
  • Hero Member
  • *****
  • Join Date: Nov 2002
  • Posts: 16878
  • Country: gb
  • Thanked: 5 times
    • Show only replies by Karlos
Re: Dear God, WHY?!?!
« Reply #10 on: August 08, 2009, 08:27:50 PM »
Quote from: ChaosLord;518522
@Karlos

Use a different preprocessor.


No need, I found a work around for it. Changing preprocessor is not a good build dependency ;)
int p; // A
 

Offline A1260

  • Hero Member
  • *****
  • Join Date: Jul 2007
  • Posts: 693
    • Show only replies by A1260
Re: Dear God, WHY?!?!
« Reply #11 on: August 08, 2009, 09:19:33 PM »
with jupiter lander in mind i guess this set a stop for the new amiga crap games that are floathing up from the sewer every now and then. (burp)
« Last Edit: August 08, 2009, 09:25:21 PM by A1260 »
 

Offline KarlosTopic starter

  • Sockologist
  • Global Moderator
  • Hero Member
  • *****
  • Join Date: Nov 2002
  • Posts: 16878
  • Country: gb
  • Thanked: 5 times
    • Show only replies by Karlos
Re: Dear God, WHY?!?!
« Reply #12 on: August 08, 2009, 09:52:03 PM »
Quote from: A1260;518528
with jupiter lander in mind i guess this set a stop for the new amiga crap games that are floathing up from the sewer every now and then. (burp)


Huh?
int p; // A
 

Offline jj

  • Lifetime Member
  • Hero Member
  • *****
  • Join Date: Feb 2002
  • Posts: 4052
  • Country: wales
  • Thanked: 2 times
  • Gender: Male
    • Show only replies by jj
Re: Dear God, WHY?!?!
« Reply #13 on: August 08, 2009, 10:49:53 PM »
rule of thumb ignore anything h has to say.  Its either troling or complete jiberish
“We don't stop playing because we grow old; we grow old because we stop playing.” - George Bernard Shaw

Xbox Live: S0ulA55a551n2
 
Registered MorphsOS 3.13 user on Powerbook G4 15"
 

Offline ejstans

  • Newbie
  • *
  • Join Date: Jun 2009
  • Posts: 48
    • Show only replies by ejstans
Re: Dear God, WHY?!?!
« Reply #14 on: August 08, 2009, 10:52:22 PM »
Quote from: Karlos;518506
Tried that, no joy.

After some experimentation I have discovered that pretty much any C/C++ operator (especially ., -> etc) doesn't like being used in ## concatenation. Which is completely stupid.

IMO, that's totally and utterly broken. It should not be up the the preprocessor to dictate what constitutes "valid" output from concatenating two pieces of text. It should just do the job and if the result is meaningless garbage, that's up to the compiler to diagnose.

It isn't the first issue I have had with gcc 4's preprocessor. It has issues with computed includes too.

You are in undefined behavior-land. From the C++98 standard:

"16.3.3 The ## operator
 [...]
 3 For both object-like and function-like macro invocations, before the replacement list is reexamined for more macro names to replace, each instance of a ## preprocessing token in the replacement list (not from an argument) is deleted and the preceding preprocessing token is concatenated with the following preprocessor token. If the result is not a valid preprocessing token, the behavior is undefined. The resulting token is available for further macro replacement. The order of evaluation of ## operators is unspecified."

The important part here is "If the result is not a valid preprocessing token, the behavior is undefined". Gcc is rather nice to point this out :)

Let's look at your fix:

#define PP_CONCAT(a, b, c) a##c::c##b

This (seemingly) works because 'a' and 'c' are concatenated (and 'c' and 'b' likewise) and since you pass in an empty argument the result is simply 'a' (and 'b') which is a valid preprocessing token. Or is it? Actually, passing in an empty argument results in undefined behaviour, so this is not a good fix...

But what if we suppose passing an in empty argument was in fact well-defined and acted like above? The result would simply be the same as:

#define PP_CONCAT(a, b) a::b

So why mix in the concatenting operator? :)
"It is preferable not to travel with a dead machine."

A500 1.3 / 512KiB slowmem / GVP HD8 w/ 8MiB fastmem & 52MB HDD
A600 2.05 / 1GB SSD
A1200 3.0 / Blizzard 1200/4 w/ 68882 @ 33MHz / 1GB SSD
A1200T 3.0 / Apollo 1260 w/ 68EC060 @ 50MHz & 16 MiB fastmem / 4GB SSD