[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