[cfe-commits] r104443 - in /cfe/trunk: include/clang/Basic/DiagnosticSemaKinds.td lib/Sema/SemaTemplate.cpp lib/Sema/SemaType.cpp test/CodeGenCXX/c99-variable-length-array.cpp test/Sema/c89.c test/SemaCXX/c99-variable-length-array.cpp test/SemaCXX/c99.cpp test/SemaCXX/offsetof.cpp test/SemaObjCXX/vla.mm test/SemaTemplate/instantiate-declref-ice.cpp www/cxx_compatibility.html

Douglas Gregor dgregor at apple.com
Sat May 22 09:17:30 PDT 2010


Author: dgregor
Date: Sat May 22 11:17:30 2010
New Revision: 104443

URL: http://llvm.org/viewvc/llvm-project?rev=104443&view=rev
Log:
Implement support for variable length arrays in C++. VLAs are limited
in several important ways:

  - VLAs of non-POD types are not permitted.
  - VLAs cannot be used in conjunction with C++ templates.

These restrictions are intended to keep VLAs out of the parts of the
C++ type system where they cause the most trouble. Fixes PR5678 and
<rdar://problem/8013618>.


Added:
    cfe/trunk/test/CodeGenCXX/c99-variable-length-array.cpp   (with props)
    cfe/trunk/test/SemaCXX/c99-variable-length-array.cpp   (with props)
Modified:
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/lib/Sema/SemaTemplate.cpp
    cfe/trunk/lib/Sema/SemaType.cpp
    cfe/trunk/test/Sema/c89.c
    cfe/trunk/test/SemaCXX/c99.cpp
    cfe/trunk/test/SemaCXX/offsetof.cpp
    cfe/trunk/test/SemaObjCXX/vla.mm
    cfe/trunk/test/SemaTemplate/instantiate-declref-ice.cpp
    cfe/trunk/www/cxx_compatibility.html

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=104443&r1=104442&r2=104443&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Sat May 22 11:17:30 2010
@@ -36,6 +36,28 @@
   "magnitude of floating-point constant too small for type %0; minimum is %1">,
   InGroup<LiteralRange>;
 
+// C99 variable-length arrays
+def ext_vla : Extension<
+  "variable length arrays are a C99 feature, accepted as an extension">;
+def err_vla_non_pod : Error<"variable length array of non-POD element type %0">;
+def err_vla_in_template : Error<
+  "variable length array cannot be used in a template %select{definition|"
+  "instantiation}0">;
+def err_array_star_in_function_definition : Error<
+  "variable length array must be bound in function definition">;
+def err_vla_decl_in_file_scope : Error<
+  "variable length array declaration not allowed at file scope">;
+def err_vla_decl_has_static_storage : Error<
+  "variable length array declaration can not have 'static' storage duration">;
+def err_vla_decl_has_extern_linkage : Error<
+  "variable length array declaration can not have 'extern' linkage">;
+  
+// C99 variably modified types
+def err_variably_modified_template_arg : Error<
+  "variably modified type %0 cannot be used as a template argument">;
+def err_variably_modified_nontype_template_param : Error<
+  "non-type template parameter of variably modified type %0">;
+
 // C99 Designated Initializers
 def err_array_designator_negative : Error<
   "array designator value '%0' is negative">;
@@ -71,11 +93,6 @@
   "flexible array initialization is a GNU extension">, InGroup<GNU>;
 
 // Declarations.
-def ext_vla : Extension<
-  "variable length arrays are a C99 feature, accepted as an extension">;
-def err_vla_cxx : Error<
-  "variable length arrays are not permitted in C++">;
-  
 def ext_anon_param_requires_type_specifier : Extension<
   "type specifier required for unnamed parameter, defaults to int">;
 def err_bad_variable_name : Error<
@@ -89,8 +106,6 @@
   InGroup<UnusedExceptionParameter>, DefaultIgnore;
 def warn_decl_in_param_list : Warning<
   "declaration of %0 will not be visible outside of this function">;
-def err_array_star_in_function_definition : Error<
-  "variable length array must be bound in function definition">;
 def warn_unused_function : Warning<"unused function %0">,
   InGroup<UnusedFunction>, DefaultIgnore;
   
@@ -1666,12 +1681,6 @@
   
 def warn_illegal_constant_array_size : Extension<
   "size of static array must be an integer constant expression">;
-def err_vla_decl_in_file_scope : Error<
-  "variable length array declaration not allowed at file scope">;
-def err_vla_decl_has_static_storage : Error<
-  "variable length array declaration can not have 'static' storage duration">;
-def err_vla_decl_has_extern_linkage : Error<
-  "variable length array declaration can not have 'extern' linkage">;
 def err_vm_decl_in_file_scope : Error<
   "variably modified type declaration not allowed at file scope">;
 def err_vm_decl_has_extern_linkage : Error<

Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=104443&r1=104442&r2=104443&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Sat May 22 11:17:30 2010
@@ -553,6 +553,13 @@
       // assume that it is well-formed.
       T->isDependentType())
     return T;
