@@ -2161,6 +2161,7 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
21612161 case Builtin::BI__builtin_ms_va_start:
21622162 case Builtin::BI__builtin_stdarg_start:
21632163 case Builtin::BI__builtin_va_start:
2164+ case Builtin::BI__builtin_c23_va_start:
21642165 if (BuiltinVAStart(BuiltinID, TheCall))
21652166 return ExprError();
21662167 break;
@@ -4844,15 +4845,27 @@ static bool checkVAStartIsInVariadicFunction(Sema &S, Expr *Fn,
48444845
48454846bool Sema::BuiltinVAStart(unsigned BuiltinID, CallExpr *TheCall) {
48464847 Expr *Fn = TheCall->getCallee();
4847-
48484848 if (checkVAStartABI(*this, BuiltinID, Fn))
48494849 return true;
48504850
4851- // In C23 mode, va_start only needs one argument. However, the builtin still
4852- // requires two arguments (which matches the behavior of the GCC builtin),
4853- // <stdarg.h> passes `0` as the second argument in C23 mode.
4854- if (checkArgCount(TheCall, 2))
4855- return true;
4851+ if (BuiltinID == Builtin::BI__builtin_c23_va_start) {
4852+ // This builtin requires one argument (the va_list), allows two arguments,
4853+ // but diagnoses more than two arguments. e.g.,
4854+ // __builtin_c23_va_start(); // error
4855+ // __builtin_c23_va_start(list); // ok
4856+ // __builtin_c23_va_start(list, param); // ok
4857+ // __builtin_c23_va_start(list, anything, anything); // error
4858+ // This differs from the GCC behavior in that they accept the last case
4859+ // with a warning, but it doesn't seem like a useful behavior to allow.
4860+ if (checkArgCountRange(TheCall, 1, 2))
4861+ return true;
4862+ } else {
4863+ // In C23 mode, va_start only needs one argument. However, the builtin still
4864+ // requires two arguments (which matches the behavior of the GCC builtin),
4865+ // <stdarg.h> passes `0` as the second argument in C23 mode.
4866+ if (checkArgCount(TheCall, 2))
4867+ return true;
4868+ }
48564869
48574870 // Type-check the first argument normally.
48584871 if (checkBuiltinArgument(*this, TheCall, 0))
@@ -4863,23 +4876,34 @@ bool Sema::BuiltinVAStart(unsigned BuiltinID, CallExpr *TheCall) {
48634876 if (checkVAStartIsInVariadicFunction(*this, Fn, &LastParam))
48644877 return true;
48654878
4866- // Verify that the second argument to the builtin is the last argument of the
4867- // current function or method. In C23 mode, if the second argument is an
4868- // integer constant expression with value 0, then we don't bother with this
4869- // check.
4870- bool SecondArgIsLastNamedArgument = false;
4879+ // Verify that the second argument to the builtin is the last non-variadic
4880+ // argument of the current function or method. In C23 mode, if the call is
4881+ // not to __builtin_c23_va_start, and the second argument is an integer
4882+ // constant expression with value 0, then we don't bother with this check.
4883+ // For __builtin_c23_va_start, we only perform the check for the second
4884+ // argument being the last argument to the current function if there is a
4885+ // second argument present.
4886+ if (BuiltinID == Builtin::BI__builtin_c23_va_start &&
4887+ TheCall->getNumArgs() < 2) {
4888+ Diag(TheCall->getExprLoc(), diag::warn_c17_compat_va_start_one_arg);
4889+ return false;
4890+ }
4891+
48714892 const Expr *Arg = TheCall->getArg(1)->IgnoreParenCasts();
48724893 if (std::optional<llvm::APSInt> Val =
48734894 TheCall->getArg(1)->getIntegerConstantExpr(Context);
4874- Val && LangOpts.C23 && *Val == 0)
4895+ Val && LangOpts.C23 && *Val == 0 &&
4896+ BuiltinID != Builtin::BI__builtin_c23_va_start) {
4897+ Diag(TheCall->getExprLoc(), diag::warn_c17_compat_va_start_one_arg);
48754898 return false;
4899+ }
48764900
48774901 // These are valid if SecondArgIsLastNamedArgument is false after the next
48784902 // block.
48794903 QualType Type;
48804904 SourceLocation ParamLoc;
48814905 bool IsCRegister = false;
4882-
4906+ bool SecondArgIsLastNamedArgument = false;
48834907 if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Arg)) {
48844908 if (const ParmVarDecl *PV = dyn_cast<ParmVarDecl>(DR->getDecl())) {
48854909 SecondArgIsLastNamedArgument = PV == LastParam;
0 commit comments