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

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


Author: snaroff
Date: Wed Jul 11 11:44:29 2007
New Revision: 39445

URL: http://llvm.org/viewvc/llvm-project?rev=39445&view=rev
Log:
Bug #:
Submitted by:
Reviewed by:
- Completed Expr::isConstantExpr() and Expr::isIntegerConstantExpr().
- Completed Sema::ParseUnaryOp(), it lacked support for sizeof/alignof.
- Added Sema::CheckSizeOfAlignOfOperand(), used by ParseUnaryOp/ParseSizeOfAlignOfTypeExpr.
- Fixed a couple bugs in CheckRelationalOperands/CheckEqualityOperands (make sure extensions aren't treated as errors).
- Changed a bunch of predicates (in BinaryOperator/UnaryOperator) to member functions (the static members weren't being used).
- Added UnaryOperator::isIncrementDecrementOp/isSizeOfAlignOfOp.

Modified:
    cfe/cfe/trunk/AST/Expr.cpp
    cfe/cfe/trunk/AST/Sema.h
    cfe/cfe/trunk/AST/SemaExpr.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=39445&r1=39444&r2=39445&view=diff

==============================================================================
--- cfe/cfe/trunk/AST/Expr.cpp (original)
+++ cfe/cfe/trunk/AST/Expr.cpp Wed Jul 11 11:44:29 2007
@@ -185,17 +185,51 @@
   case DeclRefExprClass:
     return isa<EnumConstantDecl>(cast<DeclRefExpr>(this)->getDecl());
   case UnaryOperatorClass:
-    return cast<UnaryOperator>(this)->getSubExpr()->isConstantExpr();
+    const UnaryOperator *uop = cast<UnaryOperator>(this);
+    if (uop->isIncrementDecrementOp()) // C99 6.6p3
+      return false;
+    // C99 6.5.3.4p2: otherwise, the operand is *not* evaluated and the result
+    // is an integer constant. This effective ignores any subexpression that
+    // isn't actually a constant expression (what an odd language:-)
+    if (uop->isSizeOfAlignOfOp())
+      return true;
+    return uop->getSubExpr()->isConstantExpr();
   case BinaryOperatorClass:
-    return cast<BinaryOperator>(this)->getLHS()->isConstantExpr() &&
-           cast<BinaryOperator>(this)->getRHS()->isConstantExpr();
+    const BinaryOperator *bop = cast<BinaryOperator>(this);
+    // C99 6.6p3: shall not contain assignment, increment/decrement,
+    // function call, or comma operators, *except* when they are contained
+    // within a subexpression that is not evaluated. 
+    if (bop->isAssignmentOp() || bop->getOpcode() == BinaryOperator::Comma)
+      return false;
+    return bop->getLHS()->isConstantExpr() && bop->getRHS()->isConstantExpr();
   case ParenExprClass:
     return cast<ParenExpr>(this)->getSubExpr()->isConstantExpr();
-  case CastExprClass:
-    return cast<CastExpr>(this)->getSubExpr()->isConstantExpr();
+  case CastExprClass: 
+    const CastExpr *castExpr = cast<CastExpr>(this);    
+    // C99 6.6p6: shall only convert arithmetic types to integer types.
+    if (!castExpr->getSubExpr()->getType()->isArithmeticType())
+      return false;
+    if (!castExpr->getDestType()->isIntegerType())
+      return false;      
+    // allow floating constants that are the immediate operands of casts.
+    if (castExpr->getSubExpr()->isConstantExpr() ||
+        isa<FloatingLiteral>(castExpr->getSubExpr()))
+      return true;
+    return false;
   case SizeOfAlignOfTypeExprClass:
-    return cast<SizeOfAlignOfTypeExpr>(this)->getArgumentType()
-                                            ->isConstantSizeType();
+    const SizeOfAlignOfTypeExpr *sizeExpr = cast<SizeOfAlignOfTypeExpr>(this);
+    if (sizeExpr->isSizeOf())
+      return sizeExpr->getArgumentType()->isConstantSizeType();
+    return true; // alignof will always evaluate to a constant
+  case ConditionalOperatorClass:
+    // GCC currently ignores any subexpression that isn't evaluated.
+    // GCC currently considers the following legal: "1 ? 7 : printf("xx")"
+    // EDG still flags this as an error (which is great, since this predicate
+    // can do it's job *without* evaluating the expression).
+    const ConditionalOperator *condExpr = cast<ConditionalOperator>(this);
+    return condExpr->getCond()->isConstantExpr() &&
+           condExpr->getLHS()->isConstantExpr() &&
+           condExpr->getRHS()->isConstantExpr();
   default: 
     return false;
   }
@@ -209,17 +243,52 @@
   case DeclRefExprClass:
     return isa<EnumConstantDecl>(cast<DeclRefExpr>(this)->getDecl());
   case UnaryOperatorClass:
-    return cast<UnaryOperator>(this)->getSubExpr()->isIntegerConstantExpr();
+    const UnaryOperator *uop = cast<UnaryOperator>(this);
+    if (uop->isIncrementDecrementOp()) // C99 6.6p3
+      return false;
+    // C99 6.5.3.4p2: otherwise, the operand is *not* evaluated and the result
+    // is an integer constant. This effective ignores any subexpression that
+    // isn't actually a constant expression (what an odd language:-)
+    if (uop->isSizeOfAlignOfOp())
+      return true;
+    return uop->getSubExpr()->isIntegerConstantExpr();
   case BinaryOperatorClass:
-    return cast<BinaryOperator>(this)->getLHS()->isIntegerConstantExpr() &&
-           cast<BinaryOperator>(this)->getRHS()->isIntegerConstantExpr();
+    const BinaryOperator *bop = cast<BinaryOperator>(this);
+    // C99 6.6p3: shall not contain assignment, increment/decrement,
+    // function call, or comma operators, *except* when they are contained
+    // within a subexpression that is not evaluated. 
+    if (bop->isAssignmentOp() || bop->getOpcode() == BinaryOperator::Comma)
+      return false;
+    return bop->getLHS()->isIntegerConstantExpr() &&
+           bop->getRHS()->isIntegerConstantExpr();
   case ParenExprClass:
     return cast<ParenExpr>(this)->getSubExpr()->isIntegerConstantExpr();
-  case CastExprClass:
-    return cast<CastExpr>(this)->getSubExpr()->isIntegerConstantExpr();
+  case CastExprClass: 
+    const CastExpr *castExpr = cast<CastExpr>(this);    
+    // C99 6.6p6: shall only convert arithmetic types to integer types.
+    if (!castExpr->getSubExpr()->getType()->isArithmeticType())
+      return false;
+    if (!castExpr->getDestType()->isIntegerType())
+      return false;      
+    // allow floating constants that are the immediate operands of casts.
+    if (castExpr->getSubExpr()->isIntegerConstantExpr() ||
+        isa<FloatingLiteral>(castExpr->getSubExpr()))
+      return true;
+    return false;
   case SizeOfAlignOfTypeExprClass:
-    return cast<SizeOfAlignOfTypeExpr>(this)->getArgumentType()
-                                            ->isConstantSizeType();
+    const SizeOfAlignOfTypeExpr *sizeExpr = cast<SizeOfAlignOfTypeExpr>(this);
+    if (sizeExpr->isSizeOf())
+      return sizeExpr->getArgumentType()->isConstantSizeType();
+    return true; // alignof will always evaluate to a constant
+  case ConditionalOperatorClass:
+    // GCC currently ignores any subexpression that isn't evaluated.
+    // GCC currently considers the following legal: "1 ? 7 : printf("xx")"
+    // EDG still flags this as an error (which is great, since this predicate
+    // can do it's job *without* evaluating the expression).
+    const ConditionalOperator *condExpr = cast<ConditionalOperator>(this);
+    return condExpr->getCond()->isIntegerConstantExpr() &&
+           condExpr->getLHS()->isIntegerConstantExpr() &&
+           condExpr->getRHS()->isIntegerConstantExpr();
   default: 
     return false;
   }

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

