diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index c765deb8e6b0..5d5df5e1ac4e 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -48,6 +48,8 @@ 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 ext_vla_folded_to_constant : Extension< + "variable length array folded to constant array as an extension">; // C99 variably modified types def err_variably_modified_template_arg : Error< diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 5fd8afa6acf4..ec8fdc917c05 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -1100,6 +1100,28 @@ QualType Sema::BuildReferenceType(QualType T, bool SpelledAsLValue, return Context.getRValueReferenceType(T); } +/// Check whether the specified array size makes the array type a VLA. If so, +/// return true, if not, return the size of the array in SizeVal. +static bool isArraySizeVLA(Expr *ArraySize, llvm::APSInt &SizeVal, Sema &S) { + // If the size is an ICE, it certainly isn't a VLA. + if (ArraySize->isIntegerConstantExpr(SizeVal, S.Context)) + return false; + + // If we're in a GNU mode (like gnu99, but not c99) accept any evaluatable + // value as an extension. + Expr::EvalResult Result; + if (S.LangOpts.GNUMode && ArraySize->Evaluate(Result, S.Context)) { + if (!Result.hasSideEffects() && Result.Val.isInt()) { + SizeVal = Result.Val.getInt(); + S.Diag(ArraySize->getLocStart(), diag::ext_vla_folded_to_constant); + return false; + } + } + + return true; +} + + /// \brief Build an array type. /// /// \param T The type of each element in the array. @@ -1200,11 +1222,13 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM, T = Context.getIncompleteArrayType(T, ASM, Quals); } else if (ArraySize->isTypeDependent() || ArraySize->isValueDependent()) { T = Context.getDependentSizedArrayType(T, ArraySize, ASM, Quals, Brackets); - } else if (!ArraySize->isIntegerConstantExpr(ConstVal, Context) || - (!T->isDependentType() && !T->isIncompleteType() && - !T->isConstantSizeType())) { - // Per C99, a variable array is an array with either a non-constant - // size or an element type that has a non-constant-size + } else if (!T->isDependentType() && !T->isIncompleteType() && + !T->isConstantSizeType()) { + // C99: an array with an element type that has a non-constant-size is a VLA. + T = Context.getVariableArrayType(T, ArraySize, ASM, Quals, Brackets); + } else if (isArraySizeVLA(ArraySize, ConstVal, *this)) { + // C99: an array with a non-ICE size is a VLA. We accept any expression + // that we can fold to a non-zero positive value as an extension. T = Context.getVariableArrayType(T, ArraySize, ASM, Quals, Brackets); } else { // C99 6.7.5.2p1: If the expression is a constant expression, it shall diff --git a/clang/test/Sema/const-eval.c b/clang/test/Sema/const-eval.c index 56c429c58c2a..bdb40ae54be3 100644 --- a/clang/test/Sema/const-eval.c +++ b/clang/test/Sema/const-eval.c @@ -36,7 +36,7 @@ int g17[(3?:1) - 2]; EVAL_EXPR(18, ((int)((void*)10 + 10)) == 20 ? 1 : -1); struct s { - int a[(int)-1.0f]; // expected-error {{array size is negative}} + int a[(int)-1.0f]; // expected-error {{'a' declared as an array with a negative size}} }; EVAL_EXPR(19, ((int)&*(char*)10 == 10 ? 1 : -1)); diff --git a/clang/test/Sema/i-c-e.c b/clang/test/Sema/i-c-e.c index 4d7007cd077c..1aac51e204f1 100644 --- a/clang/test/Sema/i-c-e.c +++ b/clang/test/Sema/i-c-e.c @@ -1,4 +1,4 @@ -// RUN: %clang %s -ffreestanding -fsyntax-only -Xclang -verify -pedantic -fpascal-strings +// RUN: %clang %s -ffreestanding -fsyntax-only -Xclang -verify -pedantic -fpascal-strings -std=c99 #include #include diff --git a/clang/test/Sema/struct-decl.c b/clang/test/Sema/struct-decl.c index e1c7073e01b2..6070e875f5a4 100644 --- a/clang/test/Sema/struct-decl.c +++ b/clang/test/Sema/struct-decl.c @@ -6,7 +6,7 @@ struct bar { struct foo { char name[(int)&((struct bar *)0)->n]; - char name2[(int)&((struct bar *)0)->n - 1]; //expected-error{{array size is negative}} + char name2[(int)&((struct bar *)0)->n - 1]; //expected-error{{'name2' declared as an array with a negative size}} }; // PR3430 diff --git a/clang/test/Sema/typedef-variable-type.c b/clang/test/Sema/typedef-variable-type.c index b805b1e0578f..8a7ee8b911c0 100644 --- a/clang/test/Sema/typedef-variable-type.c +++ b/clang/test/Sema/typedef-variable-type.c @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 %s -verify -fsyntax-only -pedantic -Wno-typedef-redefinition +// RUN: %clang_cc1 %s -verify -fsyntax-only -pedantic -Wno-typedef-redefinition -std=c99 // Make sure we accept a single typedef typedef int (*a)[!.0]; // expected-warning{{size of static array must be an integer constant expression}} diff --git a/clang/test/Sema/vla.c b/clang/test/Sema/vla.c index ebf9b889ee2a..fd7a6bf3d72f 100644 --- a/clang/test/Sema/vla.c +++ b/clang/test/Sema/vla.c @@ -42,7 +42,7 @@ void f3() } // PR3663 -static const unsigned array[((2 * (int)((((4) / 2) + 1.0/3.0) * (4) - 1e-8)) + 1)]; // expected-warning {{size of static array must be an integer constant expression}} +static const unsigned array[((2 * (int)((((4) / 2) + 1.0/3.0) * (4) - 1e-8)) + 1)]; // expected-warning {{variable length array folded to constant array as an extension}} int a[*]; // expected-error {{star modifier used outside of function prototype}} int f4(int a[*][*]); @@ -53,7 +53,7 @@ int pr2044b; int (*pr2044c(void))[pr2044b]; // expected-error {{variably modified type}} const int f5_ci = 1; -void f5() { char a[][f5_ci] = {""}; } // expected-error {{variable-sized object may not be initialized}} +void f5() { char a[][f5_ci] = {""}; } // expected-warning {{variable length array folded to constant array as an extension}} // PR5185 void pr5185(int a[*]); diff --git a/clang/test/SemaCXX/c99-variable-length-array.cpp b/clang/test/SemaCXX/c99-variable-length-array.cpp index 98df1dbfe81e..3f1d6a8a55c0 100644 --- a/clang/test/SemaCXX/c99-variable-length-array.cpp +++ b/clang/test/SemaCXX/c99-variable-length-array.cpp @@ -121,3 +121,12 @@ namespace PR8209 { (void)new vla_type; // expected-error{{variably}} } } + +namespace rdar8733881 { // rdar://8733881 + +static const int k_cVal3 = (int)(1000*0.2f); + int f() { + // Ok, fold to a constant size array as an extension. + char rgch[k_cVal3] = {0}; + } +}