Add support for initializing char arrays from string literals.

Adapted from a patch by Anders Carlsson.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@44816 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Steve Naroff 2007-12-10 22:44:33 +00:00
Родитель 76315cabb3
Коммит 2fdc374909
6 изменённых файлов: 151 добавлений и 33 удалений

Просмотреть файл

@ -684,7 +684,10 @@ private:
void CheckConstantInitList(QualType DeclType, InitListExpr *IList,
QualType ElementType, bool isStatic,
int &nInitializers, bool &hadError);
bool CheckForCharArrayInitializer(InitListExpr *IList, QualType ElementType,
int &nInitializers, bool isConstant,
bool &hadError);
// CheckVectorCast - check type constraints for vectors.
// Since vectors are an extension, there are no C standard reference for this.
// We allow casting between vectors and integer datatypes of the same size.

Просмотреть файл

@ -429,21 +429,75 @@ bool Sema::CheckInitExpr(Expr *expr, InitListExpr *IList, unsigned slot,
void Sema::CheckVariableInitList(QualType DeclType, InitListExpr *IList,
QualType ElementType, bool isStatic,
int &nInitializers, bool &hadError) {
for (unsigned i = 0; i < IList->getNumInits(); i++) {
Expr *expr = IList->getInit(i);
unsigned numInits = IList->getNumInits();
if (numInits) {
if (CheckForCharArrayInitializer(IList, ElementType, nInitializers,
false, hadError))
return;
for (unsigned i = 0; i < numInits; i++) {
Expr *expr = IList->getInit(i);
if (InitListExpr *InitList = dyn_cast<InitListExpr>(expr)) {
if (const ConstantArrayType *CAT = DeclType->getAsConstantArrayType()) {
int maxElements = CAT->getMaximumElements();
CheckConstantInitList(DeclType, InitList, ElementType, isStatic,
maxElements, hadError);
if (InitListExpr *InitList = dyn_cast<InitListExpr>(expr)) {
if (const ConstantArrayType *CAT = DeclType->getAsConstantArrayType()) {
int maxElements = CAT->getMaximumElements();
CheckConstantInitList(DeclType, InitList, ElementType, isStatic,
maxElements, hadError);
}
} else {
hadError = CheckInitExpr(expr, IList, i, isStatic, ElementType);
}
nInitializers++;
}
} else {
Diag(IList->getLocStart(),
diag::err_at_least_one_initializer_needed_to_size_array);
hadError = true;
}
}
bool Sema::CheckForCharArrayInitializer(InitListExpr *IList,
QualType ElementType,
int &nInitializers, bool isConstant,
bool &hadError)
{
if (ElementType->isPointerType())
return false;
if (StringLiteral *literal = dyn_cast<StringLiteral>(IList->getInit(0))) {
// FIXME: Handle wide strings
if (ElementType->isCharType()) {
if (isConstant) {
if (literal->getByteLength() > (unsigned)nInitializers) {
Diag(literal->getSourceRange().getBegin(),
diag::warn_initializer_string_for_char_array_too_long,
literal->getSourceRange());
}
} else {
nInitializers = literal->getByteLength() + 1;
}
} else {
hadError = CheckInitExpr(expr, IList, i, isStatic, ElementType);
// FIXME: It might be better if we could point to the declaration
// here, instead of the string literal.
Diag(literal->getSourceRange().getBegin(),
diag::array_of_wrong_type_initialized_from_string,
ElementType.getAsString());
hadError = true;
}
nInitializers++;
// Check for excess initializers
for (unsigned i = 1; i < IList->getNumInits(); i++) {
Expr *expr = IList->getInit(i);
Diag(expr->getLocStart(),
diag::err_excess_initializers_in_char_array_initializer,
expr->getSourceRange());
}
return true;
}
return;
return false;
}
// FIXME: Doesn't deal with arrays of structures yet.
@ -473,6 +527,11 @@ void Sema::CheckConstantInitList(QualType DeclType, InitListExpr *IList,
// The empty init list "{ }" is treated specially below.
unsigned numInits = IList->getNumInits();
if (numInits) {
if (CheckForCharArrayInitializer(IList, ElementType,
maxElementsAtThisLevel,
true, hadError))
return;
for (unsigned i = 0; i < numInits; i++) {
Expr *expr = IList->getInit(i);
@ -499,19 +558,42 @@ void Sema::CheckConstantInitList(QualType DeclType, InitListExpr *IList,
Diag(IList->getLocStart(), diag::warn_excess_initializers,
IList->getSourceRange());
}
return;
}
bool Sema::CheckInitializer(Expr *&Init, QualType &DeclType, bool isStatic) {
InitListExpr *InitList = dyn_cast<InitListExpr>(Init);
if (!InitList)
return CheckSingleInitializer(Init, isStatic, DeclType);
bool hadError = false;
InitListExpr *InitList = dyn_cast<InitListExpr>(Init);
if (!InitList) {
if (StringLiteral *strLiteral = dyn_cast<StringLiteral>(Init)) {
const VariableArrayType *VAT = DeclType->getAsVariableArrayType();
// FIXME: Handle wide strings
if (VAT && VAT->getElementType()->isCharType()) {
// C99 6.7.8p14. We have an array of character type with unknown size
// being initialized to a string literal.
llvm::APSInt ConstVal(32);
ConstVal = strLiteral->getByteLength() + 1;
// Return a new array type (C99 6.7.8p22).
DeclType = Context.getConstantArrayType(VAT->getElementType(), ConstVal,
ArrayType::Normal, 0);
return hadError;
}
const ConstantArrayType *CAT = DeclType->getAsConstantArrayType();
if (CAT && CAT->getElementType()->isCharType()) {
// C99 6.7.8p14. We have an array of character type with known size.
if (strLiteral->getByteLength() > (unsigned)CAT->getMaximumElements()) {
Diag(strLiteral->getSourceRange().getBegin(),
diag::warn_initializer_string_for_char_array_too_long,
strLiteral->getSourceRange());
}
return hadError;
}
}
return CheckSingleInitializer(Init, isStatic, DeclType);
}
// We have an InitListExpr, make sure we set the type.
Init->setType(DeclType);
bool hadError = false;
// C99 6.7.8p3: The type of the entity to be initialized shall be an array
// of unknown size ("[]") or an object type that is not a variable array type.
if (const VariableArrayType *VAT = DeclType->getAsVariableArrayType()) {
@ -525,13 +607,19 @@ bool Sema::CheckInitializer(Expr *&Init, QualType &DeclType, bool isStatic) {
int numInits = 0;
CheckVariableInitList(VAT->getElementType(), InitList, VAT->getBaseType(),
isStatic, numInits, hadError);
if (!hadError) {
// Return a new array type from the number of initializers (C99 6.7.8p22).
llvm::APSInt ConstVal(32);
llvm::APSInt ConstVal(32);
if (!hadError)
ConstVal = numInits;
DeclType = Context.getConstantArrayType(VAT->getElementType(), ConstVal,
ArrayType::Normal, 0);
}
// Return a new array type from the number of initializers (C99 6.7.8p22).
// Note that if there was an error, we will still set the decl type,
// to an array type with 0 elements.
// This is to avoid "incomplete type foo[]" errors when we've already
// reported the real cause of the error.
DeclType = Context.getConstantArrayType(VAT->getElementType(), ConstVal,
ArrayType::Normal, 0);
return hadError;
}
if (const ConstantArrayType *CAT = DeclType->getAsConstantArrayType()) {

Просмотреть файл

@ -689,15 +689,9 @@ ActOnCompoundLiteral(SourceLocation LParenLoc, TypeTy *Ty,
//assert((InitExpr != 0) && "ActOnCompoundLiteral(): missing expression");
Expr *literalExpr = static_cast<Expr*>(InitExpr);
// FIXME: This is just a temporary workaround to get
// test/Parser/compound_literal.c passing. (CheckInitializer does not support
// initializing a char array from a single string literal).
if (!literalType->isArrayType() ||
!literalType->getAsArrayType()->getElementType()->isCharType()) {
// FIXME: add more semantic analysis (C99 6.5.2.5).
if (CheckInitializer(literalExpr, literalType, false))
return 0;
}
// FIXME: add more semantic analysis (C99 6.5.2.5).
if (CheckInitializer(literalExpr, literalType, false))
return 0;
return new CompoundLiteralExpr(literalType, literalExpr);
}

Просмотреть файл

@ -605,6 +605,10 @@ DIAG(err_typecheck_negative_array_size, ERROR,
"array size is negative")
DIAG(ext_typecheck_zero_array_size, EXTENSION,
"zero size arrays are an extension")
DIAG(err_at_least_one_initializer_needed_to_size_array, ERROR,
"at least one initializer value required to size array")
DIAG(array_of_wrong_type_initialized_from_string, ERROR,
"array of wrong type '%0' initialized from string constant")
DIAG(err_array_size_non_int, ERROR,
"size of array has non-integer type '%0'")
DIAG(err_init_element_not_constant, ERROR,
@ -617,6 +621,10 @@ DIAG(err_variable_object_no_init, ERROR,
"variable-sized object may not be initialized")
DIAG(warn_excess_initializers, EXTENSION,
"excess elements in array initializer")
DIAG(err_excess_initializers_in_char_array_initializer, ERROR,
"excess elements in char array initializer")
DIAG(warn_initializer_string_for_char_array_too_long, WARNING,
"initializer-string for char array is too long")
DIAG(warn_braces_around_scalar_init, WARNING,
"braces around scalar initializer")
DIAG(err_illegal_initializer, ERROR,

Просмотреть файл

@ -45,7 +45,7 @@ typedef int TA[I]; // expected-error {{variable length array declared outside of
void strFunc(char *);
const char staticAry[] = "test";
int checkStaticAry() {
strFunc(staticAry); // expected-warning{{passing 'char const []' to 'char *' discards qualifiers}}
strFunc(staticAry); // expected-warning{{passing 'char const [5]' to 'char *' discards qualifiers}}
}

Просмотреть файл

@ -137,3 +137,28 @@ void testTypedef()
AryT a = { 1, 2 }, b = { 3, 4, 5 };
}
static char const xx[] = "test";
static char const yy[5] = "test";
static char const zz[3] = "test"; // expected-warning{{initializer-string for char array is too long}}
void charArrays()
{
static char const test[] = "test";
static char const test2[] = { "weird stuff" };
static char const test3[] = { "test", "excess stuff" }; // expected-error{{excess elements in char array initializer}}
char* cp[] = { "Hello" };
char c[] = { "Hello" };
int l[sizeof(c) == 6 ? 1 : -1];
int i[] = { "Hello "}; // expected-error{{array of wrong type 'int' initialized from string constant}}
char c2[] = { "Hello", "Good bye" }; //expected-error{{excess elements in char array initializer}}
int i2[1] = { "Hello" }; //expected-error{{array of wrong type 'int' initialized from string constant}}
char c3[5] = { "Hello" };
char c4[4] = { "Hello" }; //expected-warning{{initializer-string for char array is too long}}
int i3[] = {}; //expected-error{{at least one initializer value required to size array}} expected-warning{{use of GNU empty initializer extension}}
}