diff options
-rw-r--r-- | Sema/Sema.h | 34 | ||||
-rw-r--r-- | Sema/SemaDecl.cpp | 48 | ||||
-rw-r--r-- | Sema/SemaExpr.cpp | 268 | ||||
-rw-r--r-- | Sema/SemaStmt.cpp | 53 | ||||
-rw-r--r-- | include/clang/Basic/DiagnosticKinds.def | 43 | ||||
-rw-r--r-- | test/Parser/builtin_types_compatible.c | 2 | ||||
-rw-r--r-- | test/Parser/implicit-casts.c | 4 | ||||
-rw-r--r-- | test/Parser/typeof.c | 4 | ||||
-rw-r--r-- | test/Sema/argument-checking.m | 4 | ||||
-rw-r--r-- | test/Sema/array-constraint.c | 2 | ||||
-rw-r--r-- | test/Sema/array-init.c | 6 | ||||
-rw-r--r-- | test/Sema/builtins.c | 5 | ||||
-rw-r--r-- | test/Sema/incompatible-protocol-qualified-types.m | 2 | ||||
-rw-r--r-- | test/Sema/objc-comptypes-1.m | 14 | ||||
-rw-r--r-- | test/Sema/objc-comptypes-3.m | 18 | ||||
-rw-r--r-- | test/Sema/objc-comptypes-5.m | 4 | ||||
-rw-r--r-- | test/Sema/objc-comptypes-6.m | 4 | ||||
-rw-r--r-- | test/Sema/objc-comptypes-7.m | 34 | ||||
-rw-r--r-- | test/Sema/protocol-id-test-3.m | 4 | ||||
-rw-r--r-- | test/Sema/typedef-retain.c | 4 | ||||
-rw-r--r-- | test/Sema/vector-assign.c | 28 |
21 files changed, 202 insertions, 383 deletions
diff --git a/Sema/Sema.h b/Sema/Sema.h index 6f546514db..e790a74251 100644 --- a/Sema/Sema.h +++ b/Sema/Sema.h @@ -613,34 +613,42 @@ private: // responsible for emitting appropriate error diagnostics. QualType UsualArithmeticConversions(Expr *&lExpr, Expr *&rExpr, bool isCompAssign = false); - enum AssignmentCheckResult { + enum AssignConvertType { Compatible, Incompatible, - PointerFromInt, - IntFromPointer, + PointerInt, FunctionVoidPointer, IncompatiblePointer, CompatiblePointerDiscardsQualifiers }; - // CheckAssignmentConstraints - Perform type checking for assignment, - // argument passing, variable initialization, and function return values. - // This routine is only used by the following two methods. C99 6.5.16. - AssignmentCheckResult CheckAssignmentConstraints(QualType lhs, QualType rhs); + + /// DiagnoseAssignmentResult - Emit a diagnostic, if required, for the + /// assignment conversion type specified by ConvTy. This returns true if the + /// conversion was invalid or false if the conversion was accepted. + bool DiagnoseAssignmentResult(AssignConvertType ConvTy, + SourceLocation Loc, + QualType DstType, QualType SrcType, + Expr *SrcExpr, const char *Flavor); + + /// CheckAssignmentConstraints - Perform type checking for assignment, + /// argument passing, variable initialization, and function return values. + /// This routine is only used by the following two methods. C99 6.5.16. + AssignConvertType CheckAssignmentConstraints(QualType lhs, QualType rhs); // CheckSingleAssignmentConstraints - Currently used by ActOnCallExpr, // CheckAssignmentOperands, and ActOnReturnStmt. Prior to type checking, // this routine performs the default function/array converions. - AssignmentCheckResult CheckSingleAssignmentConstraints(QualType lhs, - Expr *&rExpr); + AssignConvertType CheckSingleAssignmentConstraints(QualType lhs, + Expr *&rExpr); // CheckCompoundAssignmentConstraints - Type check without performing any // conversions. For compound assignments, the "Check...Operands" methods // perform the necessary conversions. - AssignmentCheckResult CheckCompoundAssignmentConstraints(QualType lhs, - QualType rhs); + AssignConvertType CheckCompoundAssignmentConstraints(QualType lhs, + QualType rhs); // Helper function for CheckAssignmentConstraints (C99 6.5.16.1p1) - AssignmentCheckResult CheckPointerTypesForAssignment(QualType lhsType, - QualType rhsType); + AssignConvertType CheckPointerTypesForAssignment(QualType lhsType, + QualType rhsType); /// the following "Check" methods will return a valid/converted QualType /// or a null QualType (indicating an error diagnostic was issued). diff --git a/Sema/SemaDecl.cpp b/Sema/SemaDecl.cpp index 1165e526d8..07b3d71368 100644 --- a/Sema/SemaDecl.cpp +++ b/Sema/SemaDecl.cpp @@ -364,53 +364,13 @@ bool Sema::CheckSingleInitializer(Expr *&Init, bool isStatic, return true; } - AssignmentCheckResult result; // Get the type before calling CheckSingleAssignmentConstraints(), since // it can promote the expression. - QualType rhsType = Init->getType(); + QualType InitType = Init->getType(); - result = CheckSingleAssignmentConstraints(DeclType, Init); - - // decode the result (notice that extensions still return a type). - switch (result) { - case Compatible: - break; - case Incompatible: - // FIXME: tighten up this check which should allow: - // char s[] = "abc", which is identical to char s[] = { 'a', 'b', 'c' }; - if (rhsType == Context.getPointerType(Context.CharTy)) - break; - Diag(Init->getLocStart(), diag::err_typecheck_assign_incompatible, - DeclType.getAsString(), rhsType.getAsString(), - Init->getSourceRange()); - return true; - case PointerFromInt: - Diag(Init->getLocStart(), diag::ext_typecheck_assign_pointer_int, - DeclType.getAsString(), rhsType.getAsString(), - Init->getSourceRange()); - break; - case IntFromPointer: - Diag(Init->getLocStart(), diag::ext_typecheck_assign_pointer_int, - DeclType.getAsString(), rhsType.getAsString(), - Init->getSourceRange()); - break; - case FunctionVoidPointer: - Diag(Init->getLocStart(), diag::ext_typecheck_assign_pointer_void_func, - DeclType.getAsString(), rhsType.getAsString(), - Init->getSourceRange()); - break; - case IncompatiblePointer: - Diag(Init->getLocStart(), diag::ext_typecheck_assign_incompatible_pointer, - DeclType.getAsString(), rhsType.getAsString(), - Init->getSourceRange()); - break; - case CompatiblePointerDiscardsQualifiers: - Diag(Init->getLocStart(), diag::ext_typecheck_assign_discards_qualifiers, - DeclType.getAsString(), rhsType.getAsString(), - Init->getSourceRange()); - break; - } - return false; + AssignConvertType ConvTy = CheckSingleAssignmentConstraints(DeclType, Init); + return DiagnoseAssignmentResult(ConvTy, Init->getLocStart(), DeclType, + InitType, Init, "initializing"); } bool Sema::CheckInitExpr(Expr *expr, InitListExpr *IList, unsigned slot, diff --git a/Sema/SemaExpr.cpp b/Sema/SemaExpr.cpp index 3a3cfc18bc..7ed0bf102a 100644 --- a/Sema/SemaExpr.cpp +++ b/Sema/SemaExpr.cpp @@ -615,55 +615,17 @@ ActOnCallExpr(ExprTy *fn, SourceLocation LParenLoc, // Continue to check argument types (even if we have too few/many args). for (unsigned i = 0; i != NumArgsToCheck; i++) { Expr *Arg = Args[i]; - QualType LHSType = Proto->getArgType(i); - QualType RHSType = Arg->getType(); - - // If necessary, apply function/array conversion. C99 6.7.5.3p[7,8]. - if (const ArrayType *AT = LHSType->getAsArrayType()) - LHSType = Context.getPointerType(AT->getElementType()); - else if (LHSType->isFunctionType()) - LHSType = Context.getPointerType(LHSType); + QualType ProtoArgType = Proto->getArgType(i); + QualType ArgType = Arg->getType(); // Compute implicit casts from the operand to the formal argument type. - AssignmentCheckResult Result = - CheckSingleAssignmentConstraints(LHSType, Arg); + AssignConvertType ConvTy = + CheckSingleAssignmentConstraints(ProtoArgType, Arg); TheCall->setArg(i, Arg); - // Decode the result (notice that AST's are still created for extensions). - SourceLocation Loc = Arg->getLocStart(); - switch (Result) { - case Compatible: - break; - case PointerFromInt: - Diag(Loc, diag::ext_typecheck_passing_pointer_int, - LHSType.getAsString(), RHSType.getAsString(), - Fn->getSourceRange(), Arg->getSourceRange()); - break; - case IntFromPointer: - Diag(Loc, diag::ext_typecheck_passing_pointer_int, - LHSType.getAsString(), RHSType.getAsString(), - Fn->getSourceRange(), Arg->getSourceRange()); - break; - case FunctionVoidPointer: - Diag(Loc, diag::ext_typecheck_passing_pointer_void_func, - LHSType.getAsString(), RHSType.getAsString(), - Fn->getSourceRange(), Arg->getSourceRange()); - break; - case IncompatiblePointer: - Diag(Loc, diag::ext_typecheck_passing_incompatible_pointer, - RHSType.getAsString(), LHSType.getAsString(), - Fn->getSourceRange(), Arg->getSourceRange()); - break; - case CompatiblePointerDiscardsQualifiers: - Diag(Loc, diag::ext_typecheck_passing_discards_qualifiers, - RHSType.getAsString(), LHSType.getAsString(), - Fn->getSourceRange(), Arg->getSourceRange()); - break; - case Incompatible: - return Diag(Loc, diag::err_typecheck_passing_incompatible, - RHSType.getAsString(), LHSType.getAsString(), - Fn->getSourceRange(), Arg->getSourceRange()); - } + if (DiagnoseAssignmentResult(ConvTy, Arg->getLocStart(), ProtoArgType, + ArgType, Arg, "passing")) + return true; } // If this is a variadic call, handle args passed through "...". @@ -1056,7 +1018,7 @@ QualType Sema::UsualArithmeticConversions(Expr *&lhsExpr, Expr *&rhsExpr, // routine is it effectively iqnores the qualifiers on the top level pointee. // This circumvents the usual type rules specified in 6.2.7p1 & 6.7.5.[1-3]. // FIXME: add a couple examples in this comment. -Sema::AssignmentCheckResult +Sema::AssignConvertType Sema::CheckPointerTypesForAssignment(QualType lhsType, QualType rhsType) { QualType lhptee, rhptee; @@ -1068,21 +1030,21 @@ Sema::CheckPointerTypesForAssignment(QualType lhsType, QualType rhsType) { lhptee = lhptee.getCanonicalType(); rhptee = rhptee.getCanonicalType(); - AssignmentCheckResult r = Compatible; + AssignConvertType ConvTy = Compatible; // C99 6.5.16.1p1: This following citation is common to constraints // 3 & 4 (below). ...and the type *pointed to* by the left has all the // qualifiers of the type *pointed to* by the right; if ((lhptee.getQualifiers() & rhptee.getQualifiers()) != rhptee.getQualifiers()) - r = CompatiblePointerDiscardsQualifiers; + ConvTy = CompatiblePointerDiscardsQualifiers; // C99 6.5.16.1p1 (constraint 4): If one operand is a pointer to an object or // incomplete type and the other is a pointer to a qualified or unqualified // version of void... if (lhptee->isVoidType()) { if (rhptee->isObjectType() || rhptee->isIncompleteType()) - return r; + return ConvTy; // As an extension, we allow cast to/from void* to function pointer. if (rhptee->isFunctionType()) @@ -1091,7 +1053,7 @@ Sema::CheckPointerTypesForAssignment(QualType lhsType, QualType rhsType) { if (rhptee->isVoidType()) { if (lhptee->isObjectType() || lhptee->isIncompleteType()) - return r; + return ConvTy; // As an extension, we allow cast to/from void* to function pointer. if (lhptee->isFunctionType()) @@ -1103,7 +1065,7 @@ Sema::CheckPointerTypesForAssignment(QualType lhsType, QualType rhsType) { if (!Context.typesAreCompatible(lhptee.getUnqualifiedType(), rhptee.getUnqualifiedType())) return IncompatiblePointer; // this "trumps" PointerAssignDiscardsQualifiers - return r; + return ConvTy; } /// CheckAssignmentConstraints (C99 6.5.16) - This routine currently @@ -1123,7 +1085,7 @@ Sema::CheckPointerTypesForAssignment(QualType lhsType, QualType rhsType) { /// C99 spec dictates. /// Note: the warning above turn into errors when -pedantic-errors is enabled. /// -Sema::AssignmentCheckResult +Sema::AssignConvertType Sema::CheckAssignmentConstraints(QualType lhsType, QualType rhsType) { @@ -1169,14 +1131,14 @@ Sema::CheckAssignmentConstraints(QualType lhsType, QualType rhsType) { return Compatible; } else if (lhsType->isPointerType()) { if (rhsType->isIntegerType()) - return PointerFromInt; + return PointerInt; if (rhsType->isPointerType()) return CheckPointerTypesForAssignment(lhsType, rhsType); } else if (rhsType->isPointerType()) { // C99 6.5.16.1p1: the left operand is _Bool and the right is a pointer. if ((lhsType->isIntegerType()) && (lhsType != Context.BoolTy)) - return IntFromPointer; + return PointerInt; if (lhsType->isPointerType()) return CheckPointerTypesForAssignment(lhsType, rhsType); @@ -1187,7 +1149,7 @@ Sema::CheckAssignmentConstraints(QualType lhsType, QualType rhsType) { return Incompatible; } -Sema::AssignmentCheckResult +Sema::AssignConvertType Sema::CheckSingleAssignmentConstraints(QualType lhsType, Expr *&rExpr) { // C99 6.5.16.1p1: the left operand is a pointer and the right is // a null pointer constant. @@ -1206,9 +1168,8 @@ Sema::CheckSingleAssignmentConstraints(QualType lhsType, Expr *&rExpr) { if (!lhsType->isReferenceType()) DefaultFunctionArrayConversion(rExpr); - Sema::AssignmentCheckResult result; - - result = CheckAssignmentConstraints(lhsType, rExpr->getType()); + Sema::AssignConvertType result = + CheckAssignmentConstraints(lhsType, rExpr->getType()); // C99 6.5.16.1p2: The value of the right operand is converted to the // type of the assignment expression. @@ -1217,7 +1178,7 @@ Sema::CheckSingleAssignmentConstraints(QualType lhsType, Expr *&rExpr) { return result; } -Sema::AssignmentCheckResult +Sema::AssignConvertType Sema::CheckCompoundAssignmentConstraints(QualType lhsType, QualType rhsType) { return CheckAssignmentConstraints(lhsType, rhsType); } @@ -1501,81 +1462,47 @@ inline QualType Sema::CheckAssignmentOperands( // C99 6.5.16.1 { QualType lhsType = lex->getType(); QualType rhsType = compoundType.isNull() ? rex->getType() : compoundType; - bool hadError = false; Expr::isModifiableLvalueResult mlval = lex->isModifiableLvalue(); switch (mlval) { // C99 6.5.16p2 - case Expr::MLV_Valid: - break; - case Expr::MLV_ConstQualified: - Diag(loc, diag::err_typecheck_assign_const, lex->getSourceRange()); - hadError = true; - break; - case Expr::MLV_ArrayType: - Diag(loc, diag::err_typecheck_array_not_modifiable_lvalue, - lhsType.getAsString(), lex->getSourceRange()); - return QualType(); - case Expr::MLV_NotObjectType: - Diag(loc, diag::err_typecheck_non_object_not_modifiable_lvalue, - lhsType.getAsString(), lex->getSourceRange()); - return QualType(); - case Expr::MLV_InvalidExpression: - Diag(loc, diag::err_typecheck_expression_not_modifiable_lvalue, - lex->getSourceRange()); - return QualType(); - case Expr::MLV_IncompleteType: - case Expr::MLV_IncompleteVoidType: - Diag(loc, diag::err_typecheck_incomplete_type_not_modifiable_lvalue, - lhsType.getAsString(), lex->getSourceRange()); - return QualType(); - case Expr::MLV_DuplicateVectorComponents: - Diag(loc, diag::err_typecheck_duplicate_vector_components_not_mlvalue, - lex->getSourceRange()); - return QualType(); + case Expr::MLV_Valid: + break; + case Expr::MLV_ConstQualified: + Diag(loc, diag::err_typecheck_assign_const, lex->getSourceRange()); + return QualType(); + case Expr::MLV_ArrayType: + Diag(loc, diag::err_typecheck_array_not_modifiable_lvalue, + lhsType.getAsString(), lex->getSourceRange()); + return QualType(); + case Expr::MLV_NotObjectType: + Diag(loc, diag::err_typecheck_non_object_not_modifiable_lvalue, + lhsType.getAsString(), lex->getSourceRange()); + return QualType(); + case Expr::MLV_InvalidExpression: + Diag(loc, diag::err_typecheck_expression_not_modifiable_lvalue, + lex->getSourceRange()); + return QualType(); + case Expr::MLV_IncompleteType: + case Expr::MLV_IncompleteVoidType: + Diag(loc, diag::err_typecheck_incomplete_type_not_modifiable_lvalue, + lhsType.getAsString(), lex->getSourceRange()); + return QualType(); + case Expr::MLV_DuplicateVectorComponents: + Diag(loc, diag::err_typecheck_duplicate_vector_components_not_mlvalue, + lex->getSourceRange()); + return QualType(); } - AssignmentCheckResult result; - + + AssignConvertType ConvTy; if (compoundType.isNull()) - result = CheckSingleAssignmentConstraints(lhsType, rex); + ConvTy = CheckSingleAssignmentConstraints(lhsType, rex); else - result = CheckCompoundAssignmentConstraints(lhsType, rhsType); + ConvTy = CheckCompoundAssignmentConstraints(lhsType, rhsType); - // decode the result (notice that extensions still return a type). - switch (result) { - case Compatible: - break; - case Incompatible: - Diag(loc, diag::err_typecheck_assign_incompatible, - lhsType.getAsString(), rhsType.getAsString(), - lex->getSourceRange(), rex->getSourceRange()); - hadError = true; - break; - case PointerFromInt: - Diag(loc, diag::ext_typecheck_assign_pointer_int, - lhsType.getAsString(), rhsType.getAsString(), - lex->getSourceRange(), rex->getSourceRange()); - break; - case IntFromPointer: - Diag(loc, diag::ext_typecheck_assign_pointer_int, - lhsType.getAsString(), rhsType.getAsString(), - lex->getSourceRange(), rex->getSourceRange()); - break; - case FunctionVoidPointer: - Diag(loc, diag::ext_typecheck_assign_pointer_void_func, - lhsType.getAsString(), rhsType.getAsString(), - lex->getSourceRange(), rex->getSourceRange()); - break; - case IncompatiblePointer: - Diag(loc, diag::ext_typecheck_assign_incompatible_pointer, - lhsType.getAsString(), rhsType.getAsString(), - lex->getSourceRange(), rex->getSourceRange()); - break; - case CompatiblePointerDiscardsQualifiers: - Diag(loc, diag::ext_typecheck_assign_discards_qualifiers, - lhsType.getAsString(), rhsType.getAsString(), - lex->getSourceRange(), rex->getSourceRange()); - break; - } + if (DiagnoseAssignmentResult(ConvTy, loc, lhsType, rhsType, + rex, "assigning")) + return QualType(); + // C99 6.5.16p3: The type of an assignment expression is the type of the // left operand unless the left operand has qualified type, in which case // it is the unqualified version of the type of the left operand. @@ -1583,7 +1510,7 @@ inline QualType Sema::CheckAssignmentOperands( // C99 6.5.16.1 // is converted to the type of the assignment expression (above). // C++ 5.17p1: the type of the assignment expression is that of its left // oprdu. - return hadError ? QualType() : lhsType.getUnqualifiedType(); + return lhsType.getUnqualifiedType(); } inline QualType Sema::CheckCommaOperands( // C99 6.5.17 @@ -2097,18 +2024,14 @@ Sema::ExprResult Sema::ActOnChooseExpr(SourceLocation BuiltinLoc, ExprTy *cond, Sema::ExprResult Sema::ActOnVAArg(SourceLocation BuiltinLoc, ExprTy *expr, TypeTy *type, - SourceLocation RPLoc) -{ + SourceLocation RPLoc) { Expr *E = static_cast<Expr*>(expr); QualType T = QualType::getFromOpaquePtr(type); InitBuiltinVaListType(); - Sema::AssignmentCheckResult result; - - result = CheckAssignmentConstraints(Context.getBuiltinVaListType(), - E->getType()); - if (result != Compatible) + if (CheckAssignmentConstraints(Context.getBuiltinVaListType(), E->getType()) + != Compatible) return Diag(E->getLocStart(), diag::err_first_argument_to_va_arg_not_of_type_va_list, E->getType().getAsString(), @@ -2206,6 +2129,39 @@ Sema::ExprResult Sema::ParseObjCProtocolExpression(IdentifierInfo *ProtocolId, return new ObjCProtocolExpr(t, PDecl, AtLoc, RParenLoc); } +bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy, + SourceLocation Loc, + QualType DstType, QualType SrcType, + Expr *SrcExpr, const char *Flavor) { + // Decode the result (notice that AST's are still created for extensions). + bool isInvalid = false; + unsigned DiagKind; + switch (ConvTy) { + default: assert(0 && "Unknown conversion type"); + case Compatible: return false; + case PointerInt: + DiagKind = diag::ext_typecheck_convert_pointer_int; + break; + case IncompatiblePointer: + DiagKind = diag::ext_typecheck_convert_incompatible_pointer; + break; + case FunctionVoidPointer: + DiagKind = diag::ext_typecheck_convert_pointer_void_func; + break; + case CompatiblePointerDiscardsQualifiers: + DiagKind = diag::ext_typecheck_convert_discards_qualifiers; + break; + case Incompatible: + DiagKind = diag::err_typecheck_convert_incompatible; + isInvalid = true; + break; + } + + Diag(Loc, DiagKind, DstType.getAsString(), SrcType.getAsString(), Flavor, + SrcExpr->getSourceRange()); + return isInvalid; +} + bool Sema::CheckMessageArgumentTypes(Expr **Args, unsigned NumArgs, ObjcMethodDecl *Method) { bool anyIncompatibleArgs = false; @@ -2223,44 +2179,14 @@ bool Sema::CheckMessageArgumentTypes(Expr **Args, unsigned NumArgs, else if (lhsType->isFunctionType()) lhsType = Context.getPointerType(lhsType); - AssignmentCheckResult result = CheckSingleAssignmentConstraints(lhsType, - argExpr); + AssignConvertType Result = CheckSingleAssignmentConstraints(lhsType, + argExpr); if (Args[i] != argExpr) // The expression was converted. Args[i] = argExpr; // Make sure we store the converted expression. - SourceLocation l = argExpr->getLocStart(); - - // Decode the result (notice that AST's are still created for extensions). - const char *Kind = "sending"; - switch (result) { - case Compatible: - break; - case PointerFromInt: - case IntFromPointer: - Diag(l, diag::ext_typecheck_convert_pointer_int, - lhsType.getAsString(), rhsType.getAsString(), Kind, - argExpr->getSourceRange()); - break; - case IncompatiblePointer: - Diag(l, diag::ext_typecheck_convert_incompatible_pointer, - lhsType.getAsString(), rhsType.getAsString(), Kind, - argExpr->getSourceRange()); - break; - case FunctionVoidPointer: - Diag(l, diag::ext_typecheck_convert_pointer_void_func, - lhsType.getAsString(), rhsType.getAsString(), Kind, - argExpr->getSourceRange()); - break; - case CompatiblePointerDiscardsQualifiers: - Diag(l, diag::ext_typecheck_convert_discards_qualifiers, - lhsType.getAsString(), rhsType.getAsString(), Kind, - argExpr->getSourceRange()); - break; - case Incompatible: - Diag(l, diag::err_typecheck_convert_incompatible, - lhsType.getAsString(), rhsType.getAsString(), Kind, - argExpr->getSourceRange()); - anyIncompatibleArgs = true; - } + + anyIncompatibleArgs |= + DiagnoseAssignmentResult(Result, argExpr->getLocStart(), lhsType, rhsType, + argExpr, "sending"); } return anyIncompatibleArgs; } diff --git a/Sema/SemaStmt.cpp b/Sema/SemaStmt.cpp index 6b60bd0274..a983036b99 100644 --- a/Sema/SemaStmt.cpp +++ b/Sema/SemaStmt.cpp @@ -616,10 +616,10 @@ Sema::ActOnBreakStmt(SourceLocation BreakLoc, Scope *CurScope) { Action::StmtResult Sema::ActOnReturnStmt(SourceLocation ReturnLoc, ExprTy *rex) { Expr *RetValExp = static_cast<Expr *>(rex); - QualType lhsType = CurFunctionDecl ? CurFunctionDecl->getResultType() : - CurMethodDecl->getResultType(); + QualType FnRetType = CurFunctionDecl ? CurFunctionDecl->getResultType() : + CurMethodDecl->getResultType(); - if (lhsType->isVoidType()) { + if (FnRetType->isVoidType()) { if (RetValExp) // C99 6.8.6.4p1 (ext_ since GCC warns) Diag(ReturnLoc, diag::ext_return_has_expr, (CurFunctionDecl ? CurFunctionDecl->getIdentifier()->getName() : @@ -639,51 +639,18 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, ExprTy *rex) { } } // we have a non-void function with an expression, continue checking - QualType rhsType = RetValExp->getType(); + QualType RetValType = RetValExp->getType(); // C99 6.8.6.4p3(136): The return statement is not an assignment. The // overlap restriction of subclause 6.5.16.1 does not apply to the case of // function return. - AssignmentCheckResult result = CheckSingleAssignmentConstraints(lhsType, - RetValExp); - - // decode the result (notice that extensions still return a type). - switch (result) { - case Compatible: - break; - case Incompatible: - Diag(ReturnLoc, diag::err_typecheck_return_incompatible, - lhsType.getAsString(), rhsType.getAsString(), - RetValExp->getSourceRange()); - break; - case PointerFromInt: - Diag(ReturnLoc, diag::ext_typecheck_return_pointer_int, - lhsType.getAsString(), rhsType.getAsString(), - RetValExp->getSourceRange()); - break; - case IntFromPointer: - Diag(ReturnLoc, diag::ext_typecheck_return_pointer_int, - lhsType.getAsString(), rhsType.getAsString(), - RetValExp->getSourceRange()); - break; - case FunctionVoidPointer: - Diag(ReturnLoc, diag::ext_typecheck_return_pointer_void_func, - lhsType.getAsString(), rhsType.getAsString(), - RetValExp->getSourceRange()); - break; - case IncompatiblePointer: - Diag(ReturnLoc, diag::ext_typecheck_return_incompatible_pointer, - lhsType.getAsString(), rhsType.getAsString(), - RetValExp->getSourceRange()); - break; - case CompatiblePointerDiscardsQualifiers: - Diag(ReturnLoc, diag::ext_typecheck_return_discards_qualifiers, - lhsType.getAsString(), rhsType.getAsString(), - RetValExp->getSourceRange()); - break; - } + AssignConvertType ConvTy = CheckSingleAssignmentConstraints(FnRetType, + RetValExp); + if (DiagnoseAssignmentResult(ConvTy, ReturnLoc, FnRetType, + RetValType, RetValExp, "returning")) + return true; - if (RetValExp) CheckReturnStackAddr(RetValExp, lhsType, ReturnLoc); + if (RetValExp) CheckReturnStackAddr(RetValExp, FnRetType, ReturnLoc); return new ReturnStmt(ReturnLoc, (Expr*)RetValExp); } diff --git a/include/clang/Basic/DiagnosticKinds.def b/include/clang/Basic/DiagnosticKinds.def index e07245659e..891d9317e0 100644 --- a/include/clang/Basic/DiagnosticKinds.def +++ b/include/clang/Basic/DiagnosticKinds.def @@ -764,6 +764,7 @@ DIAG(ext_typecheck_comparison_of_distinct_pointers, WARNING, DIAG(err_typecheck_assign_const, ERROR, "read-only variable is not assignable") +// assignment related diagnostics (also for argument passing, returning, etc). DIAG(err_typecheck_convert_incompatible, ERROR, "incompatible type %2 '%1', expected '%0'") DIAG(ext_typecheck_convert_pointer_int, EXTENSION, @@ -771,47 +772,9 @@ DIAG(ext_typecheck_convert_pointer_int, EXTENSION, DIAG(ext_typecheck_convert_pointer_void_func, EXTENSION, "%2 '%1' converts between void* and function pointer, expected '%0'") DIAG(ext_typecheck_convert_incompatible_pointer, EXTENSION, - "incompatible pointer types %d '%1', expected '%0'") + "incompatible pointer types %2 '%1', expected '%0'") DIAG(ext_typecheck_convert_discards_qualifiers, EXTENSION, - "%d '%1' discards qualifiers, expected '%0'") - - - -DIAG(err_typecheck_return_incompatible, ERROR, - "incompatible type returning '%1', expected '%0'") -DIAG(ext_typecheck_return_pointer_int, EXTENSION, - "incompatible type returning '%1', expected '%0'") -DIAG(ext_typecheck_return_pointer_void_func, EXTENSION, - "returning '%1' to from function expecting '%0' converts between void*" - " and function pointer") -DIAG(ext_typecheck_return_incompatible_pointer, EXTENSION, - "incompatible pointer types returning '%1', expected '%0'") -DIAG(ext_typecheck_return_discards_qualifiers, EXTENSION, - "returning '%1' from function expecting '%0' discards qualifiers") - -DIAG(err_typecheck_assign_incompatible, ERROR, - "incompatible types assigning '%1' to '%0'") -DIAG(ext_typecheck_assign_pointer_int, WARNING, - "incompatible types assigning '%1' to '%0'") -DIAG(ext_typecheck_assign_incompatible_pointer, WARNING, - "incompatible pointer types assigning '%1' to '%0'") -DIAG(ext_typecheck_assign_discards_qualifiers, WARNING, - "assigning '%1' to '%0' discards qualifiers") -DIAG(ext_typecheck_assign_pointer_void_func, EXTENSION, - "assigning '%1' to '%0' converts between void* and function pointer") - -DIAG(err_typecheck_passing_incompatible, ERROR, - "incompatible types passing '%0' to function expecting '%1'") -DIAG(ext_typecheck_passing_incompatible_pointer, WARNING, - "incompatible pointer types passing '%0' to function expecting '%1'") -DIAG(ext_typecheck_passing_pointer_int, WARNING, - "incompatible types passing '%1' to function expecting '%0'") -DIAG(ext_typecheck_passing_pointer_void_func, EXTENSION, - "passing '%1' to function expecting '%0' converts between void*" - " and function pointer") -DIAG(ext_typecheck_passing_discards_qualifiers, WARNING, - "passing '%0' to '%1' discards qualifiers") - + "%2 '%1' discards qualifiers, expected '%0'") DIAG(err_typecheck_array_not_modifiable_lvalue, ERROR, "array type '%0' is not assignable") diff --git a/test/Parser/builtin_types_compatible.c b/test/Parser/builtin_types_compatible.c index b8207841a4..925c7ea50a 100644 --- a/test/Parser/builtin_types_compatible.c +++ b/test/Parser/builtin_types_compatible.c @@ -35,7 +35,7 @@ static void test() struct xx { int a; } x, y; c = __builtin_choose_expr(a+3-7, b, x); // expected-error{{'__builtin_choose_expr' requires a constant expression}} - c = __builtin_choose_expr(0, b, x); // expected-error{{incompatible types assigning 'struct xx' to 'int'}} + c = __builtin_choose_expr(0, b, x); // expected-error{{incompatible type assigning 'struct xx', expected 'int'}} c = __builtin_choose_expr(5+3-7, b, x); y = __builtin_choose_expr(4+3-7, b, x); diff --git a/test/Parser/implicit-casts.c b/test/Parser/implicit-casts.c index a07155eea4..3d055263bc 100644 --- a/test/Parser/implicit-casts.c +++ b/test/Parser/implicit-casts.c @@ -1,4 +1,4 @@ -// RUN: clang -fsyntax-only -verify %s +// RUN: clang -fsyntax-only -verify -pedantic %s _Complex double X; void test1(int c) { X = 5; @@ -14,7 +14,7 @@ void test2() { } int test3() { int a[2]; - a[0] = test3; // expected-warning{{incompatible types assigning 'int (void)' to 'int'}} + a[0] = test3; // expected-warning{{incompatible pointer/int conversion assigning 'int (void)', expected 'int'}} } short x; void test4(char c) { x += c; } int y; void test5(char c) { y += c; } diff --git a/test/Parser/typeof.c b/test/Parser/typeof.c index 6c4e79cd16..3ea277559e 100644 --- a/test/Parser/typeof.c +++ b/test/Parser/typeof.c @@ -16,8 +16,4 @@ static void test() { const typeof (*pi) aConstInt; int xx; int *i; - i = aci; // expected-warning{{incompatible types assigning 'typeof(int const)' to 'int *'}} - i = anInt; // expected-warning{{incompatible types assigning 'typeof(TInt)' to 'int *'}} - i = aConstInt; // expected-warning{{incompatible types assigning 'typeof(*pi) const' to 'int *'}} - i = xx; // expected-warning{{incompatible types assigning 'int' to 'int *'}} } diff --git a/test/Sema/argument-checking.m b/test/Sema/argument-checking.m index 57ab14f1ff..cd84171ee7 100644 --- a/test/Sema/argument-checking.m +++ b/test/Sema/argument-checking.m @@ -16,8 +16,8 @@ void test() { id obj = [Test alloc]; struct S sInst; - charStarFunc(1); // expected-warning {{incompatible types passing 'int' to function expecting 'char *'}} - charFunc("abc"); // expected-warning {{incompatible types passing 'char *' to function expecting 'char'}} + charStarFunc(1); // expected-warning {{incompatible pointer/int conversion passing 'int', expected 'char *'}} + charFunc("abc"); // expected-warning {{incompatible pointer/int conversion passing 'char *', expected 'char'}} [obj charStarMeth:1]; // expected-warning {{incompatible pointer/int conversion sending 'int'}} [obj structMeth:1]; // expected-error {{incompatible type sending 'int'}} diff --git a/test/Sema/array-constraint.c b/test/Sema/array-constraint.c index f281df1aff..df79681d06 100644 --- a/test/Sema/array-constraint.c +++ b/ |