]> granicus.if.org Git - clang/commitdiff
Warn on va_start() when called with a reference parameter.
authorNico Weber <nicolasweber@gmx.de>
Fri, 24 May 2013 23:31:57 +0000 (23:31 +0000)
committerNico Weber <nicolasweber@gmx.de>
Fri, 24 May 2013 23:31:57 +0000 (23:31 +0000)
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1905.pdf 18.7p3
explicitly calls this (and some other things) out as undefined.

Also move 2 other existing warnings behind the new -Wvarargs flag.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@182694 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/DiagnosticGroups.td
include/clang/Basic/DiagnosticSemaKinds.td
lib/Sema/SemaChecking.cpp
test/Misc/warning-flags.c
test/Sema/varargs.cpp [new file with mode: 0644]

index e56cfda056bf33c6e50ad96a14aaa9ccc67ebd70..8c88a42fc2c5873b9fc9563384d51684e8780bf8 100644 (file)
@@ -246,6 +246,7 @@ def TautologicalCompare : DiagGroup<"tautological-compare",
 def HeaderHygiene : DiagGroup<"header-hygiene">;
 def DuplicateDeclSpecifier : DiagGroup<"duplicate-decl-specifier">;
 def CompareDistinctPointerType : DiagGroup<"compare-distinct-pointer-types">;
+def Varargs : DiagGroup<"varargs">;
 
 def Unsequenced : DiagGroup<"unsequenced">;
 // GCC name for -Wunsequenced
index 7ea87d5fd6289714957203b5b4a7f3467b6fdb2a..f64df9c6b4682205c17657490c4d832d53d57a74 100644 (file)
@@ -6090,7 +6090,9 @@ def note_empty_body_on_separate_line : Note<
 def err_va_start_used_in_non_variadic_function : Error<
   "'va_start' used in function with fixed args">;
 def warn_second_parameter_of_va_start_not_last_named_argument : Warning<
-  "second parameter of 'va_start' not last named argument">;
+  "second parameter of 'va_start' not last named argument">, InGroup<Varargs>;
+def warn_va_start_of_reference_type_is_undefined : Warning<
+  "'va_start' has undefined behavior with reference types">, InGroup<Varargs>;
 def err_first_argument_to_va_arg_not_of_type_va_list : Error<
   "first argument to 'va_arg' is of type %0 and not 'va_list'">;
 def err_second_parameter_to_va_arg_incomplete: Error<
@@ -6105,7 +6107,7 @@ def warn_second_parameter_to_va_arg_ownership_qualified : Warning<
   InGroup<NonPODVarargs>, DefaultError;
 def warn_second_parameter_to_va_arg_never_compatible : Warning<
   "second argument to 'va_arg' is of promotable type %0; this va_arg has "
-  "undefined behavior because arguments will be promoted to %1">;
+  "undefined behavior because arguments will be promoted to %1">, InGroup<Varargs>;
 
 def warn_return_missing_expr : Warning<
   "non-void %select{function|method}1 %0 should return a value">, DefaultError,
index 3471c00440658a1674a08b4c634c73ae40ced7a8..cdc546c476197d32592c52bc65048e8782a5f421 100644 (file)
@@ -1355,6 +1355,11 @@ bool Sema::SemaBuiltinVAStart(CallExpr *TheCall) {
   bool SecondArgIsLastNamedArgument = false;
   const Expr *Arg = TheCall->getArg(1)->IgnoreParenCasts();
 
+  // These are valid if SecondArgIsLastNamedArgument is false after the next
+  // block.
+  QualType Type;
+  SourceLocation ParamLoc;
+
   if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Arg)) {
     if (const ParmVarDecl *PV = dyn_cast<ParmVarDecl>(DR->getDecl())) {
       // FIXME: This isn't correct for methods (results in bogus warning).
@@ -1367,12 +1372,21 @@ bool Sema::SemaBuiltinVAStart(CallExpr *TheCall) {
       else
         LastArg = *(getCurMethodDecl()->param_end()-1);
       SecondArgIsLastNamedArgument = PV == LastArg;
+
+      Type = PV->getType();
+      ParamLoc = PV->getLocation();
     }
   }
 
   if (!SecondArgIsLastNamedArgument)
     Diag(TheCall->getArg(1)->getLocStart(),
          diag::warn_second_parameter_of_va_start_not_last_named_argument);
+  else if (Type->isReferenceType()) {
+    Diag(Arg->getLocStart(),
+         diag::warn_va_start_of_reference_type_is_undefined);
+    Diag(ParamLoc, diag::note_parameter_type) << Type;
+  }
+
   return false;
 }
 
index a6dc8f1352fdb20886a0d55e1e9c25bf2ddd05f9..3293e02a440c3dd1461ff25751e5ab9aa3917a65 100644 (file)
@@ -18,7 +18,7 @@ This test serves two purposes:
 
 The list of warnings below should NEVER grow.  It should gradually shrink to 0.
 
-CHECK: Warnings without flags (143):
+CHECK: Warnings without flags (141):
 CHECK-NEXT:   ext_delete_void_ptr_operand
 CHECK-NEXT:   ext_enum_friend
 CHECK-NEXT:   ext_expected_semi_decl_list
@@ -146,8 +146,6 @@ CHECK-NEXT:   warn_redeclaration_without_attribute_prev_attribute_ignored
 CHECK-NEXT:   warn_register_objc_catch_parm
 CHECK-NEXT:   warn_related_result_type_compatibility_class
 CHECK-NEXT:   warn_related_result_type_compatibility_protocol
-CHECK-NEXT:   warn_second_parameter_of_va_start_not_last_named_argument
-CHECK-NEXT:   warn_second_parameter_to_va_arg_never_compatible
 CHECK-NEXT:   warn_static_inline_explicit_inst_ignored
 CHECK-NEXT:   warn_static_non_static
 CHECK-NEXT:   warn_template_export_unsupported
diff --git a/test/Sema/varargs.cpp b/test/Sema/varargs.cpp
new file mode 100644 (file)
index 0000000..48a7b2f
--- /dev/null
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+class string;
+void f(const string& s, ...) {  // expected-note {{parameter of type 'const string &' is declared here}}
+  __builtin_va_list ap;
+  __builtin_va_start(ap, s); // expected-warning {{'va_start' has undefined behavior with reference types}}
+}