Skip to content

Avoid C99 typedef redeclaration error #15079

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed

Conversation

iluuu1994
Copy link
Member

Fixes GH-15070

@petk
Copy link
Member

petk commented Jul 23, 2024

I wonder if there might be some more issues related to this typedef redefinition warnings (or errors on some compiler configurations). #13347 Another one, I've also seen in the ext/dom and I think one in ext/opcache somewhere but if the build on that macOS with GCC 4.2 works out then that's fine I guess. I'll also retest it with my build system a bit.

@iluuu1994
Copy link
Member Author

I do think we should seriously consider bumping the compiler requirement to C11 soon. We should do so before investing too much time here.

@cmb69
Copy link
Member

cmb69 commented Jul 23, 2024

@barracuda156, could you please check if this compiles with the old GCC?

@iluuu1994
Copy link
Member Author

That would be great. I wasn't actually able to test this, -std=c99 alone is not enough to trigger an error.

Copy link
Member

@cmb69 cmb69 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good to me; a different solution might be to include zend_types.h instead of zend_portability.h.

@cmb69
Copy link
Member

cmb69 commented Jul 23, 2024

I do think we should seriously consider bumping the compiler requirement to C11 soon.

Well, I just looked and couldn't even find any user targeted information on the C99 requirement (neither in the docs which say you need an "An ANSI C compiler", nor in README.md). Maybe this should be fixed first, before bumping the compiler requirements to C11 (although I don't have strong feelings about this).

@iluuu1994
Copy link
Member Author

iluuu1994 commented Jul 23, 2024

@cmb69 It's here, quite hidden.

1. PHP is implemented in C99.

Edit: Oh, you edited that, so you're probably aware. Yes, that's not particularly user-targeted, and yes https://www.php.net/manual/en/install.unix.php is very much outdated.

@morrisonlevi
Copy link
Contributor

I think this small PR is okay. But honestly, the user's OS is far-outdated, from 2009. We should not spend significant effort maintaining something so old.

typedef struct _zend_object_iterator zend_object_iterator;
typedef struct _zval_struct zval;
/* Intentionally avoid typedef because of C99 redeclaration errors. */
struct _zend_array;
Copy link
Member

@TimWolla TimWolla Jul 23, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seeing this, I already wondered before: Why is the struct tag even prefixed with an underscore instead of matching the typedef'd name exactly?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is just an convention to avoid having identical names. And maybe also as a hint that clients should use the typedef'd name.

@cmb69
Copy link
Member

cmb69 commented Jul 23, 2024

@morrisonlevi, for me, this is not about supporting old compilers and build tools, but to stick to the given standard (C99). There may be even new compilers who complain about this, at least when advised (e.g. https://clang.llvm.org/docs/DiagnosticsReference.html#wtypedef-redefinition).

@iluuu1994
Copy link
Member Author

iluuu1994 commented Jul 23, 2024

There may be even new compilers who complain about this, at least when advised

@cmb69 Even though this is enabled by default, Clang only warns about this with -std=c99.

Maybe I misunderstood your statement, but if we correctly supplied the -std=c11 flag when bumping to C11, there should be no C99 warnings emitted by compilers supporting C11.

@barracuda156
Copy link

@barracuda156, could you please check if this compiles with the old GCC?

@cmb69 Sure, will do it soon and update you.

@iluuu1994
Copy link
Member Author

@barracuda156 Please wait for a few more hours. I noticed that there are many more new errors like this. I'll update this PR.

@barracuda156
Copy link

I think this small PR is okay. But honestly, the user's OS is far-outdated, from 2009. We should not spend significant effort maintaining something so old.

@morrisonlevi This is not the issue. We have gcc15 (current master) working on this 2009 macOS, so there is no problem to support any C standard. But if C11 is not required, then the code is supposed to compile with C99.

@nielsdos
Copy link
Member

From a quick google it seems that C11 support was introduced in gcc 4.7, and "GCC 4.9 Changes: “ISO C11 support is now at a similar level of completeness to ISO C99 support". GCC 4.9 is from 2014 and GCC 4.7 is from 2012. So the compilers are 10-12 years old. Does it make sense to make these changes? You'd also have to make the changes on lower branches I guess...

@iluuu1994
Copy link
Member Author

iluuu1994 commented Jul 24, 2024

You'd also have to make the changes on lower branches I guess...

I was assuming that lower branches compiled with no warnings but it doesn't seem that's the case. Edit: Actually, there are no warnings for 8.2 and 8.3. So this is indeed a new issue for master.

Does it make sense to make these changes?

I guess not. I did not expect there to be this many issues. I will consult the mailing list about switching to C11.

@barracuda156
Copy link

Anything which can build with gcc10 is fine, IMO, since gcc10 can be bootstrapped without support for C11/C11+ is the system compiler. So while one has to build a suitable compiler first, it is a one-step pathway (and honestly at least C11/C11+ is needed nowadays so often that hardly anyone actually using legacy systems is limited to gcc 4.x). Requiring something newer than gcc10 can build is a bit problematic, though even that is not really a stopper.

@iluuu1994
Copy link
Member Author

@cmb69 It seems like MSVC only supports C11 from Visual Studio 2019 [1] but VS 2015 and 2017 remain supported [2]. Do you think that is a problem?

[1] https://devblogs.microsoft.com/cppblog/c11-and-c17-standard-support-arriving-in-msvc/
[2] https://learn.microsoft.com/en-us/visualstudio/productinfo/vs-servicing#older-versions-of-visual-studio

@cmb69
Copy link
Member

cmb69 commented Jul 24, 2024

@iluuu1994, no problem there since VisualStudio 2017 is no longer used for PHP 8 officially. Some users might still use it, but I don't think that should be of concern. And particularly about the typedef redefinition, I don't think that's an issue even for older Visual Studio, since that is allowed in C++ anyway (and VS doesn't make a big difference between C and C++).

