From: Anders Carlsson Date: Fri, 12 Oct 2007 17:48:41 +0000 (+0000) Subject: Add some more diagnostics for va_start, fix tests so they pass with these new diags. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=6eda8c9cefb498ac8403bc65854e6ce411a07855;p=clang Add some more diagnostics for va_start, fix tests so they pass with these new diags. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@42917 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/Sema/SemaChecking.cpp b/Sema/SemaChecking.cpp index ea63b7dc1c..f764d80df2 100644 --- a/Sema/SemaChecking.cpp +++ b/Sema/SemaChecking.cpp @@ -43,6 +43,37 @@ Sema::CheckFunctionCall(Expr *Fn, assert(NumArgsInCall == 1 && "Wrong number of arguments to builtin CFStringMakeConstantString"); return CheckBuiltinCFStringArgument(Args[0]); + } else if (FnInfo->getBuiltinID() == Builtin::BI__builtin_va_start) { + if (NumArgsInCall > 2) { + Diag(Args[2]->getLocStart(), + diag::err_typecheck_call_too_many_args, Fn->getSourceRange(), + SourceRange(Args[2]->getLocStart(), + Args[NumArgsInCall - 1]->getLocEnd())); + return true; + } + + FunctionTypeProto* proto = + cast(CurFunctionDecl->getType()); + if (!proto->isVariadic()) { + Diag(Fn->getLocStart(), + diag::err_va_start_used_in_non_variadic_function); + return true; + } + + bool SecondArgIsLastNamedArgument = false; + if (DeclRefExpr *DR = dyn_cast(Args[1])) { + if (ParmVarDecl *PV = dyn_cast(DR->getDecl())) { + ParmVarDecl *LastNamedArg = + CurFunctionDecl->getParamDecl(CurFunctionDecl->getNumParams() - 1); + + if (PV == LastNamedArg) + SecondArgIsLastNamedArgument = true; + } + } + + if (!SecondArgIsLastNamedArgument) + Diag(Args[1]->getLocStart(), + diag::warn_second_parameter_of_va_start_not_last_named_argument); } // Search the KnownFunctionIDs for the identifier. diff --git a/include/clang/Basic/DiagnosticKinds.def b/include/clang/Basic/DiagnosticKinds.def index 16fccb62bc..81aaa5caf7 100644 --- a/include/clang/Basic/DiagnosticKinds.def +++ b/include/clang/Basic/DiagnosticKinds.def @@ -847,6 +847,10 @@ DIAG(err_multiple_default_labels_defined, ERROR, "multiple default labels in one switch") DIAG(warn_empty_if_body, WARNING, "if statement has empty body") +DIAG(err_va_start_used_in_non_variadic_function, ERROR, + "'va_start' used in function with fixed args") +DIAG(warn_second_parameter_of_va_start_not_last_named_argument, WARNING, + "second parameter of 'va_start' not last named argument") DIAG(warn_return_missing_expr, WARNING, "non-void function '%0' should return a value") diff --git a/test/Sema/format-strings.c b/test/Sema/format-strings.c index 83947cf7c3..8b3be6856b 100644 --- a/test/Sema/format-strings.c +++ b/test/Sema/format-strings.c @@ -45,7 +45,7 @@ void check_null_char_string(char* b) printf("%\0d",1); // expected-warning {{string contains '\0'}} } -void check_empty_format_string(char* buf) +void check_empty_format_string(char* buf, ...) { va_list ap; va_start(ap,buf); @@ -53,9 +53,8 @@ void check_empty_format_string(char* buf) sprintf(buf,""); // expected-warning {{format string is empty}} } -void check_wide_string() +void check_wide_string(char* b, ...) { - char *b; va_list ap; va_start(ap,b); diff --git a/test/Sema/varargs.c b/test/Sema/varargs.c new file mode 100644 index 0000000000..92faf9ff50 --- /dev/null +++ b/test/Sema/varargs.c @@ -0,0 +1,18 @@ +// RUN: clang -fsyntax-only -verify %s + +void f1(int a) +{ + __builtin_va_list ap; + + __builtin_va_start(ap, a, a); // expected-error {{too many arguments to function}} + __builtin_va_start(ap, a); // expected-error {{'va_start' used in function with fixed args}} +} + +void f2(int a, int b, ...) +{ + __builtin_va_list ap; + + __builtin_va_start(ap, 10); // expected-warning {{second parameter of 'va_start' not last named argument}} + __builtin_va_start(ap, a); // expected-warning {{second parameter of 'va_start' not last named argument}} + __builtin_va_start(ap, b); +}