==============================================================================
--- cfe/cfe/trunk/AST/Sema.h (original)
+++ cfe/cfe/trunk/AST/Sema.h Wed Jul 11 11:44:29 2007
@@ -282,6 +282,8 @@
     Expr *op, SourceLocation loc);
   QualType CheckIndirectionOperand( // C99 6.5.3.2
     Expr *op, SourceLocation loc);
+  QualType CheckSizeOfAlignOfOperand( // C99 6.5.3.4
+    QualType type, SourceLocation loc, bool isSizeof);
     
   // C99: 6.7.5p3: Used by ParseDeclarator/ParseField to make sure we have
   // a constant expression of type int with a value greater than zero.

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

==============================================================================
--- cfe/cfe/trunk/AST/SemaExpr.cpp (original)
+++ cfe/cfe/trunk/AST/SemaExpr.cpp Wed Jul 11 11:44:29 2007
@@ -170,6 +170,25 @@
   return e;
 }
 
+QualType Sema::CheckSizeOfAlignOfOperand(QualType exprType, 
+                                         SourceLocation OpLoc, bool isSizeof) {
+  // C99 6.5.3.4p1:
+  if (isa<FunctionType>(exprType) && isSizeof)
+    // alignof(function) is allowed.
+    Diag(OpLoc, diag::ext_sizeof_function_type);
+  else if (exprType->isVoidType())
+    Diag(OpLoc, diag::ext_sizeof_void_type, isSizeof ? "sizeof" : "__alignof");
+  else if (exprType->isIncompleteType()) {
+    std::string TypeName;
+    exprType->getAsString(TypeName);
+    Diag(OpLoc, isSizeof ? diag::err_sizeof_incomplete_type : 
+                           diag::err_alignof_incomplete_type, TypeName);
+    return QualType(); // error
+  }
+  // C99 6.5.3.4p4: the type (an unsigned integer type) is size_t.
+  return Context.getSizeType();
+}
+
 Action::ExprResult Sema::
 ParseSizeOfAlignOfTypeExpr(SourceLocation OpLoc, bool isSizeof, 
                            SourceLocation LParenLoc, TypeTy *Ty,
@@ -180,21 +199,11 @@
   // Verify that this is a valid expression.
   QualType ArgTy = QualType::getFromOpaquePtr(Ty);
   
-  if (isa<FunctionType>(ArgTy) && isSizeof) {
-    // alignof(function) is allowed.
-    Diag(OpLoc, diag::ext_sizeof_function_type);
-    return new IntegerLiteral(1, Context.IntTy);
-  } else if (ArgTy->isVoidType()) {
-    Diag(OpLoc, diag::ext_sizeof_void_type, isSizeof ? "sizeof" : "__alignof");
-  } else if (ArgTy->isIncompleteType()) {
-    std::string TypeName;
-    ArgTy->getAsString(TypeName);
-    Diag(OpLoc, isSizeof ? diag::err_sizeof_incomplete_type : 
-         diag::err_alignof_incomplete_type, TypeName);
-    return new IntegerLiteral(0, Context.IntTy);
-  }
-  // C99 6.5.3.4p4: the type (an unsigned integer type) is size_t.
-  return new SizeOfAlignOfTypeExpr(isSizeof, ArgTy, Context.getSizeType());
+  QualType resultType = CheckSizeOfAlignOfOperand(ArgTy, OpLoc, isSizeof);
+
+  if (resultType.isNull())
+    return true;
+  return new SizeOfAlignOfTypeExpr(isSizeof, ArgTy, resultType);
 }
 
 
