From 6eda8c9cefb498ac8403bc65854e6ce411a07855 Mon Sep 17 00:00:00 2001 From: Anders Carlsson Date: Fri, 12 Oct 2007 17:48:41 +0000 Subject: [PATCH] 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 --- Sema/SemaChecking.cpp | 31 +++++++++++++++++++++++++ include/clang/Basic/DiagnosticKinds.def | 4 ++++ test/Sema/format-strings.c | 5 ++-- test/Sema/varargs.c | 18 ++++++++++++++ 4 files changed, 55 insertions(+), 3 deletions(-) create mode 100644 test/Sema/varargs.c 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); +} -- 2.40.0