зеркало из https://github.com/microsoft/clang-1.git
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:
Родитель
76315cabb3
Коммит
2fdc374909
|
@ -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}}
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче