[cfe-commits] r39435 - in /cfe/cfe/trunk: AST/Expr.cpp AST/Sema.cpp AST/Sema.h AST/SemaExpr.cpp Sema/Sema.cpp Sema/Sema.h Sema/SemaExpr.cpp include/clang/AST/Expr.h

Steve Naroff snaroff at apple.com
Wed Jul 11 09:44:22 PDT 2007


Author: snaroff
Date: Wed Jul 11 11:44:21 2007
New Revision: 39435

URL: http://llvm.org/viewvc/llvm-project?rev=39435&view=rev
Log:
Bug #:
Submitted by:
Reviewed by:
- Unified CheckSimpleAssignmentOperands/CheckCompoundAssignmentOperands
into one function, named CheckAssignmentOperands. One less function to maintain.
- Converted the unary check functions (ParseUnaryOp and friends) to have
the same API as their binary counterparts.
- Implemented CheckIndirectionOperand (was stubbed). While testing, noticed
that Expr::isModifiableLvalue was incomplete (fixed and referenced draft).
- Added constantOne instance variable to Sema.
- Removed CheckArithmeticOperand (the code was so simple that it is now
part of ParseUnaryOp). The name wasn't great anyway:-)

Modified:
    cfe/cfe/trunk/AST/Expr.cpp
    cfe/cfe/trunk/AST/Sema.cpp
    cfe/cfe/trunk/AST/Sema.h
    cfe/cfe/trunk/AST/SemaExpr.cpp
    cfe/cfe/trunk/Sema/Sema.cpp
    cfe/cfe/trunk/Sema/Sema.h
    cfe/cfe/trunk/Sema/SemaExpr.cpp
    cfe/cfe/trunk/include/clang/AST/Expr.h

Modified: cfe/cfe/trunk/AST/Expr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/AST/Expr.cpp?rev=39435&r1=39434&r2=39435&view=diff

==============================================================================
--- cfe/cfe/trunk/AST/Expr.cpp (original)
+++ cfe/cfe/trunk/AST/Expr.cpp Wed Jul 11 11:44:21 2007
@@ -124,7 +124,7 @@
 ///  - (e), where e must be an lvalue
 ///  - e.name, where e must be an lvalue
 ///  - e->name
-///  - *e
+///  - *e, the type of e cannot be a function type
 ///  - string-constant
 ///
 bool Expr::isModifiableLvalue() {
@@ -146,7 +146,8 @@
     return m->getBase()->isModifiableLvalue(); // make sure "." is an lvalue
   case UnaryOperatorClass:
     const UnaryOperator *u = cast<UnaryOperator>(this);
-    return u->getOpcode() == UnaryOperator::Deref;
+    return u->getOpcode() == UnaryOperator::Deref &&
+           u->getType().isModifiableLvalue(); // C99 6.5.3.2p4
   case ParenExprClass:
     return cast<ParenExpr>(this)->getSubExpr()->isModifiableLvalue();
   default: 

Modified: cfe/cfe/trunk/AST/Sema.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/AST/Sema.cpp?rev=39435&r1=39434&r2=39435&view=diff

==============================================================================
--- cfe/cfe/trunk/AST/Sema.cpp (original)
+++ cfe/cfe/trunk/AST/Sema.cpp Wed Jul 11 11:44:21 2007
@@ -20,6 +20,7 @@
 
 Sema::Sema(Preprocessor &pp, ASTContext &ctxt, std::vector<Decl*> &prevInGroup)
   : PP(pp), Context(ctxt), CurFunctionDecl(0), LastInGroupList(prevInGroup) {
+  constantOne = new IntegerLiteral(1, ctxt.IntTy);
 }
 
 //===----------------------------------------------------------------------===//

Modified: cfe/cfe/trunk/AST/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/AST/Sema.h?rev=39435&r1=39434&r2=39435&view=diff

==============================================================================
--- cfe/cfe/trunk/AST/Sema.h (original)
+++ cfe/cfe/trunk/AST/Sema.h Wed Jul 11 11:44:21 2007
@@ -32,6 +32,7 @@
   class LangOptions;
   class DeclaratorChunk;
   class LexerToken;
+  class IntegerLiteral;
   
 /// Sema - This implements semantic analysis and AST building for C.
 class Sema : public Action {
@@ -48,6 +49,9 @@
   /// all but the last decl will be entered into this.  This is used by the
   /// ASTStreamer.
   std::vector<Decl*> &LastInGroupList;
+  
+  /// Constant for "1"
+  IntegerLiteral *constantOne;
 public:
   Sema(Preprocessor &pp, ASTContext &ctxt, std::vector<Decl*> &prevInGroup);
   
@@ -261,20 +265,21 @@
     Expr *lex, Expr *rex, SourceLocation OpLoc); 
   inline QualType CheckLogicalOperands( // C99 6.5.[13,14]
     Expr *lex, Expr *rex, SourceLocation OpLoc);
-  inline QualType CheckSimpleAssignmentOperands( // C99 6.5.16.1
-    Expr *lex, Expr *rex, SourceLocation OpLoc);
-  inline QualType CheckCompoundAssignmentOperands( // C99 6.5.16.2
-    Expr *lex, QualType, SourceLocation OpLoc);
+  // CheckAssignmentOperands is used for both simple and compound assignment.
+  // For simple assignment, pass both expressions and a null converted type.
+  // For compound assignment, pass both expressions and the converted type.
+  inline QualType CheckAssignmentOperands( // C99 6.5.16.[1,2]
+    Expr *lex, Expr *rex, SourceLocation OpLoc, QualType convertedType);
   inline QualType CheckCommaOperands( // C99 6.5.17
     Expr *lex, Expr *rex, SourceLocation OpLoc);
   
   /// type checking unary operators (subroutines of ParseUnaryOp).
   /// The unsigned arguments are really enums (UnaryOperator::Opcode)
-  ExprResult CheckIncrementDecrementOperand( // C99 6.5.3.1 
-    Expr *op, SourceLocation loc, unsigned OpCode);
-  ExprResult CheckAddressOfOperand( // C99 6.5.3.2
+  QualType CheckIncrementDecrementOperand( // C99 6.5.3.1 
+    Expr *op, SourceLocation loc);
+  QualType CheckAddressOfOperand( // C99 6.5.3.2
     Expr *op, SourceLocation loc);
-  ExprResult CheckIndirectionOperand( // C99 6.5.3.2
+  QualType CheckIndirectionOperand( // C99 6.5.3.2
     Expr *op, SourceLocation loc);
   ExprResult CheckArithmeticOperand( // C99 6.5.3.3
     Expr *op, SourceLocation OpLoc, unsigned OpCode);

Modified: cfe/cfe/trunk/AST/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/AST/SemaExpr.cpp?rev=39435&r1=39434&r2=39435&view=diff

==============================================================================
--- cfe/cfe/trunk/AST/SemaExpr.cpp (original)
+++ cfe/cfe/trunk/AST/SemaExpr.cpp Wed Jul 11 11:44:21 2007
@@ -170,44 +170,6 @@
   return e;
 }
 
-
-// Unary Operators.  'Tok' is the token for the operator.
-Action::ExprResult Sema::ParseUnaryOp(SourceLocation OpLoc, tok::TokenKind Op,
-                                      ExprTy *Input) {
-  UnaryOperator::Opcode Opc;
-  switch (Op) {
-  default: assert(0 && "Unknown unary op!");
-  case tok::plusplus:     Opc = UnaryOperator::PreInc; break;
-  case tok::minusminus:   Opc = UnaryOperator::PreDec; break;
-  case tok::amp:          Opc = UnaryOperator::AddrOf; break;
-  case tok::star:         Opc = UnaryOperator::Deref; break;
-  case tok::plus:         Opc = UnaryOperator::Plus; break;
-  case tok::minus:        Opc = UnaryOperator::Minus; break;
-  case tok::tilde:        Opc = UnaryOperator::Not; break;
-  case tok::exclaim:      Opc = UnaryOperator::LNot; break;
-  case tok::kw_sizeof:    Opc = UnaryOperator::SizeOf; break;
-  case tok::kw___alignof: Opc = UnaryOperator::AlignOf; break;
-  case tok::kw___real:    Opc = UnaryOperator::Real; break;
-  case tok::kw___imag:    Opc = UnaryOperator::Imag; break;
-  case tok::ampamp:       Opc = UnaryOperator::AddrLabel; break;
-  case tok::kw___extension__: 
-    return Input;
-    //Opc = UnaryOperator::Extension;
-    //break;
-  }
-  if (Opc == UnaryOperator::PreInc || Opc == UnaryOperator::PreDec)
-    return CheckIncrementDecrementOperand((Expr *)Input, OpLoc, Opc);
-  else if (Opc == UnaryOperator::AddrOf)
-    return CheckAddressOfOperand((Expr *)Input, OpLoc);
-  else if (Opc == UnaryOperator::Deref) 
-    return CheckIndirectionOperand((Expr *)Input, OpLoc);
-  else if (UnaryOperator::isArithmeticOp(Opc))
-    return CheckArithmeticOperand((Expr *)Input, OpLoc, Opc);
-  
-  // will go away when all cases are handled...
-  return new UnaryOperator((Expr *)Input, Opc, QualType());
-}
-
 Action::ExprResult Sema::
 ParseSizeOfAlignOfTypeExpr(SourceLocation OpLoc, bool isSizeof, 
                            SourceLocation LParenLoc, TypeTy *Ty,
@@ -245,7 +207,10 @@
   case tok::plusplus:   Opc = UnaryOperator::PostInc; break;
   case tok::minusminus: Opc = UnaryOperator::PostDec; break;
   }
-  return CheckIncrementDecrementOperand((Expr *)Input, OpLoc, Opc);
+  QualType result = CheckIncrementDecrementOperand((Expr *)Input, OpLoc);
+  if (result.isNull())
+    return true;
+  return new UnaryOperator((Expr *)Input, Opc, result);
 }
 
 Action::ExprResult Sema::
@@ -670,11 +635,11 @@
   return QualType();
 }
 
