From 4b7ce03f5545dca23862ddf917a07a74ffea2f59 Mon Sep 17 00:00:00 2001 From: Steve Naroff Date: Fri, 20 Apr 2007 22:26:17 +0000 Subject: [PATCH] Bug #: Submitted by: Reviewed by: - Added Type::isPromotableIntegerType(). - The unary operators are now largely complete (Sema::ParseUnaryOp and friends). - Implemented ImplicitConversion hook (was a stub). llvm-svn: 39409 --- clang/AST/SemaExpr.cpp | 56 ++++++++++++++++--- clang/AST/Type.cpp | 18 ++++++ clang/Sema/SemaExpr.cpp | 56 ++++++++++++++++--- clang/include/clang/AST/ExprCXX.h | 2 - clang/include/clang/AST/Type.h | 3 + clang/include/clang/Basic/DiagnosticKinds.def | 2 + 6 files changed, 121 insertions(+), 16 deletions(-) diff --git a/clang/AST/SemaExpr.cpp b/clang/AST/SemaExpr.cpp index 69438fea5142..b2354d9dc209 100644 --- a/clang/AST/SemaExpr.cpp +++ b/clang/AST/SemaExpr.cpp @@ -180,9 +180,42 @@ Action::ExprResult Sema::ParseUnaryOp(SourceLocation OpLoc, tok::TokenKind Op, return CheckAddressOfOperand((Expr *)Input, OpLoc, Opc); else if (Opc == UnaryOperator::Deref) return CheckIndirectionOperand((Expr *)Input, OpLoc, Opc); - - // when all the check functions are written, this will go away... - return new UnaryOperator((Expr*)Input, Opc, QualType()); + else { + // handle the arithmetic unary operators (C99 6.5.3.3) + QualType opType = ImplicitConversion((Expr *)Input)->getType(); + assert(!opType.isNull() && "no type for arithmetic unary expression"); + QualType resultType = opType; + + switch (Opc) { + case UnaryOperator::Plus: + case UnaryOperator::Minus: + if (!opType->isArithmeticType()) // C99 6.5.3.3p1 + return Diag(OpLoc, diag::err_typecheck_unary_expr, opType); + + if (opType->isPromotableIntegerType()) // C99 6.5.3.3p2 + resultType = Context.IntTy; + break; + case UnaryOperator::Not: // bitwise complement + if (!opType->isIntegralType()) // C99 6.5.3.3p1 + return Diag(OpLoc, diag::err_typecheck_unary_expr, opType); + + if (opType->isPromotableIntegerType()) // C99 6.5.3.3p2 + resultType = Context.IntTy; + break; + case UnaryOperator::LNot: // logical negation + if (!opType->isScalarType()) // C99 6.5.3.3p1 + return Diag(OpLoc, diag::err_typecheck_unary_expr, opType); + + if (opType->isPromotableIntegerType()) // C99 6.5.3.3p2 + resultType = Context.IntTy; + break; + case UnaryOperator::SizeOf: // C99 6.5.3.4 TODO + break; + default: + break; + } + return new UnaryOperator((Expr*)Input, Opc, resultType); + } } Action::ExprResult Sema:: @@ -392,12 +425,21 @@ Action::ExprResult Sema::ParseConditionalOp(SourceLocation QuestionLoc, return new ConditionalOperator((Expr*)Cond, (Expr*)LHS, (Expr*)RHS); } +/// ImplicitConversion - Performs various conversions that are common to most +/// operators. At present, this routine only handles conversions that require +/// synthesizing an expression/type. Arithmetic type promotions are done locally, +/// since they don't require a new expression. Expr *Sema::ImplicitConversion(Expr *E) { -#if 0 QualType t = E->getType(); - if (t != 0) t.dump(); - else printf("no type for expr %s\n", E->getStmtClassName()); -#endif + assert(!t.isNull() && "no type for implicit conversion"); + + if (t->isFunctionType()) // C99 6.3.2.1p4 + return new UnaryOperator(E, UnaryOperator::AddrOf, Context.getPointerType(t)); + else if (t->isArrayType()) { // C99 6.3.2.1p3 + QualType elt = cast(t)->getElementType(); + QualType convertedType = Context.getPointerType(elt); + return new UnaryOperator(E, UnaryOperator::AddrOf, convertedType); + } return E; } diff --git a/clang/AST/Type.cpp b/clang/AST/Type.cpp index 7d6e1ebfebff..bbc2180766c9 100644 --- a/clang/AST/Type.cpp +++ b/clang/AST/Type.cpp @@ -199,6 +199,24 @@ bool Type::isLvalue() const { return false; } +bool Type::isPromotableIntegerType() const { + if (CanonicalType->getTypeClass() == Builtin) { + const BuiltinType *BT = static_cast(CanonicalType.getTypePtr()); + switch (BT->getKind()) { + case BuiltinType::Bool: + case BuiltinType::Char: + case BuiltinType::SChar: + case BuiltinType::UChar: + case BuiltinType::Short: + case BuiltinType::UShort: + return true; + default: + return false; + } + } + return false; +} + /// isModifiableLvalue - C99 6.3.2.1: an lvalue that does not have array type, /// does not have an incomplete type, does not have a const-qualified type, and /// if it is a structure or union, does not have any member (including, diff --git a/clang/Sema/SemaExpr.cpp b/clang/Sema/SemaExpr.cpp index 69438fea5142..b2354d9dc209 100644 --- a/clang/Sema/SemaExpr.cpp +++ b/clang/Sema/SemaExpr.cpp @@ -180,9 +180,42 @@ Action::ExprResult Sema::ParseUnaryOp(SourceLocation OpLoc, tok::TokenKind Op, return CheckAddressOfOperand((Expr *)Input, OpLoc, Opc); else if (Opc == UnaryOperator::Deref) return CheckIndirectionOperand((Expr *)Input, OpLoc, Opc); - - // when all the check functions are written, this will go away... - return new UnaryOperator((Expr*)Input, Opc, QualType()); + else { + // handle the arithmetic unary operators (C99 6.5.3.3) + QualType opType = ImplicitConversion((Expr *)Input)->getType(); + assert(!opType.isNull() && "no type for arithmetic unary expression"); + QualType resultType = opType; + + switch (Opc) { + case UnaryOperator::Plus: + case UnaryOperator::Minus: + if (!opType->isArithmeticType()) // C99 6.5.3.3p1 + return Diag(OpLoc, diag::err_typecheck_unary_expr, opType); + + if (opType->isPromotableIntegerType()) // C99 6.5.3.3p2 + resultType = Context.IntTy; + break; + case UnaryOperator::Not: // bitwise complement + if (!opType->isIntegralType()) // C99 6.5.3.3p1 + return Diag(OpLoc, diag::err_typecheck_unary_expr, opType); + + if (opType->isPromotableIntegerType()) // C99 6.5.3.3p2 + resultType = Context.IntTy; + break; + case UnaryOperator::LNot: // logical negation + if (!opType->isScalarType()) // C99 6.5.3.3p1 + return Diag(OpLoc, diag::err_typecheck_unary_expr, opType); + + if (opType->isPromotableIntegerType()) // C99 6.5.3.3p2 + resultType = Context.IntTy; + break; + case UnaryOperator::SizeOf: // C99 6.5.3.4 TODO + break; + default: + break; + } + return new UnaryOperator((Expr*)Input, Opc, resultType); + } } Action::ExprResult Sema:: @@ -392,12 +425,21 @@ Action::ExprResult Sema::ParseConditionalOp(SourceLocation QuestionLoc, return new ConditionalOperator((Expr*)Cond, (Expr*)LHS, (Expr*)RHS); } +/// ImplicitConversion - Performs various conversions that are common to most +/// operators. At present, this routine only handles conversions that require +/// synthesizing an expression/type. Arithmetic type promotions are done locally, +/// since they don't require a new expression. Expr *Sema::ImplicitConversion(Expr *E) { -#if 0 QualType t = E->getType(); - if (t != 0) t.dump(); - else printf("no type for expr %s\n", E->getStmtClassName()); -#endif + assert(!t.isNull() && "no type for implicit conversion"); + + if (t->isFunctionType()) // C99 6.3.2.1p4 + return new UnaryOperator(E, UnaryOperator::AddrOf, Context.getPointerType(t)); + else if (t->isArrayType()) { // C99 6.3.2.1p3 + QualType elt = cast(t)->getElementType(); + QualType convertedType = Context.getPointerType(elt); + return new UnaryOperator(E, UnaryOperator::AddrOf, convertedType); + } return E; } diff --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h index 37a9cb3bfa95..cdaf0075f750 100644 --- a/clang/include/clang/AST/ExprCXX.h +++ b/clang/include/clang/AST/ExprCXX.h @@ -51,8 +51,6 @@ namespace clang { CXXBoolLiteralExpr(bool val) : Expr(CXXBoolLiteralExprClass, QualType()), Value(val) {} - virtual Expr *getPrimaryExpr() { return this; } - virtual void visit(StmtVisitor &Visitor); }; diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h index 8b2987d01773..33f4085e0cf6 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -226,6 +226,9 @@ public: bool isAggregateType() const; // C99 6.2.5p21 (arrays, structures) bool isLvalue() const; // C99 6.3.2.1 + + /// Type Conversions/Promotions + bool isPromotableIntegerType() const; // C99 6.3.1.1p2 private: // this forces clients to use isModifiableLvalue on QualType, the class that // knows if the type is const. This predicate is a helper to QualType. diff --git a/clang/include/clang/Basic/DiagnosticKinds.def b/clang/include/clang/Basic/DiagnosticKinds.def index b32623856272..53ed67ca54c3 100644 --- a/clang/include/clang/Basic/DiagnosticKinds.def +++ b/clang/include/clang/Basic/DiagnosticKinds.def @@ -533,6 +533,8 @@ DIAG(err_typecheck_address_of_register, ERROR, "address of register variable requested") DIAG(err_typecheck_invalid_lvalue_addrof, ERROR, "invalid lvalue in address expression") +DIAG(err_typecheck_unary_expr, ERROR, + "invalid argument type to unary expression '%s'") // Statements. DIAG(err_continue_not_in_loop, ERROR,