From 6f49f5df03437b7b2f04775e1e20cdb72d0380b7 Mon Sep 17 00:00:00 2001 From: Steve Naroff Date: Tue, 29 May 2007 14:23:36 +0000 Subject: [PATCH] Bug #: Submitted by: Reviewed by: - Finished Sema::ParseReturnStmt(). Still need to tweak ranges. - Tweaked location for function arguments (they now point at the expression directly, no parens or commas). - Added InvalidOperands helper...was sick of looking at the same 3 lines in ~9 Check functions. - Added a few diags and moved a group of statement diags to the proper comment/category. llvm-svn: 39517 --- clang/Sema/Sema.h | 1 + clang/Sema/SemaExpr.cpp | 44 +++++++------------ clang/Sema/SemaStmt.cpp | 32 +++++++++----- clang/include/clang/Basic/DiagnosticKinds.def | 31 ++++++++----- 4 files changed, 57 insertions(+), 51 deletions(-) diff --git a/clang/Sema/Sema.h b/clang/Sema/Sema.h index cf929d29dd14..cc89a90c2206 100644 --- a/clang/Sema/Sema.h +++ b/clang/Sema/Sema.h @@ -275,6 +275,7 @@ private: /// or a null QualType (indicating an error diagnostic was issued). /// type checking binary operators (subroutines of ParseBinOp). + inline void InvalidOperands(SourceLocation l, Expr *lex, Expr *rex); inline QualType CheckMultiplyDivideOperands( // C99 6.5.5 Expr *lex, Expr *rex, SourceLocation OpLoc); inline QualType CheckRemainderOperands( // C99 6.5.5 diff --git a/clang/Sema/SemaExpr.cpp b/clang/Sema/SemaExpr.cpp index ef018c4270b5..d9136874c8b5 100644 --- a/clang/Sema/SemaExpr.cpp +++ b/clang/Sema/SemaExpr.cpp @@ -410,7 +410,7 @@ ParseCallExpr(ExprTy *Fn, SourceLocation LParenLoc, AssignmentConversionResult result; UsualAssignmentConversions(lhsType, rhsType, result); - SourceLocation l = (i == 0) ? LParenLoc : CommaLocs[i-1]; + SourceLocation l = argExpr->getLocStart(); // decode the result (notice that AST's are still created for extensions). // FIXME: decide to include/exclude the argument # (decided to remove @@ -707,6 +707,12 @@ QualType Sema::UsualAssignmentConversions(QualType lhsType, QualType rhsType, return QualType(); } +inline void Sema::InvalidOperands(SourceLocation loc, Expr *lex, Expr *rex) { + Diag(loc, diag::err_typecheck_invalid_operands, + lex->getType().getAsString(), rex->getType().getAsString(), + lex->getSourceRange(), rex->getSourceRange()); +} + inline QualType Sema::CheckMultiplyDivideOperands( Expr *lex, Expr *rex, SourceLocation loc) { @@ -714,9 +720,7 @@ inline QualType Sema::CheckMultiplyDivideOperands( if (resType->isArithmeticType()) return resType; - Diag(loc, diag::err_typecheck_invalid_operands, - lex->getType().getAsString(), rex->getType().getAsString(), - lex->getSourceRange(), rex->getSourceRange()); + InvalidOperands(loc, lex, rex); return QualType(); } @@ -727,9 +731,7 @@ inline QualType Sema::CheckRemainderOperands( if (resType->isIntegerType()) return resType; - Diag(loc, diag::err_typecheck_invalid_operands, - lex->getType().getAsString(), rex->getType().getAsString(), - lex->getSourceRange(), rex->getSourceRange()); + InvalidOperands(loc, lex, rex); return QualType(); } @@ -746,9 +748,7 @@ inline QualType Sema::CheckAdditionOperands( // C99 6.5.6 if ((lhsType->isPointerType() && rhsType->isIntegerType()) || (lhsType->isIntegerType() && rhsType->isPointerType())) return resType; - Diag(loc, diag::err_typecheck_invalid_operands, - lhsType.getAsString(), rhsType.getAsString(), - lex->getSourceRange(), rex->getSourceRange()); + InvalidOperands(loc, lex, rex); return QualType(); } @@ -764,9 +764,7 @@ inline QualType Sema::CheckSubtractionOperands( // C99 6.5.6 if ((lhsType->isPointerType() && rhsType->isIntegerType()) || (lhsType->isPointerType() && rhsType->isPointerType())) return resType; - Diag(loc, diag::err_typecheck_invalid_operands, - lhsType.getAsString(), rhsType.getAsString(), - lex->getSourceRange(), rex->getSourceRange()); + InvalidOperands(loc, lex, rex); return QualType(); } @@ -777,9 +775,7 @@ inline QualType Sema::CheckShiftOperands( // C99 6.5.7 if (resType->isIntegerType()) return resType; - Diag(loc, diag::err_typecheck_invalid_operands, - lex->getType().getAsString(), rex->getType().getAsString(), - lex->getSourceRange(), rex->getSourceRange()); + InvalidOperands(loc, lex, rex); return QualType(); } @@ -798,9 +794,7 @@ inline QualType Sema::CheckRelationalOperands( // C99 6.5.8 Diag(loc, diag::ext_typecheck_comparison_of_pointer_integer); return Context.IntTy; } - Diag(loc, diag::err_typecheck_invalid_operands, - lType.getAsString(), rType.getAsString(), - lex->getSourceRange(), rex->getSourceRange()); + InvalidOperands(loc, lex, rex); return QualType(); } @@ -818,9 +812,7 @@ inline QualType Sema::CheckEqualityOperands( // C99 6.5.9 Diag(loc, diag::ext_typecheck_comparison_of_pointer_integer); return Context.IntTy; } - Diag(loc, diag::err_typecheck_invalid_operands, - lType.getAsString(), rType.getAsString(), - lex->getSourceRange(), rex->getSourceRange()); + InvalidOperands(loc, lex, rex); return QualType(); } @@ -831,9 +823,7 @@ inline QualType Sema::CheckBitwiseOperands( if (resType->isIntegerType()) return resType; - Diag(loc, diag::err_typecheck_invalid_operands, - lex->getType().getAsString(), rex->getType().getAsString(), - lex->getSourceRange(), rex->getSourceRange()); + InvalidOperands(loc, lex, rex); return QualType(); } @@ -845,9 +835,7 @@ inline QualType Sema::CheckLogicalOperands( // C99 6.5.[13,14] if (lhsType->isScalarType() || rhsType->isScalarType()) return Context.IntTy; - Diag(loc, diag::err_typecheck_invalid_operands, - lex->getType().getAsString(), rex->getType().getAsString(), - lex->getSourceRange(), rex->getSourceRange()); + InvalidOperands(loc, lex, rex); return QualType(); } diff --git a/clang/Sema/SemaStmt.cpp b/clang/Sema/SemaStmt.cpp index 8d43533d79fe..7f9d471d890f 100644 --- a/clang/Sema/SemaStmt.cpp +++ b/clang/Sema/SemaStmt.cpp @@ -16,6 +16,8 @@ #include "clang/AST/Expr.h" #include "clang/Parse/Scope.h" #include "clang/Basic/Diagnostic.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Lex/IdentifierTable.h" using namespace llvm; using namespace clang; @@ -199,25 +201,33 @@ Sema::ParseBreakStmt(SourceLocation BreakLoc, Scope *CurScope) { Action::StmtResult Sema::ParseReturnStmt(SourceLocation ReturnLoc, ExprTy *RetValExp) { - // 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. QualType lhsType = CurFunctionDecl->getResultType(); - if (!RetValExp) - return new ReturnStmt((Expr*)RetValExp); - - // C99 6.8.6.4p1 if (lhsType->isVoidType()) { - // a void function may not return a value - // non-void function "voidFunc" should return a value + if (RetValExp) // C99 6.8.6.4p1 (ext_ since GCC warns) + Diag(ReturnLoc, diag::ext_return_has_expr, + CurFunctionDecl->getIdentifier()->getName(), + ((Expr *)RetValExp)->getSourceRange()); + return new ReturnStmt((Expr*)RetValExp); + } else { + if (!RetValExp) { + const char *funcName = CurFunctionDecl->getIdentifier()->getName(); + if (getLangOptions().C99) // C99 6.8.6.4p1 (ext_ since GCC warns) + Diag(ReturnLoc, diag::ext_return_missing_expr, funcName); + else // C90 6.6.6.4p4 + Diag(ReturnLoc, diag::warn_return_missing_expr, funcName); + return new ReturnStmt((Expr*)0); + } } - + // we have a non-void function with an expression, continue checking QualType rhsType = ((Expr *)RetValExp)->getType(); if (lhsType == rhsType) // common case, fast path... return new ReturnStmt((Expr*)RetValExp); - + + // 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. AssignmentConversionResult result; QualType resType = UsualAssignmentConversions(lhsType, rhsType, result); bool hadError = false; diff --git a/clang/include/clang/Basic/DiagnosticKinds.def b/clang/include/clang/Basic/DiagnosticKinds.def index ffd500efa60f..e0931d195145 100644 --- a/clang/include/clang/Basic/DiagnosticKinds.def +++ b/clang/include/clang/Basic/DiagnosticKinds.def @@ -594,6 +594,18 @@ DIAG(ext_typecheck_passing_pointer_from_int, EXTENSION, "passing argument %0 makes pointer from integer without a cast") DIAG(ext_typecheck_passing_discards_qualifiers, EXTENSION, "passing argument %0 discards qualifiers from pointer target type") +DIAG(err_typecheck_cond_expect_scalar, ERROR, + "used type '%0' where arithmetic or pointer type is required") +DIAG(err_typecheck_cond_incompatible_operands, ERROR, + "incompatible operand types ('%0' and '%1')") +DIAG(ext_typecheck_cond_incompatible_pointers, EXTENSION, + "pointer type mismatch ('%0' and '%1')") + +// Statements. +DIAG(err_continue_not_in_loop, ERROR, + "'continue' statement not in loop statement") +DIAG(err_break_not_in_loop_or_switch, ERROR, + "'break' statement not in loop or switch statement") DIAG(err_typecheck_return_incompatible, ERROR, "incompatible types in return ('%0' and '%1')") DIAG(ext_typecheck_return_int_from_pointer, EXTENSION, @@ -604,19 +616,14 @@ DIAG(ext_typecheck_return_incompatible_pointer, EXTENSION, "return from incompatible pointer type") DIAG(ext_typecheck_return_discards_qualifiers, EXTENSION, "return discards qualifiers from pointer target type") -DIAG(err_typecheck_cond_expect_scalar, ERROR, - "used type '%0' where arithmetic or pointer type is required") -DIAG(err_typecheck_cond_incompatible_operands, ERROR, - "incompatible operand types ('%0' and '%1')") -DIAG(ext_typecheck_cond_incompatible_pointers, EXTENSION, - "pointer type mismatch ('%0' and '%1')") DIAG(err_typecheck_statement_requires_scalar, ERROR, "statement requires expression of scalar type ('%0' invalid)") - -// Statements. -DIAG(err_continue_not_in_loop, ERROR, - "'continue' statement not in loop statement") -DIAG(err_break_not_in_loop_or_switch, ERROR, - "'break' statement not in loop or switch statement") + +DIAG(warn_return_missing_expr, WARNING, + "non-void function '%0' should return a value") +DIAG(ext_return_missing_expr, EXTENSION, + "non-void function '%0' should return a value") +DIAG(ext_return_has_expr, EXTENSION, + "void function '%0' should not return a value") #undef DIAG