-inline QualType Sema::CheckSimpleAssignmentOperands( // C99 6.5.16.1
-  Expr *lex, Expr *rex, SourceLocation loc) 
+inline QualType Sema::CheckAssignmentOperands( // C99 6.5.16.1
+  Expr *lex, Expr *rex, SourceLocation loc, QualType compoundType) 
 {
   QualType lhsType = lex->getType();
-  QualType rhsType = rex->getType();
+  QualType rhsType = compoundType.isNull() ? rex->getType() : compoundType;
   
   // FIXME: consider hacking isModifiableLvalue to return an enum that
   // communicates why the expression/type wasn't a modifiableLvalue.
@@ -703,7 +668,7 @@
     return QualType();
   case PointerFromInt:
     // check for null pointer constant (C99 6.3.2.3p3)
-    if (!rex->isNullPointerConstant())
+    if (compoundType.isNull() && !rex->isNullPointerConstant())
       Diag(loc, diag::ext_typecheck_assign_pointer_from_int);
     return resType;
   case IntFromPointer:
@@ -716,79 +681,36 @@
   assert(0 && "should never get here");
 }
 
-inline QualType Sema::CheckCompoundAssignmentOperands( // C99 6.5.16.2
-  Expr *lex, QualType rhsType, SourceLocation loc) 
-{
-  QualType lhsType = lex->getType();
-  
-  // FIXME: consider hacking isModifiableLvalue to return an enum that
-  // communicates why the expression/type wasn't a modifiableLvalue.
-  
-  // this check is done first to give a more precise diagnostic.
-  if (lhsType.isConstQualified()) {
-    Diag(loc, diag::err_typecheck_assign_const);
-    return QualType();
-  }
-  if (!lex->isModifiableLvalue()) { // this includes checking for "const"
-    Diag(loc, diag::ext_typecheck_assign_non_lvalue);
-    return QualType();
-  }
-  if (lhsType == rhsType) // common case, fast path...
-    return lhsType;
-  
-  AssignmentConversionResult result;
-  QualType resType = UsualAssignmentConversions(lhsType, rhsType, result);
-
-  // decode the result (notice that extensions still return a type).
-  switch (result) {
-  case Compatible:
-    return resType;
-  case Incompatible:
-    Diag(loc, diag::err_typecheck_assign_incompatible);
-    return QualType();
-  case PointerFromInt:
-    Diag(loc, diag::ext_typecheck_assign_pointer_from_int);
-    return resType;
-  case IntFromPointer:
-    Diag(loc, diag::ext_typecheck_assign_int_from_pointer);
-    return resType;
-  case IncompatiblePointer:
-    Diag(loc, diag::ext_typecheck_assign_incompatible_pointer);
-    return resType;
-  }
-  assert(0 && "should never get here");
-}
-
 inline QualType Sema::CheckCommaOperands( // C99 6.5.17
   Expr *lex, Expr *rex, SourceLocation loc) 
 {
   return UsualUnaryConversion(rex->getType());
 }
 