Anyway, I think requiring C11 should be discussed on the mailing list; hopefully a quick and uncontroversal discussion not requiring an RFC.

@iluuu1994
Copy link
Member Author

iluuu1994 commented Jul 24, 2024

@cmb69 I agree. I was just gathering information about common environments to send an informed e-mail. Thank you!

@petk
Copy link
Member

petk commented Jul 24, 2024

@iluuu1994 can we also set a minimum GCC and Clang compilers versions while bumping the C11? Because there is this constant issue of what is the minimum GCC version supported in PHP. I know that this might not be such a common practice out there but it will be quite helpful. Getting version in Autoconf can be done something like this: https://github.com/autoconf-archive/autoconf-archive/blob/master/m4/ax_compiler_version.m4 but this will be adjusted to a bit simpler PHP_COMPILER or something M4 macro.

@@ -22,12 +22,12 @@

#include "zend_types.h"

typedef struct _zval_struct zval;
struct _zval_struct;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stupid question maybe, but why do we need this at all? The typedef is defined in zend_types.h which is included right above?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, this one is indeed probably unneeded.

@bwoebi
Copy link
Member

bwoebi commented Jul 24, 2024

@iluuu1994 I think there are quite a few places in Zend/ (e.g. zend_frameless_functions.h) which reference definitions from zend_string.h or zend_types.h. I think there's no need to avoid including zend_types.h/zend_string.h multiple times. These files are anyway relatively small. and will sort of anyway be somehow included by any file using Zend things.

@ryandesign
Copy link
Contributor

I'm always baffled when I encounter these redefinition of typedef errors. Why are programmers so eager to redefine typedefs? Isn't it more confusing when a typedef is one thing in one place in the code and another thing somewhere else? Programmers got along fine with having a single meaning for a given typedef before C11 made redefinitions possible.

can we also set a minimum GCC and Clang compilers versions while bumping the C11?

Why?

Requiring a C99 compiler, or a C11 compiler if you absolutely must, should be sufficient.

If it isn't, and you want to define lower limits for clang, do not forget that there are two different compilers called clang—one released by llvm.org and one released by Apple—and they use different version numbering schemes, so you must state what the lower limit is for each of them.

@nielsdos
Copy link
Member

For DOM, because I don't want to include another header inside the header file to get a certain typedef.

But I'm always baffled when people pull out ancient compiler versions 🤷.

@iluuu1994
Copy link
Member Author

I agree. Some of the PHP headers are gigantic and it's easy to run into recursive dependencies when not careful. I added some new headers that are included in common headers, and to avoid adding more dependencies I used some forward declarations.

@petk
Copy link
Member

petk commented Jul 24, 2024

Why bumping compiler minimum version? Because of the compiler features that we constantly check here and there. For example of issues like this #14497 and for example checking the attribute is also inconsistent in php-src at the moment.

There are still some checks for GCC version 2 in the code. Obviously PHP doesn't build on GCC 2 anymore.

Treating compiler versions like part of the requirements. Minimum re2c, bison, Autoconf, and also build tools like compiler sounds quite logical to me in the very inconsistent C landscape.

@petk
Copy link
Member

petk commented Jul 24, 2024

do not forget that there are two different compilers called clang—one released by llvm.org and one released by Apple—and they use different version numbering schemes

And yes, I agree. The "AppleClang" should be treated as a standalone compiler here indeed. So, checking for version of AppleClang separately from Clang. This Clang isn't so much of an issue actually. This would be an ideal case or in the bare minimum to check for GCC version.

@bukka
Copy link
Member

bukka commented Jul 24, 2024

I had recently a bug report (by email as that person did not have GitHub) running GCC 4.9. I doubt that there will be too many older versions in use so if we can set minimal version to 4.9, it should be hopefully fine even for 8.4. We could consider further bump in the future but 4.9 would be probably good start IMHO.

@petk
Copy link
Member

petk commented Jul 25, 2024

Just adding here another example of the compiler version issue: https://bugs.php.net/bug.php?id=77883

Probably, I've also missed something, because I haven't finished reviewing entire php-src attributes and similar compiler features implementation but I also still think that setting only the C standard wouldn't be enough in PHP's case. For example, should the attributes be handled in the C code conditionally etc. without limiting the minimum compiler version(s) or should some minimum compiler version be a requirement...

@cmb69
Copy link
Member

cmb69 commented Jul 31, 2024

@iluuu1994, are you still planning to write to internals? I don't want to rush, but I think this issue should be resolved prior to 8.4.0beta1. If you don't have time, I can send the mail instead (although I would be happy if you could provide me with info about compiler compatibility you have gathered so far).

Treating compiler versions like part of the requirements. Minimum re2c, bison, Autoconf, and also build tools like compiler sounds quite logical to me in the very inconsistent C landscape.

I'd rather focus on a C (C++) standard, and would only document exact versions of the most important compilers (and even that probably only if there's actual need, i.e. if we come across an issue with an old compiler version). I can imagine there are still a couple of compilers (or variants) in use, we don't really know about.

@iluuu1994
Copy link
Member Author

@cmb69 Yes, sorry for the delay. I'll try to send it tonight or tomorrow.

@iluuu1994
Copy link
Member Author

iluuu1994 commented Aug 1, 2024

Hi everyone

We've gotten a bug report about compile errors in the PHP 8.4 alpha on old C99 compilers (and on some modern compilers when passing the -std=c99 flag). Specifically, C99 does not support typedef redeclarations, which is a C11 feature.

// some_header.h
typedef struct _zval_struct zval;
void some_func(zval *zv);

// zend_types.h
struct _zval_struct { ... };
typedef struct _zval_struct zval;

Some headers might want to forward declare zval so that zend_types.h doesn't have to be included. The two primary reasons you might want to avoid that is 1. to reduce compile times if the header is very large and 2. to prevent recursive header dependencies.

However, in C99 this code is actually illegal if both of these headers end up being included, because redeclarations of typedefs are not allowed. To fix it, the typedef must be removed and the signatures must refer to the struct directly.

// some_header.h
struct _zval_struct;
void some_func(struct _zval_struct *zv);

I started fixing these in a PR [1] which required more changes than expected. After a short discourse, we were wondering whether it might be better to switch to a newer C standard instead. Our coding standards [2] currently specify that compiling php-src requires C99. The Unix installation page on php.net [3] claim it is ANSI C, which is certainly outdated. There have been suggestions to require C11 for a while, which should be well supported by all compilers shipped with maintained distributions.

GCC gained support for C11 in 4.7 [4], Clang in 3.1, both released in 2012. For context, Debian Bullseye comes with GCC 10.2 [5], Ubuntu Focal Fossa comes with GCC 9.3 [6], RHEL 8 comes with GCC 8.x [7]. The biggest blocker in the past was MSVC, which has finally added C11 support in Visual Studio 2019 [8]. Technically, Visual Studio 2015 and 2017 are still supported by Microsoft [9], but according to Christoph they are no longer used for PHP builds since version 8.

Hence, it seems like it would be ok to bump our C compiler requirement to C11. We'd like to make this change before beta 1 if there are no objections. If you have any, please let me know.

Ilija

[1] #15079
[2]

1. PHP is implemented in C99.

[3] https://www.php.net/manual/en/install.unix.php
[4] https://stackoverflow.com/a/16256596
[5] https://packages.debian.org/bullseye/gcc
[6] https://packages.ubuntu.com/focal/gcc
[7] https://access.redhat.com/solutions/19458
[8] https://devblogs.microsoft.com/cppblog/c11-and-c17-standard-support-arriving-in-msvc/
[9] https://learn.microsoft.com/en-us/visualstudio/productinfo/vs-servicing

Sounds ok?

@cmb69
Copy link
Member

cmb69 commented Aug 1, 2024

@iluuu1994, looks very good. Maybe add

  • that there are no plans to use any other new features of C11 for 8.4
  • that switching to C11 also solves the issue with VLAs which are mandatory in C99 but optional in C11, and not supported by MSVC at all

@ryandesign
Copy link
Contributor

GCC gained support for C11 in 4.7 [4], Clang in 3.1, both released in 2012.

As I mentioned previously, there are two different things called clang so it is importantly to specify which one one is talking about: llvm.org clang or Apple clang. According to this table, Apple clang 3.1, 4.0, and 4.1 were all based on prerelease versions of llvm.org clang 3.1 and Apple clang 4.2 was based on a prerelease version of llvm.org clang 3.2. If the feature you need was introduced in llvm.org clang 3.1, I do not know in which version of Apple clang it was introduced.

typedef struct _php_random_fallback_seed_state php_random_fallback_seed_state;
struct _php_random_fallback_seed_state;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can keep this as is, just remove the typedef struct.. later in the same file.

@iluuu1994
Copy link
Member Author

Closing in favor of #15397. For context: https://externals.io/message/124706#124922

@iluuu1994 iluuu1994 closed this Aug 23, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8.4.0alpha2 fails to build: error: redefinition of typedef ‘zend_string’