@@ -624,10 +633,11 @@
   if (lType->isPointerType() &&  rType->isPointerType())
     return Context.IntTy;
 
-  if (lType->isIntegerType() || rType->isIntegerType()) // GCC extension.
+  if (lType->isIntegerType() || rType->isIntegerType()) { // GCC extension.
     Diag(loc, diag::ext_typecheck_comparison_of_pointer_integer);
-  else
-    Diag(loc, diag::err_typecheck_invalid_operands);
+    return Context.IntTy;
+  }
+  Diag(loc, diag::err_typecheck_invalid_operands);
   return QualType();
 }
 
@@ -641,10 +651,11 @@
   if (lType->isPointerType() &&  rType->isPointerType())
     return Context.IntTy;
     
-  if (lType->isIntegerType() || rType->isIntegerType()) // GCC extension.
+  if (lType->isIntegerType() || rType->isIntegerType()) { // GCC extension.
     Diag(loc, diag::ext_typecheck_comparison_of_pointer_integer);
-  else
-    Diag(loc, diag::err_typecheck_invalid_operands);
+    return Context.IntTy;
+  }
+  Diag(loc, diag::err_typecheck_invalid_operands);
   return QualType();
 }
 
@@ -1014,8 +1025,13 @@
       return Diag(OpLoc, diag::err_typecheck_unary_expr, resultType);
     break;
   case UnaryOperator::SizeOf:
+    resultType = CheckSizeOfAlignOfOperand(((Expr *)Input)->getType(), OpLoc,
+                                           true);
+    break;
   case UnaryOperator::AlignOf:
-    assert(0 && "need to implement type checking for sizeof/alignof");
+    resultType = CheckSizeOfAlignOfOperand(((Expr *)Input)->getType(), OpLoc,
+                                           false);
+    break;
   }
   if (resultType.isNull())
     return true;

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

==============================================================================
--- cfe/cfe/trunk/Sema/Sema.h (original)
+++ cfe/cfe/trunk/Sema/Sema.h Wed Jul 11 11:44:29 2007
@@ -282,6 +282,8 @@
     Expr *op, SourceLocation loc);
   QualType CheckIndirectionOperand( // C99 6.5.3.2
     Expr *op, SourceLocation loc);
+  QualType CheckSizeOfAlignOfOperand( // C99 6.5.3.4
+    QualType type, SourceLocation loc, bool isSizeof);
     
   // C99: 6.7.5p3: Used by ParseDeclarator/ParseField to make sure we have
   // a constant expression of type int with a value greater than zero.

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

==============================================================================
--- cfe/cfe/trunk/Sema/SemaExpr.cpp (original)
+++ cfe/cfe/trunk/Sema/SemaExpr.cpp Wed Jul 11 11:44:29 2007
@@ -170,6 +170,25 @@
   return e;
 }
 
+QualType Sema::CheckSizeOfAlignOfOperand(QualType exprType, 
+                                         SourceLocation OpLoc, bool isSizeof) {
+  // C99 6.5.3.4p1:
+  if (isa<FunctionType>(exprType) && isSizeof)
+    // alignof(function) is allowed.
+    Diag(OpLoc, diag::ext_sizeof_function_type);
+  else if (exprType->isVoidType())
+    Diag(OpLoc, diag::ext_sizeof_void_type, isSizeof ? "sizeof" : "__alignof");
+  else if (exprType->isIncompleteType()) {
+    std::string TypeName;
+    exprType->getAsString(TypeName);
+    Diag(OpLoc, isSizeof ? diag::err_sizeof_incomplete_type : 
+                           diag::err_alignof_incomplete_type, TypeName);
+    return QualType(); // error
+  }
+  // C99 6.5.3.4p4: the type (an unsigned integer type) is size_t.
+  return Context.getSizeType();
+}
+
 Action::ExprResult Sema::
 ParseSizeOfAlignOfTypeExpr(SourceLocation OpLoc, bool isSizeof, 
                            SourceLocation LParenLoc, TypeTy *Ty,
@@ -180,21 +199,11 @@
   // Verify that this is a valid expression.
   QualType ArgTy = QualType::getFromOpaquePtr(Ty);
   
-  if (isa<FunctionType>(ArgTy) && isSizeof) {
-    // alignof(function) is allowed.
-    Diag(OpLoc, diag::ext_sizeof_function_type);
-    return new IntegerLiteral(1, Context.IntTy);
-  } else if (ArgTy->isVoidType()) {
-    Diag(OpLoc, diag::ext_sizeof_void_type, isSizeof ? "sizeof" : "__alignof");
-  } else if (ArgTy->isIncompleteType()) {
-    std::string TypeName;
-    ArgTy->getAsString(TypeName);
-    Diag(OpLoc, isSizeof ? diag::err_sizeof_incomplete_type : 
-         diag::err_alignof_incomplete_type, TypeName);
-    return new IntegerLiteral(0, Context.IntTy);
-  }
-  // C99 6.5.3.4p4: the type (an unsigned integer type) is size_t.
-  return new SizeOfAlignOfTypeExpr(isSizeof, ArgTy, Context.getSizeType());
+  QualType resultType = CheckSizeOfAlignOfOperand(ArgTy, OpLoc, isSizeof);
+
+  if (resultType.isNull())
+    return true;
+  return new SizeOfAlignOfTypeExpr(isSizeof, ArgTy, resultType);
 }
 
 
@@ -624,10 +633,11 @@
   if (lType->isPointerType() &&  rType->isPointerType())
     return Context.IntTy;
 
-  if (lType->isIntegerType() || rType->isIntegerType()) // GCC extension.
+  if (lType->isIntegerType() || rType->isIntegerType()) { // GCC extension.
     Diag(loc, diag::ext_typecheck_comparison_of_pointer_integer);
-  else
-    Diag(loc, diag::err_typecheck_invalid_operands);
+    return Context.IntTy;
+  }
+  Diag(loc, diag::err_typecheck_invalid_operands);
   return QualType();
 }
 