-Action::ExprResult
-Sema::CheckIncrementDecrementOperand(Expr *op, SourceLocation OpLoc,
-                                               unsigned OpCode) {
-  QualType qType = op->getType();
-
-  assert(!qType.isNull() && "no type for increment/decrement expression");
-
-  QualType canonType = qType.getCanonicalType();
+QualType Sema::CheckIncrementDecrementOperand(Expr *op, SourceLocation OpLoc) {
+  QualType resType = UsualArithmeticConversions(op->getType(), 
+                                                constantOne->getType());
+  assert(!resType.isNull() && "no type for increment/decrement expression");
 
   // C99 6.5.2.4p1
-  if (const PointerType *pt = dyn_cast<PointerType>(canonType)) {
-    if (!pt->getPointeeType()->isObjectType()) // C99 6.5.2.4p2, 6.5.6p2
-      return Diag(OpLoc, diag::err_typecheck_arithmetic_incomplete_type, qType);    
-  } else if (!canonType->isRealType()) { 
+  if (const PointerType *pt = dyn_cast<PointerType>(resType)) {
+    if (!pt->getPointeeType()->isObjectType()) { // C99 6.5.2.4p2, 6.5.6p2
+      Diag(OpLoc, diag::err_typecheck_arithmetic_incomplete_type, resType);
+      return QualType();
+    }
+  } else if (!resType->isRealType()) { 
     // FIXME: Allow Complex as a GCC extension.
-    return Diag(OpLoc, diag::err_typecheck_illegal_increment_decrement, qType);    
+    Diag(OpLoc, diag::err_typecheck_illegal_increment_decrement, resType);
+    return QualType(); 
   }
   // At this point, we know we have a real or pointer type. As a result, the
   // following predicate is overkill (i.e. it will check for types we know we
   // don't have in this context). Nevertheless, we model the C99 spec closely.
-  if (!canonType.isModifiableLvalue())
-    return Diag(OpLoc, diag::err_typecheck_not_modifiable, qType);
-
-  return new UnaryOperator(op, (UOP)OpCode, qType);
+  if (!resType.isModifiableLvalue()) {
+    Diag(OpLoc, diag::err_typecheck_not_modifiable, resType);
+    return QualType();
+  }
+  return resType;
 }
 
 /// getPrimaryDeclaration - Helper function for CheckAddressOfOperand().
@@ -819,65 +741,42 @@
 /// object cannot be declared with storage class register or be a bit field.
 /// Note: The usual conversions are *not* applied to the operand of the & 
 /// operator, and its result is never an lvalue.
-Action::ExprResult
-Sema::CheckAddressOfOperand(Expr *op, SourceLocation OpLoc) {
+QualType Sema::CheckAddressOfOperand(Expr *op, SourceLocation OpLoc) {
   Decl *dcl = getPrimaryDeclaration(op);
   
   if (!op->isModifiableLvalue()) {
     if (dcl && isa<FunctionDecl>(dcl))
       ;  // C99 6.5.3.2p1: Allow function designators.
-    else
-      return Diag(OpLoc, diag::err_typecheck_invalid_lvalue_addrof);      
+    else {
+      Diag(OpLoc, diag::err_typecheck_invalid_lvalue_addrof);
+      return QualType();
+    }
   } else if (dcl) {
     // We have an lvalue with a decl. Make sure the decl is not declared 
     // with the register storage-class specifier.
     if (const VarDecl *vd = dyn_cast<VarDecl>(dcl)) {
-      if (vd->getStorageClass() == VarDecl::Register)
-        return Diag(OpLoc, diag::err_typecheck_address_of_register);
+      if (vd->getStorageClass() == VarDecl::Register) {
+        Diag(OpLoc, diag::err_typecheck_address_of_register);
+        return QualType();
+      }
     } else 
       assert(0 && "Unknown/unexpected decl type");
     
     // FIXME: add check for bitfields!
   }
   // If the operand has type "type", the result has type "pointer to type".
-  return new UnaryOperator(op, UnaryOperator::AddrOf, 
-                           Context.getPointerType(op->getType()));
+  return Context.getPointerType(op->getType());
 }
 
-Action::ExprResult
-Sema::CheckIndirectionOperand(Expr *op, SourceLocation OpLoc) {
-  QualType qType = op->getType();
-
-  assert(!qType.isNull() && "no type for * expression");
-
-  QualType canonType = qType.getCanonicalType();
-
-  // FIXME: add type checking and fix result type
+QualType Sema::CheckIndirectionOperand(Expr *op, SourceLocation OpLoc) {
+  QualType qType = UsualUnaryConversion(op->getType());
   
-  return new UnaryOperator(op, UnaryOperator::Deref, Context.IntTy);
-}
+  assert(!qType.isNull() && "no type for * expression");
 
-/// CheckArithmeticOperand - Check the arithmetic unary operators (C99 6.5.3.3).
-Action::ExprResult
-Sema::CheckArithmeticOperand(Expr *op, SourceLocation OpLoc, unsigned Opc) {
-  QualType resultType = UsualUnaryConversion(op->getType());
-  
-  switch (Opc) {
-  case UnaryOperator::Plus:
-  case UnaryOperator::Minus:
-    if (!resultType->isArithmeticType()) // C99 6.5.3.3p1
-      return Diag(OpLoc, diag::err_typecheck_unary_expr, resultType);
-    break;
-  case UnaryOperator::Not: // bitwise complement
-    if (!resultType->isIntegerType()) // C99 6.5.3.3p1
-      return Diag(OpLoc, diag::err_typecheck_unary_expr, resultType);
-    break;
-  case UnaryOperator::LNot: // logical negation
-    if (!resultType->isScalarType()) // C99 6.5.3.3p1
-      return Diag(OpLoc, diag::err_typecheck_unary_expr, resultType);
-    break;
-  }
-  return new UnaryOperator(op, (UOP)Opc, resultType);
+  if (PointerType *PT = dyn_cast<PointerType>(qType))
+    return PT->getPointeeType();
+  Diag(OpLoc, diag::err_typecheck_unary_expr, qType);
+  return QualType();
 }
 
 static inline BinaryOperator::Opcode ConvertTokenKindToBinaryOpcode(
@@ -919,6 +818,29 @@
   return Opc;
 }
 
+static inline UnaryOperator::Opcode ConvertTokenKindToUnaryOpcode(
+  tok::TokenKind Kind) {
+  UnaryOperator::Opcode Opc;
+  switch (Kind) {
+  default: assert(0 && "Unknown unary op!");
+  case tok::plusplus:     Opc = UnaryOperator::PreInc; break;
+  case tok::minusminus:   Opc = UnaryOperator::PreDec; break;
+  case tok::amp:          Opc = UnaryOperator::AddrOf; break;
+  case tok::star:         Opc = UnaryOperator::Deref; break;
+  case tok::plus:         Opc = UnaryOperator::Plus; break;
+  case tok::minus:        Opc = UnaryOperator::Minus; break;
+  case tok::tilde:        Opc = UnaryOperator::Not; break;
+  case tok::exclaim:      Opc = UnaryOperator::LNot; break;
+  case tok::kw_sizeof:    Opc = UnaryOperator::SizeOf; break;
+  case tok::kw___alignof: Opc = UnaryOperator::AlignOf; break;
+  case tok::kw___real:    Opc = UnaryOperator::Real; break;
+  case tok::kw___imag:    Opc = UnaryOperator::Imag; break;
+  case tok::ampamp:       Opc = UnaryOperator::AddrLabel; break;
+  // FIXME: case tok::kw___extension__: 
+  }
+  return Opc;
+}
+
 // Binary Operators.  'Tok' is the token for the operator.
 Action::ExprResult Sema::ParseBinOp(SourceLocation TokLoc, tok::TokenKind Kind,
                                     ExprTy *LHS, ExprTy *RHS) {
@@ -934,7 +856,7 @@
   default:
     assert(0 && "Unknown binary expr!");
   case BinaryOperator::Assign:
-    result = CheckSimpleAssignmentOperands(lhs, rhs, TokLoc);
+    result = CheckAssignmentOperands(lhs, rhs, TokLoc, QualType());
     break;
   case BinaryOperator::Mul: 
   case BinaryOperator::Div:
@@ -977,32 +899,32 @@
     result = CheckMultiplyDivideOperands(lhs, rhs, TokLoc);
     if (result.isNull())
       return true;
-    result = CheckCompoundAssignmentOperands(lhs, result, TokLoc);
+    result = CheckAssignmentOperands(lhs, rhs, TokLoc, result);
     break;
   case BinaryOperator::RemAssign:
     result = CheckRemainderOperands(lhs, rhs, TokLoc);
     if (result.isNull())
       return true;
-    result = CheckCompoundAssignmentOperands(lhs, result, TokLoc);
+    result = CheckAssignmentOperands(lhs, rhs, TokLoc, result);
     break;
   case BinaryOperator::AddAssign:
     result = CheckAdditionOperands(lhs, rhs, TokLoc);
     if (result.isNull())
       return true;
-    result = CheckCompoundAssignmentOperands(lhs, result, TokLoc);
+    result = CheckAssignmentOperands(lhs, rhs, TokLoc, result);
     break;
   case BinaryOperator::SubAssign:
     result = CheckSubtractionOperands(lhs, rhs, TokLoc);
     if (result.isNull())
       return true;
-    result = CheckCompoundAssignmentOperands(lhs, result, TokLoc);
+    result = CheckAssignmentOperands(lhs, rhs, TokLoc, result);
     break;
   case BinaryOperator::ShlAssign:
   case BinaryOperator::ShrAssign:
     result = CheckShiftOperands(lhs, rhs, TokLoc);
     if (result.isNull())
       return true;
-    result = CheckCompoundAssignmentOperands(lhs, result, TokLoc);
+    result = CheckAssignmentOperands(lhs, rhs, TokLoc, result);
     break;
   case BinaryOperator::AndAssign:
   case BinaryOperator::XorAssign:
@@ -1010,7 +932,7 @@
     result = CheckBitwiseOperands(lhs, rhs, TokLoc);
     if (result.isNull())
       return true;
-    result = CheckCompoundAssignmentOperands(lhs, result, TokLoc);
+    result = CheckAssignmentOperands(lhs, rhs, TokLoc, result);
     break;
   case BinaryOperator::Comma:
     result = CheckCommaOperands(lhs, rhs, TokLoc);
@@ -1021,3 +943,45 @@
   return new BinaryOperator(lhs, rhs, Opc, result);
 }
 
+// Unary Operators.  'Tok' is the token for the operator.
+Action::ExprResult Sema::ParseUnaryOp(SourceLocation OpLoc, tok::TokenKind Op,
+                                      ExprTy *Input) {
+  UnaryOperator::Opcode Opc = ConvertTokenKindToUnaryOpcode(Op);
+  QualType resultType;
+  switch (Opc) {
+  default:
+    assert(0 && "Unimplemented unary expr!");
+  case UnaryOperator::PreInc:
+  case UnaryOperator::PreDec:
+    resultType = CheckIncrementDecrementOperand((Expr *)Input, OpLoc);
+    break;
+  case UnaryOperator::AddrOf: 
+    resultType = CheckAddressOfOperand((Expr *)Input, OpLoc);
+    break;
+  case UnaryOperator::Deref: 
+    resultType = CheckIndirectionOperand((Expr *)Input, OpLoc);
+    break;
+  case UnaryOperator::Plus:
+  case UnaryOperator::Minus:
+    resultType = UsualUnaryConversion(((Expr *)Input)->getType());
+    if (!resultType->isArithmeticType())  // C99 6.5.3.3p1
+      return Diag(OpLoc, diag::err_typecheck_unary_expr, resultType);
+    break;
+  case UnaryOperator::Not: // bitwise complement
+    resultType = UsualUnaryConversion(((Expr *)Input)->getType());
+    if (!resultType->isIntegerType())  // C99 6.5.3.3p1
+      return Diag(OpLoc, diag::err_typecheck_unary_expr, resultType);
+    break;
+  case UnaryOperator::LNot: // logical negation
+    resultType = UsualUnaryConversion(((Expr *)Input)->getType());
+    if (!resultType->isScalarType()) // C99 6.5.3.3p1
+      return Diag(OpLoc, diag::err_typecheck_unary_expr, resultType);
+    break;
+  case UnaryOperator::SizeOf:
+  case UnaryOperator::AlignOf:
+    assert(0 && "need to implement type checking for sizeof/alignof");
+  }
+  if (resultType.isNull())
+    return true;
+  return new UnaryOperator((Expr *)Input, Opc, resultType);
+}

Modified: cfe/cfe/trunk/Sema/Sema.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/Sema/Sema.cpp?rev=39435&r1=39434&r2=39435&view=diff

==============================================================================
--- cfe/cfe/trunk/Sema/Sema.cpp (original)
+++ cfe/cfe/trunk/Sema/Sema.cpp Wed Jul 11 11:44:21 2007
@@ -20,6 +20,7 @@
 
 Sema::Sema(Preprocessor &pp, ASTContext &ctxt, std::vector<Decl*> &prevInGroup)
   : PP(pp), Context(ctxt), CurFunctionDecl(0), LastInGroupList(prevInGroup) {
+  constantOne = new IntegerLiteral(1, ctxt.IntTy);
 }
 
 //===----------------------------------------------------------------------===//

Modified: cfe/cfe/trunk/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/Sema/Sema.h?rev=39435&r1=39434&r2=39435&view=diff

==============================================================================
--- cfe/cfe/trunk/Sema/Sema.h (original)
+++ cfe/cfe/trunk/Sema/Sema.h Wed Jul 11 11:44:21 2007
@@ -32,6 +32,7 @@
   class LangOptions;
   class DeclaratorChunk;
   class LexerToken;
+  class IntegerLiteral;
   
 /// Sema - This implements semantic analysis and AST building for C.
 class Sema : public Action {
@@ -48,6 +49,9 @@
   /// all but the last decl will be entered into this.  This is used by the
   /// ASTStreamer.
   std::vector<Decl*> &LastInGroupList;
+  
+  /// Constant for "1"
+  IntegerLiteral *constantOne;
 public:
   Sema(Preprocessor &pp, ASTContext &ctxt, std::vector<Decl*> &prevInGroup);
   
@@ -261,20 +265,21 @@
     Expr *lex, Expr *rex, SourceLocation OpLoc); 
   inline QualType CheckLogicalOperands( // C99 6.5.[13,14]
     Expr *lex, Expr *rex, SourceLocation OpLoc);
-  inline QualType CheckSimpleAssignmentOperands( // C99 6.5.16.1
-    Expr *lex, Expr *rex, SourceLocation OpLoc);
-  inline QualType CheckCompoundAssignmentOperands( // C99 6.5.16.2
-    Expr *lex, QualType, SourceLocation OpLoc);
+  // CheckAssignmentOperands is used for both simple and compound assignment.
+  // For simple assignment, pass both expressions and a null converted type.
+  // For compound assignment, pass both expressions and the converted type.
+  inline QualType CheckAssignmentOperands( // C99 6.5.16.[1,2]
+    Expr *lex, Expr *rex, SourceLocation OpLoc, QualType convertedType);
   inline QualType CheckCommaOperands( // C99 6.5.17
     Expr *lex, Expr *rex, SourceLocation OpLoc);
   
   /// type checking unary operators (subroutines of ParseUnaryOp).
   /// The unsigned arguments are really enums (UnaryOperator::Opcode)
-  ExprResult CheckIncrementDecrementOperand( // C99 6.5.3.1 
-    Expr *op, SourceLocation loc, unsigned OpCode);
-  ExprResult CheckAddressOfOperand( // C99 6.5.3.2
+  QualType CheckIncrementDecrementOperand( // C99 6.5.3.1 
+    Expr *op, SourceLocation loc);
+  QualType CheckAddressOfOperand( // C99 6.5.3.2
     Expr *op, SourceLocation loc);
-  ExprResult CheckIndirectionOperand( // C99 6.5.3.2
+  QualType CheckIndirectionOperand( // C99 6.5.3.2
     Expr *op, SourceLocation loc);
   ExprResult CheckArithmeticOperand( // C99 6.5.3.3
     Expr *op, SourceLocation OpLoc, unsigned OpCode);

Modified: cfe/cfe/trunk/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/Sema/SemaExpr.cpp?rev=39435&r1=39434&r2=39435&view=diff

==============================================================================
--- cfe/cfe/trunk/Sema/SemaExpr.cpp (original)
+++ cfe/cfe/trunk/Sema/SemaExpr.cpp Wed Jul 11 11:44:21 2007
@@ -170,44 +170,6 @@
   return e;
 }
 
-
-// Unary Operators.  'Tok' is the token for the operator.
-Action::ExprResult Sema::ParseUnaryOp(SourceLocation OpLoc, tok::TokenKind Op,
-                                      ExprTy *Input) {
-  UnaryOperator::Opcode Opc;
-  switch (Op) {
-  default: assert(0 && "Unknown unary op!");
-  case tok::plusplus:     Opc = UnaryOperator::PreInc; break;
-  case tok::minusminus:   Opc = UnaryOperator::PreDec; break;
-  case tok::amp:          Opc = UnaryOperator::AddrOf; break;
-  case tok::star:         Opc = UnaryOperator::Deref; break;
-  case tok::plus:         Opc = UnaryOperator::Plus; break;
-  case tok::minus:        Opc = UnaryOperator::Minus; break;
-  case tok::tilde:        Opc = UnaryOperator::Not; break;
-  case tok::exclaim:      Opc = UnaryOperator::LNot; break;
-  case tok::kw_sizeof:    Opc = UnaryOperator::SizeOf; break;
-  case tok::kw___alignof: Opc = UnaryOperator::AlignOf; break;
-  case tok::kw___real:    Opc = UnaryOperator::Real; break;
-  case tok::kw___imag:    Opc = UnaryOperator::Imag; break;
-  case tok::ampamp:       Opc = UnaryOperator::AddrLabel; break;
-  case tok::kw___extension__: 
-    return Input;
-    //Opc = UnaryOperator::Extension;
-    //break;
-  }
-  if (Opc == UnaryOperator::PreInc || Opc == UnaryOperator::PreDec)
-    return CheckIncrementDecrementOperand((Expr *)Input, OpLoc, Opc);
-  else if (Opc == UnaryOperator::AddrOf)
-    return CheckAddressOfOperand((Expr *)Input, OpLoc);
-  else if (Opc == UnaryOperator::Deref) 
-    return CheckIndirectionOperand((Expr *)Input, OpLoc);
-  else if (UnaryOperator::isArithmeticOp(Opc))
-    return CheckArithmeticOperand((Expr *)Input, OpLoc, Opc);
-  
-  // will go away when all cases are handled...
-  return new UnaryOperator((Expr *)Input, Opc, QualType());
-}
-
 Action::ExprResult Sema::
 ParseSizeOfAlignOfTypeExpr(SourceLocation OpLoc, bool isSizeof, 
                            SourceLocation LParenLoc, TypeTy *Ty,
@@ -245,7 +207,10 @@
   case tok::plusplus:   Opc = UnaryOperator::PostInc; break;
   case tok::minusminus: Opc = UnaryOperator::PostDec; break;
   }
-  return CheckIncrementDecrementOperand((Expr *)Input, OpLoc, Opc);
+  QualType result = CheckIncrementDecrementOperand((Expr *)Input, OpLoc);
+  if (result.isNull())
+    return true;
+  return new UnaryOperator((Expr *)Input, Opc, result);
 }
 
 Action::ExprResult Sema::
@@ -670,11 +635,11 @@
   return QualType();
 }
 
-inline QualType Sema::CheckSimpleAssignmentOperands( // C99 6.5.16.1
-  Expr *lex, Expr *rex, SourceLocation loc) 
+inline QualType Sema::CheckAssignmentOperands( // C99 6.5.16.1
+  Expr *lex, Expr *rex, SourceLocation loc, QualType compoundType) 
 {
   QualType lhsType = lex->getType();
-  QualType rhsType = rex->getType();
+  QualType rhsType = compoundType.isNull() ? rex->getType() : compoundType;
   
   // FIXME: consider hacking isModifiableLvalue to return an enum that
   // communicates why the expression/type wasn't a modifiableLvalue.
@@ -703,7 +668,7 @@
     return QualType();
   case PointerFromInt:
     // check for null pointer constant (C99 6.3.2.3p3)
-    if (!rex->isNullPointerConstant())
+    if (compoundType.isNull() && !rex->isNullPointerConstant())
       Diag(loc, diag::ext_typecheck_assign_pointer_from_int);
     return resType;
   case IntFromPointer:
@@ -716,79 +681,36 @@
   assert(0 && "should never get here");
 }
 
-inline QualType Sema::CheckCompoundAssignmentOperands( // C99 6.5.16.2
-  Expr *lex, QualType rhsType, SourceLocation loc) 
-{
-  QualType lhsType = lex->getType();
-  
-  // FIXME: consider hacking isModifiableLvalue to return an enum that
-  // communicates why the expression/type wasn't a modifiableLvalue.
-  
-  // this check is done first to give a more precise diagnostic.
-  if (lhsType.isConstQualified()) {
-    Diag(loc, diag::err_typecheck_assign_const);
-    return QualType();
-  }
-  if (!lex->isModifiableLvalue()) { // this includes checking for "const"
-    Diag(loc, diag::ext_typecheck_assign_non_lvalue);
-    return QualType();
-  }
-  if (lhsType == rhsType) // common case, fast path...
-    return lhsType;
-  
-  AssignmentConversionResult result;
-  QualType resType = UsualAssignmentConversions(lhsType, rhsType, result);
-
-  // decode the result (notice that extensions still return a type).
-  switch (result) {
-  case Compatible:
-    return resType;
-  case Incompatible:
-    Diag(loc, diag::err_typecheck_assign_incompatible);
-    return QualType();
-  case PointerFromInt:
-    Diag(loc, diag::ext_typecheck_assign_pointer_from_int);
-    return resType;
-  case IntFromPointer:
-    Diag(loc, diag::ext_typecheck_assign_int_from_pointer);
-    return resType;
-  case IncompatiblePointer:
-    Diag(loc, diag::ext_typecheck_assign_incompatible_pointer);
-    return resType;
-  }
-  assert(0 && "should never get here");
-}
-
 inline QualType Sema::CheckCommaOperands( // C99 6.5.17
   Expr *lex, Expr *rex, SourceLocation loc) 
 {
   return UsualUnaryConversion(rex->getType());
 }
 
-Action::ExprResult
-Sema::CheckIncrementDecrementOperand(Expr *op, SourceLocation OpLoc,
-                                               unsigned OpCode) {
-  QualType qType = op->getType();
-
-  assert(!qType.isNull() && "no type for increment/decrement expression");
-
-  QualType canonType = qType.getCanonicalType();
+QualType Sema::CheckIncrementDecrementOperand(Expr *op, SourceLocation OpLoc) {
+  QualType resType = UsualArithmeticConversions(op->getType(), 
+                                                constantOne->getType());
+  assert(!resType.isNull() && "no type for increment/decrement expression");
 
   // C99 6.5.2.4p1
-  if (const PointerType *pt = dyn_cast<PointerType>(canonType)) {
-    if (!pt->getPointeeType()->isObjectType()) // C99 6.5.2.4p2, 6.5.6p2
-      return Diag(OpLoc, diag::err_typecheck_arithmetic_incomplete_type, qType);    
-  } else if (!canonType->isRealType()) { 
+  if (const PointerType *pt = dyn_cast<PointerType>(resType)) {
+    if (!pt->getPointeeType()->isObjectType()) { // C99 6.5.2.4p2, 6.5.6p2
+      Diag(OpLoc, diag::err_typecheck_arithmetic_incomplete_type, resType);
+      return QualType();
+    }
+  } else if (!resType->isRealType()) { 
     // FIXME: Allow Complex as a GCC extension.
-    return Diag(OpLoc, diag::err_typecheck_illegal_increment_decrement, qType);    
+    Diag(OpLoc, diag::err_typecheck_illegal_increment_decrement, resType);
+    return QualType(); 
   }
   // At this point, we know we have a real or pointer type. As a result, the
   // following predicate is overkill (i.e. it will check for types we know we
   // don't have in this context). Nevertheless, we model the C99 spec closely.
-  if (!canonType.isModifiableLvalue())
-    return Diag(OpLoc, diag::err_typecheck_not_modifiable, qType);
-
-  return new UnaryOperator(op, (UOP)OpCode, qType);
+  if (!resType.isModifiableLvalue()) {
+    Diag(OpLoc, diag::err_typecheck_not_modifiable, resType);
+    return QualType();
+  }
+  return resType;
 }
 
 /// getPrimaryDeclaration - Helper function for CheckAddressOfOperand().
@@ -819,65 +741,42 @@
 /// object cannot be declared with storage class register or be a bit field.
 /// Note: The usual conversions are *not* applied to the operand of the & 
 /// operator, and its result is never an lvalue.
-Action::ExprResult
-Sema::CheckAddressOfOperand(Expr *op, SourceLocation OpLoc) {
+QualType Sema::CheckAddressOfOperand(Expr *op, SourceLocation OpLoc) {
   Decl *dcl = getPrimaryDeclaration(op);
   
   if (!op->isModifiableLvalue()) {
     if (dcl && isa<FunctionDecl>(dcl))
       ;  // C99 6.5.3.2p1: Allow function designators.
-    else
-      return Diag(OpLoc, diag::err_typecheck_invalid_lvalue_addrof);      
+    else {
+      Diag(OpLoc, diag::err_typecheck_invalid_lvalue_addrof);
+      return QualType();
+    }
   } else if (dcl) {
     // We have an lvalue with a decl. Make sure the decl is not declared 
     // with the register storage-class specifier.
     if (const VarDecl *vd = dyn_cast<VarDecl>(dcl)) {
-      if (vd->getStorageClass() == VarDecl::Register)
-        return Diag(OpLoc, diag::err_typecheck_address_of_register);
+      if (vd->getStorageClass() == VarDecl::Register) {
+        Diag(OpLoc, diag::err_typecheck_address_of_register);
+        return QualType();
+      }
     } else 
       assert(0 && "Unknown/unexpected decl type");
     
     // FIXME: add check for bitfields!
   }
   // If the operand has type "type", the result has type "pointer to type".
-  return new UnaryOperator(op, UnaryOperator::AddrOf, 
-                           Context.getPointerType(op->getType()));
+  return Context.getPointerType(op->getType());
 }
 
-Action::ExprResult
-Sema::CheckIndirectionOperand(Expr *op, SourceLocation OpLoc) {
-  QualType qType = op->getType();
-
-  assert(!qType.isNull() && "no type for * expression");
-
-  QualType canonType = qType.getCanonicalType();
-
-  // FIXME: add type checking and fix result type
+QualType Sema::CheckIndirectionOperand(Expr *op, SourceLocation OpLoc) {
+  QualType qType = UsualUnaryConversion(op->getType());
   
-  return new UnaryOperator(op, UnaryOperator::Deref, Context.IntTy);
-}
+  assert(!qType.isNull() && "no type for * expression");
 
-/// CheckArithmeticOperand - Check the arithmetic unary operators (C99 6.5.3.3).
-Action::ExprResult
-Sema::CheckArithmeticOperand(Expr *op, SourceLocation OpLoc, unsigned Opc) {
-  QualType resultType = UsualUnaryConversion(op->getType());
-  
-  switch (Opc) {
-  case UnaryOperator::Plus:
-  case UnaryOperator::Minus:
-    if (!resultType->isArithmeticType()) // C99 6.5.3.3p1
-      return Diag(OpLoc, diag::err_typecheck_unary_expr, resultType);
-    break;
-  case UnaryOperator::Not: // bitwise complement
-    if (!resultType->isIntegerType()) // C99 6.5.3.3p1
-      return Diag(OpLoc, diag::err_typecheck_unary_expr, resultType);
-    break;
-  case UnaryOperator::LNot: // logical negation
-    if (!resultType->isScalarType()) // C99 6.5.3.3p1
-      return Diag(OpLoc, diag::err_typecheck_unary_expr, resultType);
-    break;
-  }
-  return new UnaryOperator(op, (UOP)Opc, resultType);
+  if (PointerType *PT = dyn_cast<PointerType>(qType))
+    return PT->getPointeeType();
+  Diag(OpLoc, diag::err_typecheck_unary_expr, qType);
+  return QualType();
 }
 
 static inline BinaryOperator::Opcode ConvertTokenKindToBinaryOpcode(
@@ -919,6 +818,29 @@
   return Opc;
 }
 
+static inline UnaryOperator::Opcode ConvertTokenKindToUnaryOpcode(
+  tok::TokenKind Kind) {
+  UnaryOperator::Opcode Opc;
+  switch (Kind) {
+  default: assert(0 && "Unknown unary op!");
+  case tok::plusplus:     Opc = UnaryOperator::PreInc; break;
+  case tok::minusminus:   Opc = UnaryOperator::PreDec; break;
+  case tok::amp:          Opc = UnaryOperator::AddrOf; break;
+  case tok::star:         Opc = UnaryOperator::Deref; break;
+  case tok::plus:         Opc = UnaryOperator::Plus; break;
+  case tok::minus:        Opc = UnaryOperator::Minus; break;
+  case tok::tilde:        Opc = UnaryOperator::Not; break;
+  case tok::exclaim:      Opc = UnaryOperator::LNot; break;
+  case tok::kw_sizeof:    Opc = UnaryOperator::SizeOf; break;
+  case tok::kw___alignof: Opc = UnaryOperator::AlignOf; break;
+  case tok::kw___real:    Opc = UnaryOperator::Real; break;
+  case tok::kw___imag:    Opc = UnaryOperator::Imag; break;
+  case tok::ampamp:       Opc = UnaryOperator::AddrLabel; break;
+  // FIXME: case tok::kw___extension__: 
+  }
+  return Opc;
+}
+
 // Binary Operators.  'Tok' is the token for the operator.
 Action::ExprResult Sema::ParseBinOp(SourceLocation TokLoc, tok::TokenKind Kind,
                                     ExprTy *LHS, ExprTy *RHS) {
@@ -934,7 +856,7 @@
   default:
     assert(0 && "Unknown binary expr!");
   case BinaryOperator::Assign:
-    result = CheckSimpleAssignmentOperands(lhs, rhs, TokLoc);
+    result = CheckAssignmentOperands(lhs, rhs, TokLoc, QualType());
     break;
   case BinaryOperator::Mul: 
   case BinaryOperator::Div:
@@ -977,32 +899,32 @@
     result = CheckMultiplyDivideOperands(lhs, rhs, TokLoc);
     if (result.isNull())
       return true;
-    result = CheckCompoundAssignmentOperands(lhs, result, TokLoc);
+    result = CheckAssignmentOperands(lhs, rhs, TokLoc, result);
     break;
   case BinaryOperator::RemAssign:
     result = CheckRemainderOperands(lhs, rhs, TokLoc);
     if (result.isNull())
       return true;
-    result = CheckCompoundAssignmentOperands(lhs, result, TokLoc);
+    result = CheckAssignmentOperands(lhs, rhs, TokLoc, result);
     break;
   case BinaryOperator::AddAssign:
     result = CheckAdditionOperands(lhs, rhs, TokLoc);
     if (result.isNull())
       return true;
-    result = CheckCompoundAssignmentOperands(lhs, result, TokLoc);
+    result = CheckAssignmentOperands(lhs, rhs, TokLoc, result);
     break;
   case BinaryOperator::SubAssign:
     result = CheckSubtractionOperands(lhs, rhs, TokLoc);
     if (result.isNull())
       return true;
-    result = CheckCompoundAssignmentOperands(lhs, result, TokLoc);
+    result = CheckAssignmentOperands(lhs, rhs, TokLoc, result);
     break;
   case BinaryOperator::ShlAssign:
   case BinaryOperator::ShrAssign:
     result = CheckShiftOperands(lhs, rhs, TokLoc);
     if (result.isNull())
       return true;
-    result = CheckCompoundAssignmentOperands(lhs, result, TokLoc);
+    result = CheckAssignmentOperands(lhs, rhs, TokLoc, result);
     break;
   case BinaryOperator::AndAssign:
   case BinaryOperator::XorAssign:
@@ -1010,7 +932,7 @@
     result = CheckBitwiseOperands(lhs, rhs, TokLoc);
     if (result.isNull())
       return true;
-    result = CheckCompoundAssignmentOperands(lhs, result, TokLoc);
+    result = CheckAssignmentOperands(lhs, rhs, TokLoc, result);
     break;
   case BinaryOperator::Comma:
     result = CheckCommaOperands(lhs, rhs, TokLoc);
@@ -1021,3 +943,45 @@
   return new BinaryOperator(lhs, rhs, Opc, result);
 }
 
+// Unary Operators.  'Tok' is the token for the operator.
+Action::ExprResult Sema::ParseUnaryOp(SourceLocation OpLoc, tok::TokenKind Op,
+                                      ExprTy *Input) {
+  UnaryOperator::Opcode Opc = ConvertTokenKindToUnaryOpcode(Op);
+  QualType resultType;
+  switch (Opc) {
+  default:
+    assert(0 && "Unimplemented unary expr!");
+  case UnaryOperator::PreInc:
+  case UnaryOperator::PreDec:
+    resultType = CheckIncrementDecrementOperand((Expr *)Input, OpLoc);
+    break;
+  case UnaryOperator::AddrOf: 
+    resultType = CheckAddressOfOperand((Expr *)Input, OpLoc);
+    break;
+  case UnaryOperator::Deref: 
+    resultType = CheckIndirectionOperand((Expr *)Input, OpLoc);
+    break;
+  case UnaryOperator::Plus:
+  case UnaryOperator::Minus:
+    resultType = UsualUnaryConversion(((Expr *)Input)->getType());
+    if (!resultType->isArithmeticType())  // C99 6.5.3.3p1
+      return Diag(OpLoc, diag::err_typecheck_unary_expr, resultType);
+    break;
+  case UnaryOperator::Not: // bitwise complement
+    resultType = UsualUnaryConversion(((Expr *)Input)->getType());
+    if (!resultType->isIntegerType())  // C99 6.5.3.3p1
+      return Diag(OpLoc, diag::err_typecheck_unary_expr, resultType);
+    break;
+  case UnaryOperator::LNot: // logical negation
+    resultType = UsualUnaryConversion(((Expr *)Input)->getType());
+    if (!resultType->isScalarType()) // C99 6.5.3.3p1
+      return Diag(OpLoc, diag::err_typecheck_unary_expr, resultType);
+    break;
+  case UnaryOperator::SizeOf:
+  case UnaryOperator::AlignOf:
+    assert(0 && "need to implement type checking for sizeof/alignof");
+  }
+  if (resultType.isNull())
+    return true;
+  return new UnaryOperator((Expr *)Input, Opc, resultType);
+}

Modified: cfe/cfe/trunk/include/clang/AST/Expr.h
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/include/clang/AST/Expr.h?rev=39435&r1=39434&r2=39435&view=diff

==============================================================================
--- cfe/cfe/trunk/include/clang/AST/Expr.h (original)
+++ cfe/cfe/trunk/include/clang/AST/Expr.h Wed Jul 11 11:44:21 2007
@@ -41,7 +41,7 @@
   ///  - (e), where e must be an lvalue
   ///  - e.name, where e must be an lvalue
   ///  - e->name
-  ///  - *e
+  ///  - *e, where e must be an lvalue (pointer-to-function isn't an lvalue)
   ///  - string-constant
   ///
   bool isModifiableLvalue();





More information about the cfe-commits mailing list