This revision was automatically updated to reflect the committed changes.
Closed by commit rL302188: Fix bugs checking va_start in lambdas and erroneous 
contexts (authored by rnk).

Changed prior to commit:
  https://reviews.llvm.org/D32761?vs=97503&id=97868#toc

Repository:
  rL LLVM

https://reviews.llvm.org/D32761

Files:
  cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
  cfe/trunk/lib/Sema/SemaChecking.cpp
  cfe/trunk/test/OpenMP/varargs.cpp
  cfe/trunk/test/SemaCXX/varargs.cpp

Index: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
@@ -7920,7 +7920,11 @@
 def note_empty_body_on_separate_line : Note<
   "put the semicolon on a separate line to silence this warning">;
 
-def err_va_start_used_in_non_variadic_function : Error<
+def err_va_start_captured_stmt : Error<
+  "'va_start' cannot be used in a captured statement">;
+def err_va_start_outside_function : Error<
+  "'va_start' cannot be used outside a function">;
+def err_va_start_fixed_function : Error<
   "'va_start' used in function with fixed args">;
 def err_va_start_used_in_wrong_abi_function : Error<
   "'va_start' used in %select{System V|Win64}0 ABI function">;
Index: cfe/trunk/test/SemaCXX/varargs.cpp
===================================================================
--- cfe/trunk/test/SemaCXX/varargs.cpp
+++ cfe/trunk/test/SemaCXX/varargs.cpp
@@ -1,12 +1,59 @@
-// RUN: %clang_cc1 -fsyntax-only -std=c++03 -verify %s
+// RUN: %clang_cc1 -std=c++03 -verify %s
+// RUN: %clang_cc1 -std=c++11 -verify %s
+
+__builtin_va_list ap;
 
 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 {{passing an object of reference type to 'va_start' has undefined behavior}}
 }
 
 void g(register int i, ...) {
-  __builtin_va_list ap;
-  __builtin_va_start(ap, i); // okay
+  __builtin_va_start(ap, i); // UB in C, OK in C++
+}
+
+// Don't crash when there is no last parameter.
+void no_params(...) {
+  int a;
+  __builtin_va_start(ap, a); // expected-warning {{second argument to 'va_start' is not the last named parameter}}
+}
+
+// Reject this. The __builtin_va_start would execute in Foo's non-variadic
+// default ctor.
+void record_context(int a, ...) {
+  struct Foo {
+    // expected-error@+1 {{'va_start' cannot be used outside a function}}
+    void meth(int a, int b = (__builtin_va_start(ap, a), 0)) {}
+  };
+}
+
+#if __cplusplus >= 201103L
+// We used to have bugs identifying the correct enclosing function scope in a
+// lambda.
+
+void fixed_lambda_varargs_function(int a, ...) {
+  [](int b) {
+    __builtin_va_start(ap, b); // expected-error {{'va_start' used in function with fixed args}}
+  }(42);
+}
+void varargs_lambda_fixed_function(int a) {
+  [](int b, ...) {
+    __builtin_va_start(ap, b); // correct
+  }(42);
+}
+
+auto fixed_lambda_global = [](int f) {
+  __builtin_va_start(ap, f); // expected-error {{'va_start' used in function with fixed args}}
+};
+auto varargs_lambda_global = [](int f, ...) {
+  __builtin_va_start(ap, f); // correct
+};
+
+void record_member_init(int a, ...) {
+  struct Foo {
+    int a = 0;
+    // expected-error@+1 {{'va_start' cannot be used outside a function}}
+    int b = (__builtin_va_start(ap, a), 0);
+  };
 }
+#endif
Index: cfe/trunk/test/OpenMP/varargs.cpp
===================================================================
--- cfe/trunk/test/OpenMP/varargs.cpp
+++ cfe/trunk/test/OpenMP/varargs.cpp
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -verify -fopenmp %s
+void f(int a, ...) {
+#pragma omp parallel for
+  for (int i = 0; i < 100; ++i) {
+    __builtin_va_list ap;
+    __builtin_va_start(ap, a); // expected-error {{'va_start' cannot be used in a captured statement}}
+  }
+};
Index: cfe/trunk/lib/Sema/SemaChecking.cpp
===================================================================
--- cfe/trunk/lib/Sema/SemaChecking.cpp
+++ cfe/trunk/lib/Sema/SemaChecking.cpp
@@ -3652,22 +3652,29 @@
   // and get its parameter list.
   bool IsVariadic = false;
   ArrayRef<ParmVarDecl *> Params;
-  if (BlockScopeInfo *CurBlock = S.getCurBlock()) {
-    IsVariadic = CurBlock->TheDecl->isVariadic();
-    Params = CurBlock->TheDecl->parameters();
-  } else if (FunctionDecl *FD = S.getCurFunctionDecl()) {
+  DeclContext *Caller = S.CurContext;
+  if (auto *Block = dyn_cast<BlockDecl>(Caller)) {
+    IsVariadic = Block->isVariadic();
+    Params = Block->parameters();
+  } else if (auto *FD = dyn_cast<FunctionDecl>(Caller)) {
     IsVariadic = FD->isVariadic();
     Params = FD->parameters();
-  } else if (ObjCMethodDecl *MD = S.getCurMethodDecl()) {
+  } else if (auto *MD = dyn_cast<ObjCMethodDecl>(Caller)) {
     IsVariadic = MD->isVariadic();
     // FIXME: This isn't correct for methods (results in bogus warning).
     Params = MD->parameters();
+  } else if (isa<CapturedDecl>(Caller)) {
+    // We don't support va_start in a CapturedDecl.
+    S.Diag(Fn->getLocStart(), diag::err_va_start_captured_stmt);
+    return true;
   } else {
-    llvm_unreachable("unknown va_start context");
+    // This must be some other declcontext that parses exprs.
+    S.Diag(Fn->getLocStart(), diag::err_va_start_outside_function);
+    return true;
   }
 
   if (!IsVariadic) {
-    S.Diag(Fn->getLocStart(), diag::err_va_start_used_in_non_variadic_function);
+    S.Diag(Fn->getLocStart(), diag::err_va_start_fixed_function);
     return true;
   }
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to