@@ -641,10 +651,11 @@
   if (lType->isPointerType() &&  rType->isPointerType())
     return Context.IntTy;
     
-  if (lType->isIntegerType() || rType->isIntegerType()) // GCC extension.
+  if (lType->isIntegerType() || rType->isIntegerType()) { // GCC extension.
     Diag(loc, diag::ext_typecheck_comparison_of_pointer_integer);
-  else
-    Diag(loc, diag::err_typecheck_invalid_operands);
+    return Context.IntTy;
+  }
+  Diag(loc, diag::err_typecheck_invalid_operands);
   return QualType();
 }
 
@@ -1014,8 +1025,13 @@
       return Diag(OpLoc, diag::err_typecheck_unary_expr, resultType);
     break;
   case UnaryOperator::SizeOf:
+    resultType = CheckSizeOfAlignOfOperand(((Expr *)Input)->getType(), OpLoc,
+                                           true);
+    break;
   case UnaryOperator::AlignOf:
-    assert(0 && "need to implement type checking for sizeof/alignof");
+    resultType = CheckSizeOfAlignOfOperand(((Expr *)Input)->getType(), OpLoc,
+                                           false);
+    break;
   }
   if (resultType.isNull())
     return true;

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=39445&r1=39444&r2=39445&view=diff

==============================================================================
--- cfe/cfe/trunk/include/clang/AST/Expr.h (original)
+++ cfe/cfe/trunk/include/clang/AST/Expr.h Wed Jul 11 11:44:29 2007
@@ -203,6 +203,8 @@
   Expr *getSubExpr() const { return Val; }
   
   bool isPostfix() const { return isPostfix(Opc); }
+  bool isIncrementDecrementOp() const { return Opc>=PostInc && Opc<=PreDec; }
+  bool isSizeOfAlignOfOp() const { return Opc == SizeOf || Opc == AlignOf; }
   
   /// getDecl - a recursive routine that derives the base decl for an
   /// expression. For example, it will return the declaration for "s" from
@@ -374,14 +376,14 @@
   static const char *getOpcodeStr(Opcode Op);
 
   /// predicates to categorize the respective opcodes.
-  static bool isMultiplicativeOp(Opcode Op) { return Op >= Mul && Op <= Rem; }
-  static bool isAdditiveOp(Opcode Op) { return Op == Add || Op == Sub; }
-  static bool isShiftOp(Opcode Op) { return Op == Shl || Op == Shr; }
-  static bool isBitwiseOp(Opcode Op) { return Op >= And && Op <= Or; }
-  static bool isRelationalOp(Opcode Op) { return Op >= LT && Op <= GE; }
-  static bool isEqualityOp(Opcode Op) { return Op == EQ || Op == NE; }
-  static bool isLogicalOp(Opcode Op) { return Op == LAnd || Op == LOr; }
-  static bool isAssignmentOp(Opcode Op) { return Op >= Assign && Op<=OrAssign; }
+  bool isMultiplicativeOp() const { return Opc >= Mul && Opc <= Rem; }
+  bool isAdditiveOp() const { return Opc == Add || Opc == Sub; }
+  bool isShiftOp() const { return Opc == Shl || Opc == Shr; }
+  bool isBitwiseOp() const { return Opc >= And && Opc <= Or; }
+  bool isRelationalOp() const { return Opc >= LT && Opc <= GE; }
+  bool isEqualityOp() const { return Opc == EQ || Opc == NE; }
+  bool isLogicalOp() const { return Opc == LAnd || Opc == LOr; }
+  bool isAssignmentOp() const { return Opc >= Assign && Opc <= OrAssign; }
   
   Opcode getOpcode() const { return Opc; }
   Expr *getLHS() const { return LHS; }
@@ -406,9 +408,9 @@
   ConditionalOperator(Expr *cond, Expr *lhs, Expr *rhs, QualType t)
     : Expr(ConditionalOperatorClass, t), Cond(cond), LHS(lhs), RHS(rhs) {}
 
-  Expr *getCond() { return Cond; }
-  Expr *getLHS() { return LHS; }
-  Expr *getRHS() { return RHS; }
+  Expr *getCond() const { return Cond; }
+  Expr *getLHS() const { return LHS; }
+  Expr *getRHS() const { return RHS; }
   
   virtual void visit(StmtVisitor &Visitor);
   static bool classof(const Stmt *T) { 





More information about the cfe-commits mailing list