From: Chris Lattner Date: Tue, 24 Feb 2009 22:27:37 +0000 (+0000) Subject: move some initialization checking code from SemaDecl.cpp X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=dd8e0065207e953bb28b95ad9cb6b2c13f56b3b8;p=clang move some initialization checking code from SemaDecl.cpp to SemaInit.cpp, no functionality change. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@65394 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 373296fb58..abb5e40dd4 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -1100,147 +1100,6 @@ Sema::DeclTy *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, return Anon; } -bool Sema::CheckSingleInitializer(Expr *&Init, QualType DeclType, - bool DirectInit) { - // Get the type before calling CheckSingleAssignmentConstraints(), since - // it can promote the expression. - QualType InitType = Init->getType(); - - if (getLangOptions().CPlusPlus) { - // FIXME: I dislike this error message. A lot. - if (PerformImplicitConversion(Init, DeclType, "initializing", DirectInit)) - return Diag(Init->getSourceRange().getBegin(), - diag::err_typecheck_convert_incompatible) - << DeclType << Init->getType() << "initializing" - << Init->getSourceRange(); - - return false; - } - - AssignConvertType ConvTy = CheckSingleAssignmentConstraints(DeclType, Init); - return DiagnoseAssignmentResult(ConvTy, Init->getLocStart(), DeclType, - InitType, Init, "initializing"); -} - -bool Sema::CheckStringLiteralInit(StringLiteral *strLiteral, QualType &DeclT) { - const ArrayType *AT = Context.getAsArrayType(DeclT); - - if (const IncompleteArrayType *IAT = dyn_cast(AT)) { - // 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). - DeclT = Context.getConstantArrayType(IAT->getElementType(), ConstVal, - ArrayType::Normal, 0); - } else { - const ConstantArrayType *CAT = cast(AT); - // C99 6.7.8p14. We have an array of character type with known size. - // FIXME: Avoid truncation for 64-bit length strings. - if (strLiteral->getByteLength() > (unsigned)CAT->getSize().getZExtValue()) - Diag(strLiteral->getSourceRange().getBegin(), - diag::warn_initializer_string_for_char_array_too_long) - << strLiteral->getSourceRange(); - } - // Set type from "char *" to "constant array of char". - strLiteral->setType(DeclT); - // For now, we always return false (meaning success). - return false; -} - -StringLiteral *Sema::IsStringLiteralInit(Expr *Init, QualType DeclType) { - if (const ArrayType *AT = Context.getAsArrayType(DeclType)) - if (AT->getElementType()->isCharType()) - return dyn_cast(Init->IgnoreParens()); - return 0; -} - -bool Sema::CheckInitializerTypes(Expr *&Init, QualType &DeclType, - SourceLocation InitLoc, - DeclarationName InitEntity, - bool DirectInit) { - if (DeclType->isDependentType() || Init->isTypeDependent()) - return false; - - // C++ [dcl.init.ref]p1: - // A variable declared to be a T&, that is "reference to type T" - // (8.3.2), shall be initialized by an object, or function, of - // type T or by an object that can be converted into a T. - if (DeclType->isReferenceType()) - return CheckReferenceInit(Init, DeclType, 0, false, DirectInit); - - // 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 = Context.getAsVariableArrayType(DeclType)) - return Diag(InitLoc, diag::err_variable_object_no_init) - << VAT->getSizeExpr()->getSourceRange(); - - InitListExpr *InitList = dyn_cast(Init); - if (!InitList) { - // FIXME: Handle wide strings - if (StringLiteral *StrLiteral = IsStringLiteralInit(Init, DeclType)) - return CheckStringLiteralInit(StrLiteral, DeclType); - - // C++ [dcl.init]p14: - // -- If the destination type is a (possibly cv-qualified) class - // type: - if (getLangOptions().CPlusPlus && DeclType->isRecordType()) { - QualType DeclTypeC = Context.getCanonicalType(DeclType); - QualType InitTypeC = Context.getCanonicalType(Init->getType()); - - // -- If the initialization is direct-initialization, or if it is - // copy-initialization where the cv-unqualified version of the - // source type is the same class as, or a derived class of, the - // class of the destination, constructors are considered. - if ((DeclTypeC.getUnqualifiedType() == InitTypeC.getUnqualifiedType()) || - IsDerivedFrom(InitTypeC, DeclTypeC)) { - CXXConstructorDecl *Constructor - = PerformInitializationByConstructor(DeclType, &Init, 1, - InitLoc, Init->getSourceRange(), - InitEntity, - DirectInit? IK_Direct : IK_Copy); - return Constructor == 0; - } - - // -- Otherwise (i.e., for the remaining copy-initialization - // cases), user-defined conversion sequences that can - // convert from the source type to the destination type or - // (when a conversion function is used) to a derived class - // thereof are enumerated as described in 13.3.1.4, and the - // best one is chosen through overload resolution - // (13.3). If the conversion cannot be done or is - // ambiguous, the initialization is ill-formed. The - // function selected is called with the initializer - // expression as its argument; if the function is a - // constructor, the call initializes a temporary of the - // destination type. - // FIXME: We're pretending to do copy elision here; return to - // this when we have ASTs for such things. - if (!PerformImplicitConversion(Init, DeclType, "initializing")) - return false; - - if (InitEntity) - return Diag(InitLoc, diag::err_cannot_initialize_decl) - << InitEntity << (int)(Init->isLvalue(Context) == Expr::LV_Valid) - << Init->getType() << Init->getSourceRange(); - else - return Diag(InitLoc, diag::err_cannot_initialize_decl_noname) - << DeclType << (int)(Init->isLvalue(Context) == Expr::LV_Valid) - << Init->getType() << Init->getSourceRange(); - } - - // C99 6.7.8p16. - if (DeclType->isArrayType()) - return Diag(Init->getLocStart(), diag::err_array_init_list_required) - << Init->getSourceRange(); - - return CheckSingleInitializer(Init, DeclType, DirectInit); - } - - bool hadError = CheckInitList(InitList, DeclType); - Init = InitList; - return hadError; -} /// GetNameForDeclarator - Determine the full declaration name for the /// given Declarator. diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index 38ab5c520d..e3235ac401 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -7,9 +7,12 @@ // //===----------------------------------------------------------------------===// // -// This file implements semantic analysis for initializers. The entry -// point is Sema::CheckInitList(), but all of the work is performed -// within the InitListChecker class. +// This file implements semantic analysis for initializers. The main entry +// point is Sema::CheckInitList(), but all of the work is performed +// within the InitListChecker class. +// +// This file also includes some miscellaneous other initialization checking +// code that is part of Sema. // //===----------------------------------------------------------------------===// @@ -20,6 +23,156 @@ #include using namespace clang; +//===----------------------------------------------------------------------===// +// Sema Initialization Checking +//===----------------------------------------------------------------------===// + +StringLiteral *Sema::IsStringLiteralInit(Expr *Init, QualType DeclType) { + if (const ArrayType *AT = Context.getAsArrayType(DeclType)) + if (AT->getElementType()->isCharType()) + return dyn_cast(Init->IgnoreParens()); + return 0; +} + +bool Sema::CheckSingleInitializer(Expr *&Init, QualType DeclType, + bool DirectInit) { + // Get the type before calling CheckSingleAssignmentConstraints(), since + // it can promote the expression. + QualType InitType = Init->getType(); + + if (getLangOptions().CPlusPlus) { + // FIXME: I dislike this error message. A lot. + if (PerformImplicitConversion(Init, DeclType, "initializing", DirectInit)) + return Diag(Init->getSourceRange().getBegin(), + diag::err_typecheck_convert_incompatible) + << DeclType << Init->getType() << "initializing" + << Init->getSourceRange(); + + return false; + } + + AssignConvertType ConvTy = CheckSingleAssignmentConstraints(DeclType, Init); + return DiagnoseAssignmentResult(ConvTy, Init->getLocStart(), DeclType, + InitType, Init, "initializing"); +} + +bool Sema::CheckStringLiteralInit(StringLiteral *strLiteral, QualType &DeclT) { + const ArrayType *AT = Context.getAsArrayType(DeclT); + + if (const IncompleteArrayType *IAT = dyn_cast(AT)) { + // 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). + DeclT = Context.getConstantArrayType(IAT->getElementType(), ConstVal, + ArrayType::Normal, 0); + } else { + const ConstantArrayType *CAT = cast(AT); + // C99 6.7.8p14. We have an array of character type with known size. + // FIXME: Avoid truncation for 64-bit length strings. + if (strLiteral->getByteLength() > (unsigned)CAT->getSize().getZExtValue()) + Diag(strLiteral->getSourceRange().getBegin(), + diag::warn_initializer_string_for_char_array_too_long) + << strLiteral->getSourceRange(); + } + // Set type from "char *" to "constant array of char". + strLiteral->setType(DeclT); + // For now, we always return false (meaning success). + return false; +} + +bool Sema::CheckInitializerTypes(Expr *&Init, QualType &DeclType, + SourceLocation InitLoc, + DeclarationName InitEntity, + bool DirectInit) { + if (DeclType->isDependentType() || Init->isTypeDependent()) + return false; + + // C++ [dcl.init.ref]p1: + // A variable declared to be a T&, that is "reference to type T" + // (8.3.2), shall be initialized by an object, or function, of + // type T or by an object that can be converted into a T. + if (DeclType->isReferenceType()) + return CheckReferenceInit(Init, DeclType, 0, false, DirectInit); + + // 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 = Context.getAsVariableArrayType(DeclType)) + return Diag(InitLoc, diag::err_variable_object_no_init) + << VAT->getSizeExpr()->getSourceRange(); + + InitListExpr *InitList = dyn_cast(Init); + if (!InitList) { + // FIXME: Handle wide strings + if (StringLiteral *StrLiteral = IsStringLiteralInit(Init, DeclType)) + return CheckStringLiteralInit(StrLiteral, DeclType); + + // C++ [dcl.init]p14: + // -- If the destination type is a (possibly cv-qualified) class + // type: + if (getLangOptions().CPlusPlus && DeclType->isRecordType()) { + QualType DeclTypeC = Context.getCanonicalType(DeclType); + QualType InitTypeC = Context.getCanonicalType(Init->getType()); + + // -- If the initialization is direct-initialization, or if it is + // copy-initialization where the cv-unqualified version of the + // source type is the same class as, or a derived class of, the + // class of the destination, constructors are considered. + if ((DeclTypeC.getUnqualifiedType() == InitTypeC.getUnqualifiedType()) || + IsDerivedFrom(InitTypeC, DeclTypeC)) { + CXXConstructorDecl *Constructor + = PerformInitializationByConstructor(DeclType, &Init, 1, + InitLoc, Init->getSourceRange(), + InitEntity, + DirectInit? IK_Direct : IK_Copy); + return Constructor == 0; + } + + // -- Otherwise (i.e., for the remaining copy-initialization + // cases), user-defined conversion sequences that can + // convert from the source type to the destination type or + // (when a conversion function is used) to a derived class + // thereof are enumerated as described in 13.3.1.4, and the + // best one is chosen through overload resolution + // (13.3). If the conversion cannot be done or is + // ambiguous, the initialization is ill-formed. The + // function selected is called with the initializer + // expression as its argument; if the function is a + // constructor, the call initializes a temporary of the + // destination type. + // FIXME: We're pretending to do copy elision here; return to + // this when we have ASTs for such things. + if (!PerformImplicitConversion(Init, DeclType, "initializing")) + return false; + + if (InitEntity) + return Diag(InitLoc, diag::err_cannot_initialize_decl) + << InitEntity << (int)(Init->isLvalue(Context) == Expr::LV_Valid) + << Init->getType() << Init->getSourceRange(); + else + return Diag(InitLoc, diag::err_cannot_initialize_decl_noname) + << DeclType << (int)(Init->isLvalue(Context) == Expr::LV_Valid) + << Init->getType() << Init->getSourceRange(); + } + + // C99 6.7.8p16. + if (DeclType->isArrayType()) + return Diag(Init->getLocStart(), diag::err_array_init_list_required) + << Init->getSourceRange(); + + return CheckSingleInitializer(Init, DeclType, DirectInit); + } + + bool hadError = CheckInitList(InitList, DeclType); + Init = InitList; + return hadError; +} + +//===----------------------------------------------------------------------===// +// Semantic checking for initializer lists. +//===----------------------------------------------------------------------===// + /// @brief Semantic checking for initializer lists. /// /// The InitListChecker class contains a set of routines that each diff --git a/test/CodeGenObjC/encode-test-3.m b/test/CodeGenObjC/encode-test-3.m index c10db091cc..ce7fc06577 100644 --- a/test/CodeGenObjC/encode-test-3.m +++ b/test/CodeGenObjC/encode-test-3.m @@ -11,4 +11,5 @@ int main() { // PR3648 int a[sizeof(@encode(int)) == 2 ? 1 : -1]; // Type is char[2] +const char *B = @encode(int); char (*c)[2] = &@encode(int); // @encode is an lvalue