This is an archive of the discontinued LLVM Phabricator instance.

[C2x] Relaxing requirements for va_start
ClosedPublic

Authored by aaron.ballman on Dec 6 2022, 8:31 AM.

Details

Summary

This implements WG14 N2975 relaxing requirements for va_start (https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2975.pdf), which does two things:

  1. Allows the declaration of a variadic function without any named arguments. e.g., void f(...) is now valid, as in C++.
  2. Modified the signature of the va_start macro to be a variadic macro that accepts one or more arguments; the second (and later) arguments are not expanded or evaluated.

I followed the GCC implementation in terms of not modifying the behavior of __builtin_va_start (it still requires exactly two arguments), but this approach has led to several QoI issues that I've documented with FIXME comments in the test. Specifically, the requirement that we do not evaluate *or expand* the second and later arguments means it's no longer possible to issue diagnostics for compatibility with older C versions and C++. I am reaching out to folks in WG14 to see if we can get an NB comment to address these concerns (the US comment period has already closed, so I cannot file the comment myself), so the diagnostic behavior may change in the future.

I took this opportunity to add some documentation for all the related builtins in this area, since there was no documentation for them yet.

Diff Detail

Event Timeline

aaron.ballman created this revision.Dec 6 2022, 8:31 AM
Herald added a project: Restricted Project. · View Herald TranscriptDec 6 2022, 8:31 AM
aaron.ballman requested review of this revision.Dec 6 2022, 8:31 AM
Herald added a project: Restricted Project. · View Herald TranscriptDec 6 2022, 8:31 AM
erichkeane added inline comments.
clang/lib/Parse/ParseDecl.cpp
7356 ↗(On Diff #480501)

Is this right? Isnt this also allowing:

foo(int a ...)

I don't think we want to do that, right? GCC diagnoses that as "requires a named argument", not a comma.

clang/lib/Sema/SemaChecking.cpp
7227

This doesn't exactly match the comment, this isn't checking against the literal-0, it is checking against an ICE.

An updated comment would probably be fine here, and perhaps preferential, in order to allow a paren-expr containing 0.

7230

is there value to not jsut doing an early return here? There is a lot of work happening below based on the last arg that we can just skip instead.

cor3ntin added inline comments.
clang/lib/Headers/stdarg.h
30

Yeah, i really think there should be some king of diagnostic here.
Maybe __builtin_va_start could take an arbitrary number of arguments and diagnose for more that 2 args or if the second arg is not valid?
is it a matter of being compatible with gcc? do we need to?

aaron.ballman marked 4 inline comments as done.Dec 6 2022, 9:10 AM
aaron.ballman added inline comments.
clang/lib/Headers/stdarg.h
30

We try pretty hard to keep our builtins compatible with GCC; that makes everyone's lives easier (most especially standard library authors). If we did anything here, it would be to add a new builtin specific for the new variant. However, that won't save us because of the standard's requirement to not *expand* the variadic arguments. We'd need that builtin to be named va_start and we'd have to get rid of this macro (otherwise, the arguments passed to the builtin will be expanded as they're lexed). But va_start is defined by the standard as being a macro specifically, so we'd still need to make #if defined(va_start) work. Ultimately, I don't think it's worth that level of heroics -- instead, I am hoping WG14 will relax the requirement that the arguments not be expanded or evaluated; that gives us options.

clang/lib/Parse/ParseDecl.cpp
7356 ↗(On Diff #480501)

Ah good catch! I'll add a test case for that. In fact, I don't think I need to do anything here in C; the existing logic was already correct.

clang/lib/Sema/SemaChecking.cpp
7227

Ah, fair, we check against 0 explicitly, but we don't care if you got that zero from 0 or from 0 + 0, etc. I'll update the comment.

7230

Hmmm that seems reasonable to me, good call!

aaron.ballman marked 4 inline comments as done.

Updating based on review feedback.

  • Rolled back parsing changes as they were not needed
  • Moved the diagnostic from common kinds to sema kinds because it's now solely in sema
  • Reworded a comment
  • Added a new test case for void f(int a...)
erichkeane added inline comments.Dec 6 2022, 9:28 AM
clang/lib/Sema/SemaChecking.cpp
7230

I see below that we still set the return type of hte call to Void. Do we wnat to keep that line, or at least, move it to the top of this function?

clang/test/C/C2x/n2975.c
49

.

Give others an extra chance to look at this, but other than the 1 concern, LGTM.

erichkeane added inline comments.Dec 6 2022, 9:30 AM
clang/test/C/C2x/n2975.c
49

Was going to complain about the error message here, but I'm on the fence whether we should say THIS (the required comma), or something more descriptive, but at least this is better than GCC just failing in normal parsing.

cor3ntin added inline comments.Dec 6 2022, 9:42 AM
clang/lib/Headers/stdarg.h
30

We probably can reuse the same macro name (we'd still have to handle the 0 case though), but if you'd rather be conforming now and revisit the issue when WG14 remove the limitation that parameters are not expanded, I'm fine with it!

aaron.ballman marked 4 inline comments as done.Dec 6 2022, 9:53 AM
aaron.ballman added inline comments.
clang/lib/Headers/stdarg.h
30

For the moment, I'd rather match what GCC is doing (deficiencies and all) until it's clear what actually gets into the final standard. We can revisit once WG14 has said their piece.

clang/lib/Sema/SemaChecking.cpp
7230

I added test coverage and it seems that setting the return type is not needed (by my understanding, CreateBuiltin requires the return type to be passed to it explicitly, and LazilyCreateBuiltin uses the builtin type string to specify *at least* the return type information (even if custom type checking happens for the rest of the signature).

clang/test/C/C2x/n2975.c
49

FWIW, this is existing diagnostic wording and behavior. I think it's reasonable, but if we want to do something better, we can fix it in a follow-up.

aaron.ballman marked 3 inline comments as done.

Update based on review feedback.

  • Removed code setting the return type for the builtin (it's already set elsewhere)
  • Added test coverage verifying the return type for the builtin is correct
erichkeane accepted this revision.Dec 6 2022, 10:07 AM
erichkeane added inline comments.
clang/lib/Sema/SemaChecking.cpp
7230

Great, thanks for checking!

This revision is now accepted and ready to land.Dec 6 2022, 10:07 AM

Adding some more test cases that demonstrate that you can still call these functions as you'd expect and that function pointer assignment works as expected.

This revision was automatically updated to reflect the committed changes.