+  // We don't allow variably-modified types as the type of non-type template
+  // parameters.
+  else if (T->isVariablyModifiedType()) {
+    Diag(Loc, diag::err_variably_modified_nontype_template_param)
+      << T;
+    return QualType();
+  }
   // C++ [temp.param]p8:
   //
   //   A non-type template-parameter of type "array of T" or
@@ -564,7 +571,7 @@
   else if (T->isFunctionType())
     // FIXME: Keep the type prior to promotion?
     return Context.getPointerType(T);
-
+  
   Diag(Loc, diag::err_template_nontype_parm_bad_type)
     << T;
 
@@ -2354,7 +2361,8 @@
   //   compounded from any of these types shall not be used as a
   //   template-argument for a template type-parameter.
   //
-  // FIXME: Perform the recursive and no-linkage type checks.
+  // FIXME: Perform the unnamed type check.
+  SourceRange SR = ArgInfo->getTypeLoc().getSourceRange();
   const TagType *Tag = 0;
   if (const EnumType *EnumT = Arg->getAs<EnumType>())
     Tag = EnumT;
@@ -2366,12 +2374,14 @@
       << QualType(Tag, 0) << SR;
   } else if (Tag && !Tag->getDecl()->getDeclName() &&
            !Tag->getDecl()->getTypedefForAnonDecl()) {
-    SourceRange SR = ArgInfo->getTypeLoc().getSourceRange();
     Diag(SR.getBegin(), diag::err_template_arg_unnamed_type) << SR;
     Diag(Tag->getDecl()->getLocation(), diag::note_template_unnamed_type_here);
     return true;
+  } else if (Arg->isVariablyModifiedType()) {
+    Diag(SR.getBegin(), diag::err_variably_modified_template_arg)
+      << Arg;
+    return true;
   } else if (Context.hasSameUnqualifiedType(Arg, Context.OverloadTy)) {
-    SourceRange SR = ArgInfo->getTypeLoc().getSourceRange();
     return Diag(SR.getBegin(), diag::err_template_arg_overload_type) << SR;
   }
 

Modified: cfe/trunk/lib/Sema/SemaType.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=104443&r1=104442&r2=104443&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaType.cpp (original)
+++ cfe/trunk/lib/Sema/SemaType.cpp Sat May 22 11:17:30 2010
@@ -709,11 +709,26 @@
   }
   // If this is not C99, extwarn about VLA's and C99 array size modifiers.
   if (!getLangOptions().C99) {
-    if (ArraySize && !ArraySize->isTypeDependent() &&
-        !ArraySize->isValueDependent() &&
-        !ArraySize->isIntegerConstantExpr(Context))
-      Diag(Loc, getLangOptions().CPlusPlus? diag::err_vla_cxx : diag::ext_vla);
-    else if (ASM != ArrayType::Normal || Quals != 0)
+    if (T->isVariableArrayType()) {
+      // Prohibit the use of non-POD types in VLAs.
+      if (!Context.getBaseElementType(T)->isPODType()) {
+        Diag(Loc, diag::err_vla_non_pod)
+          << Context.getBaseElementType(T);
+        return QualType();
+      } 
+      // Prohibit the use of VLAs in template instantiations, since we don't
+      // want them to accidentally be used. This means that we handle VLAs in
+      // C-like contexts, but still ban them from C++-specific contexts.
+      // And, since we check template definitions early, prohibit them there,
+      // too.
+      else if (CurContext->isDependentContext() ||
+               ActiveTemplateInstantiations.size())
+        Diag(Loc, diag::err_vla_in_template)
+          << !CurContext->isDependentContext();
+      // Just extwarn about VLAs.
+      else
+        Diag(Loc, diag::ext_vla);
+    } else if (ASM != ArrayType::Normal || Quals != 0)
       Diag(Loc, 
            getLangOptions().CPlusPlus? diag::err_c99_array_usage_cxx
                                      : diag::ext_c99_array_usage);

Added: cfe/trunk/test/CodeGenCXX/c99-variable-length-array.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/c99-variable-length-array.cpp?rev=104443&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenCXX/c99-variable-length-array.cpp (added)
+++ cfe/trunk/test/CodeGenCXX/c99-variable-length-array.cpp Sat May 22 11:17:30 2010
@@ -0,0 +1,27 @@
+// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck %s
+struct X {
+  X();
+  ~X();
+};
+
+struct Y {
+  Y();
+  ~Y();
+};
+
+// CHECK: define void @_Z1fiPPKc(
+void f(int argc, const char* argv[]) {
+  // CHECK: call void @_ZN1XC1Ev
+  X x;
+  // CHECK: call i8* @llvm.stacksave(
+  const char *argv2[argc];
+  // CHECK: call void @_ZN1YC1Ev
+  Y y;
+  for (int i = 0; i != argc; ++i)
+    argv2[i] = argv[i];
+
+  // CHECK: call void @_ZN1YD1Ev
+  // CHECK: call void @llvm.stackrestore
+  // CHECK: call void @_ZN1XD1Ev
+  // CHECK: ret void
+}

Propchange: cfe/trunk/test/CodeGenCXX/c99-variable-length-array.cpp
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cfe/trunk/test/CodeGenCXX/c99-variable-length-array.cpp
------------------------------------------------------------------------------
    svn:keywords = Id

Propchange: cfe/trunk/test/CodeGenCXX/c99-variable-length-array.cpp
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: cfe/trunk/test/Sema/c89.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/c89.c?rev=104443&r1=104442&r2=104443&view=diff
==============================================================================
--- cfe/trunk/test/Sema/c89.c (original)
+++ cfe/trunk/test/Sema/c89.c Sat May 22 11:17:30 2010
@@ -61,7 +61,7 @@
 void foo(void) {}
 
 /* PR2759 */
-void test10 (int x[*]); /* expected-warning {{use of C99-specific array features}} */
+void test10 (int x[*]); /* expected-warning {{variable length arrays are a C99 feature, accepted as an extension}} */
 void test11 (int x[static 4]); /* expected-warning {{use of C99-specific array features}} */
 
 void test12 (int x[const 4]) { /* expected-warning {{use of C99-specific array features}} */

Added: cfe/trunk/test/SemaCXX/c99-variable-length-array.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/c99-variable-length-array.cpp?rev=104443&view=auto
==============================================================================
--- cfe/trunk/test/SemaCXX/c99-variable-length-array.cpp (added)
+++ cfe/trunk/test/SemaCXX/c99-variable-length-array.cpp Sat May 22 11:17:30 2010
@@ -0,0 +1,80 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+struct NonPOD {
+  NonPOD();
+};
+
+struct NonPOD2 {
+  NonPOD np;
+};
+
+struct POD {
+  int x;
+  int y;
+};
+
+// We allow VLAs of POD types, only.
+void vla(int N) {
+  int array1[N];
+  POD array2[N];
+  NonPOD array3[N]; // expected-error{{variable length array of non-POD element type 'NonPOD'}}
+  NonPOD2 array4[N][3]; // expected-error{{variable length array of non-POD element type 'NonPOD2'}}
+}
+
+// We disallow VLAs in templates
+template<typename T>
+void vla_in_template(int N, T t) {
+  int array1[N]; // expected-error{{variable length array cannot be used in a template definition}}
+}
+
+struct HasConstantValue {
+  static const unsigned int value = 2;
+};
+
+struct HasNonConstantValue {
+  static unsigned int value;
+};
+
+template<typename T>
+void vla_in_template(T t) {
+  int array2[T::value]; // expected-error{{variable length array cannot be used in a template instantiation}}
+}
+
+template void vla_in_template<HasConstantValue>(HasConstantValue);
+template void vla_in_template<HasNonConstantValue>(HasNonConstantValue); // expected-note{{instantiation of}}
+
+template<typename T> struct X0 { };
+
+// Cannot use any variably-modified type with a template parameter or
+// argument.
+void inst_with_vla(int N) {
+  int array[N];
+  X0<__typeof__(array)> x0a; // expected-error{{variably modified type 'typeof (array)' (aka 'int [N]') cannot be used as a template argument}}
+}
+
+template<typename T>
+struct X1 {
+  template<int (&Array)[T::value]> // expected-error{{variable length array cannot be used in a template instantiation}}
+  struct Inner {
+    
+  };
+};
+
+X1<HasConstantValue> x1a;
+X1<HasNonConstantValue> x1b; // expected-note{{in instantiation of}}
+
+// Template argument deduction does not allow deducing a size from a VLA.
+template<typename T, unsigned N>
+void accept_array(T (&array)[N]); // expected-note{{candidate template ignored: failed template argument deduction}}
+
+void test_accept_array(int N) {
+  int array[N];
+  accept_array(array); // expected-error{{no matching function for call to 'accept_array'}}
+}
+
+// Variably-modified types cannot be used in local classes.
+void local_classes(int N) {
+  struct X {
+    int size;
+    int array[N]; // expected-error{{fields must have a constant size: 'variable length array in structure' extension will never be supported}}
+  };
+}

Propchange: cfe/trunk/test/SemaCXX/c99-variable-length-array.cpp
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cfe/trunk/test/SemaCXX/c99-variable-length-array.cpp
------------------------------------------------------------------------------
    svn:keywords = Id

Propchange: cfe/trunk/test/SemaCXX/c99-variable-length-array.cpp
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: cfe/trunk/test/SemaCXX/c99.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/c99.cpp?rev=104443&r1=104442&r2=104443&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/c99.cpp (original)
+++ cfe/trunk/test/SemaCXX/c99.cpp Sat May 22 11:17:30 2010
@@ -1,8 +1,3 @@
 // RUN: %clang_cc1 -fsyntax-only -verify %s
-
-void f0(int i) {
-  char array[i]; // expected-error{{variable length arrays}}
-}
-
 void f1(int i[static 5]) { // expected-error{{C99}}
 }

Modified: cfe/trunk/test/SemaCXX/offsetof.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/offsetof.cpp?rev=104443&r1=104442&r2=104443&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/offsetof.cpp (original)
+++ cfe/trunk/test/SemaCXX/offsetof.cpp Sat May 22 11:17:30 2010
@@ -26,7 +26,7 @@
 // Constant and non-constant offsetof expressions
 void test_ice(int i) {
   int array0[__builtin_offsetof(HasArray, array[5])];
-  int array1[__builtin_offsetof(HasArray, array[i])]; // expected-error{{variable length arrays are not permitted in C++}}
+  int array1[__builtin_offsetof(HasArray, array[i])];
 }
 
 // Bitfields

Modified: cfe/trunk/test/SemaObjCXX/vla.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjCXX/vla.mm?rev=104443&r1=104442&r2=104443&view=diff
==============================================================================
--- cfe/trunk/test/SemaObjCXX/vla.mm (original)
+++ cfe/trunk/test/SemaObjCXX/vla.mm Sat May 22 11:17:30 2010
@@ -6,7 +6,7 @@
 @end
 
 void test(Data *d) {
-  char buffer[[d length]]; // expected-error{{variable length arrays are not permitted in C++}}
+  char buffer[[d length]];
   [d getData:buffer];
 }
 

Modified: cfe/trunk/test/SemaTemplate/instantiate-declref-ice.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/instantiate-declref-ice.cpp?rev=104443&r1=104442&r2=104443&view=diff
==============================================================================
--- cfe/trunk/test/SemaTemplate/instantiate-declref-ice.cpp (original)
+++ cfe/trunk/test/SemaTemplate/instantiate-declref-ice.cpp Sat May 22 11:17:30 2010
@@ -31,5 +31,4 @@
 template<typename T>
 const unsigned X1<T>::value = sizeof(T);
 
-int array3[X1<int>::value == sizeof(int)? 1 : -1]; // expected-error{{variable length arrays are not permitted in C++}} \
-// expected-error{{variable length array declaration not allowed at file scope}}
+int array3[X1<int>::value == sizeof(int)? 1 : -1]; // expected-error{{variable length array declaration not allowed at file scope}}

Modified: cfe/trunk/www/cxx_compatibility.html
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/www/cxx_compatibility.html?rev=104443&r1=104442&r2=104443&view=diff
==============================================================================
--- cfe/trunk/www/cxx_compatibility.html (original)
+++ cfe/trunk/www/cxx_compatibility.html Sat May 22 11:17:30 2010
@@ -42,14 +42,28 @@
 <h2 id="vla">Variable-length arrays</h2>
 <!-- ======================================================================= -->
 
-<p>GCC allows an array's size to be determined at run time. This,
-however, is not standard C++. Furthermore, it is a potential security
-hole as an incorrect array size may overflow the stack. If Clang tells
-you <tt>"variable length arrays are not permitted in C++"</tt>, here
-are some ways in which you can fix it:</p>
+<p>GCC and C99 allow an array's size to be determined at run
+time. This extension is not permitted in standard C++. However, Clang
+supports such variable length arrays in very limited circumstances for
+compatibility with GNU C and C99 programs:</p>
+
+<ul>  
+  <li>The element type of a variable length array must be a POD
+  ("plain old data") type, which means that it cannot have any
+  user-declared constructors or destructors, base classes, or any
+  members if non-POD type. All C types are POD types.</li>
+
+  <li>Variable length arrays cannot be used in conjunction with
+  templates. For example, one cannot use a variable length array
+  inside a template or use a variable length array type in a template
+  argument.</li>
+</ul>
+
+<p>If your code uses variable length arrays in a manner that Clang doesn't support, there are several ways to fix your code:
 
 <ol>
-<li>replace it with a fixed-size array if you can determine a
+<li>replace the variable length array with a fixed-size array if you can
+    determine a
     reasonable upper bound at compile time; sometimes this is as
     simple as changing <tt>int size = ...;</tt> to <tt>const int size
     = ...;</tt> (if the definition of <tt>size</tt> is a compile-time





More information about the cfe-commits mailing list