[cfe-commits] r39370 - in /cfe/cfe/trunk: AST/Sema.h AST/SemaExpr.cpp Sema/Sema.h Sema/SemaExpr.cpp include/clang/AST/Type.h include/clang/Basic/DiagnosticKinds.def

Steve Naroff snaroff at apple.com
Wed Jul 11 09:43:42 PDT 2007


Author: snaroff
Date: Wed Jul 11 11:43:42 2007
New Revision: 39370

URL: http://llvm.org/viewvc/llvm-project?rev=39370&view=rev
Log:
Bug #:
Submitted by:
Reviewed by:
Incorporate feedback from Chris (on the last check-in).
- added a shared hook for pre/post ++/-- CheckIncrementDecrementOperand().
- handle invalid arithmetic on incomplete types (void *, struct foo *, where the
body isn't in scope). Added a diagnostic for this case.
- added some comments and C99 annotations.
- Sema.h now includes Expr.h. I'd prefer not to, however it doesn't break
any layering.

Modified:
    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/Type.h
    cfe/cfe/trunk/include/clang/Basic/DiagnosticKinds.def

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

==============================================================================
--- cfe/cfe/trunk/AST/Sema.h (original)
+++ cfe/cfe/trunk/AST/Sema.h Wed Jul 11 11:43:42 2007
@@ -16,6 +16,7 @@
 #define LLVM_CLANG_AST_SEMA_H
 
 #include "clang/Parse/Action.h"
+#include "clang/AST/Expr.h"
 #include <vector>
 #include <string>
 
@@ -24,7 +25,6 @@
   class ASTContext;
   class Preprocessor;
   class Decl;
-  class Expr;
   class VarDecl;
   class TypedefDecl;
   class FunctionDecl;
@@ -225,13 +225,18 @@
   Expr *ImplicitConversion(Expr *E); // C99 6.3
   
   /// type checking binary operators (subroutines of ParseBinOp).
-  void CheckMultiplicativeOperands(Expr *op1, Expr *op2); // C99 6.5.5
-  void CheckAdditiveOperands(Expr *op1, Expr *op2);       // C99 6.5.6
-  void CheckShiftOperands(Expr *op1, Expr *op2);          // C99 6.5.7
-  void CheckRelationalOperands(Expr *op1, Expr *op2);     // C99 6.5.8
-  void CheckEqualityOperands(Expr *op1, Expr *op2);       // C99 6.5.9
-  void CheckBitwiseOperands(Expr *op1, Expr *op2);        // C99 6.5.[10...12]
-  void CheckLogicalOperands(Expr *op1, Expr *op2);        // C99 6.5.[13,14]
+  /// the following "Check" methods will either return a well formed AST node
+  /// or will return true if the expressions didn't type check properly.
+  ExprResult CheckMultiplicativeOperands(Expr *op1, Expr *op2); // C99 6.5.5
+  ExprResult CheckAdditiveOperands(Expr *op1, Expr *op2);       // C99 6.5.6
+  ExprResult CheckShiftOperands(Expr *op1, Expr *op2);          // C99 6.5.7
+  ExprResult CheckRelationalOperands(Expr *op1, Expr *op2);     // C99 6.5.8
+  ExprResult CheckEqualityOperands(Expr *op1, Expr *op2);       // C99 6.5.9
+  ExprResult CheckBitwiseOperands(Expr *op1, Expr *op2);   // C99 6.5.[10...12]
+  ExprResult CheckLogicalOperands(Expr *op1, Expr *op2);   // C99 6.5.[13,14]
+  
+  ExprResult CheckIncrementDecrementOperand(Expr *op, SourceLocation loc,
+                                            UnaryOperator::Opcode Opc);
 };
 
 

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

==============================================================================
--- cfe/cfe/trunk/AST/SemaExpr.cpp (original)
+++ cfe/cfe/trunk/AST/SemaExpr.cpp Wed Jul 11 11:43:42 2007
@@ -173,22 +173,11 @@
     //Opc = UnaryOperator::Extension;
     //break;
   }
-  TypeRef type = ((Expr *)Input)->getTypeRef();
-
-  assert(!type.isNull() && "no type for prefix unary expression");
-
-  if (Opc == UnaryOperator::PreInc || Opc == UnaryOperator::PreDec) {
-    // C99 6.5.3.1: isRealType excludes complex (GCC allows complex).
-    if (!type->isRealType() && !type->isPointerType())
-      return Diag(OpLoc, diag::err_typecheck_illegal_increment_decrement, type);    
-
-    // 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 (!type.isModifiableLvalue())
-      return Diag(OpLoc, diag::err_typecheck_not_modifiable, type);
-  }
-  return new UnaryOperator((Expr*)Input, Opc, type);
+  if (Opc == UnaryOperator::PreInc || Opc == UnaryOperator::PreDec)
+    return CheckIncrementDecrementOperand((Expr *)Input, OpLoc, Opc);
+  
+  // when all the check functions are written, this will go away...
+  return new UnaryOperator((Expr*)Input, Opc, 0);
 }
 
 Action::ExprResult Sema::
@@ -228,21 +217,7 @@
   case tok::plusplus:   Opc = UnaryOperator::PostInc; break;
   case tok::minusminus: Opc = UnaryOperator::PostDec; break;
   }
-  TypeRef type = ((Expr *)Input)->getTypeRef();
-
-  assert(!type.isNull() && "no type for postfix unary expression");
-  
-  // C99 6.5.2.4: isRealType excludes complex (GCC allows complex).
-  if (!type->isRealType() && !type->isPointerType())
-    return Diag(OpLoc, diag::err_typecheck_illegal_increment_decrement, type);    
-
-  // 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 (!type.isModifiableLvalue())
-    return Diag(OpLoc, diag::err_typecheck_not_modifiable, type);
-    
-  return new UnaryOperator((Expr*)Input, Opc, type);
+  return CheckIncrementDecrementOperand((Expr *)Input, OpLoc, Opc);
 }
 
 Action::ExprResult Sema::
@@ -273,6 +248,7 @@
   if (!indexType->isIntegralType())
     return Diag(LLoc, diag::err_typecheck_subscript);
 
+  // FIXME: need to deal with const...
   TypeRef resultType;
   if (ArrayType *ary = dyn_cast<ArrayType>(baseType)) {
     resultType = ary->getElementType();
@@ -412,24 +388,54 @@
   return E;
 }
 
-void Sema::CheckMultiplicativeOperands(Expr *op1, Expr *op2) {
+Action::ExprResult Sema::CheckMultiplicativeOperands(Expr *op1, Expr *op2) {
+  return false;
+}
+
+Action::ExprResult Sema::CheckAdditiveOperands(Expr *op1, Expr *op2) {
+  return false;
 }
 
-void Sema::CheckAdditiveOperands(Expr *op1, Expr *op2) {
+Action::ExprResult Sema::CheckShiftOperands(Expr *op1, Expr *op2) {
+  return false;
 }
 
-void Sema::CheckShiftOperands(Expr *op1, Expr *op2) {
+Action::ExprResult Sema::CheckRelationalOperands(Expr *op1, Expr *op2) {
+  return false;
 }
 
-void Sema::CheckRelationalOperands(Expr *op1, Expr *op2) {
+Action::ExprResult Sema::CheckEqualityOperands(Expr *op1, Expr *op2) {
+  return false;
 }
 
-void Sema::CheckEqualityOperands(Expr *op1, Expr *op2) {
+Action::ExprResult Sema::CheckBitwiseOperands(Expr *op1, Expr *op2) {
+  return false;
 }
 
-void Sema::CheckBitwiseOperands(Expr *op1, Expr *op2) {
+Action::ExprResult Sema::CheckLogicalOperands(Expr *op1, Expr *op2) {
+  return false;
 }
 
-void Sema::CheckLogicalOperands(Expr *op1, Expr *op2) {
+Action::ExprResult
+Sema::CheckIncrementDecrementOperand(Expr *op, SourceLocation OpLoc,
+                                               UnaryOperator::Opcode OpCode) {
+  TypeRef type = op->getTypeRef();
+
+  assert(!type.isNull() && "no type for increment/decrement expression");
+  
+  if (const PointerType *pt = dyn_cast<PointerType>(type)) {
+    if (!pt->getPointeeType()->isObjectType()) // C99 6.5.6p2
+      return Diag(OpLoc, diag::err_typecheck_arithmetic_incomplete_type, type);    
+  } else if (!type->isRealType()) // C99 6.5.2.4: isRealType excludes complex.
+    // FIXME: Allow Complex as a GCC extension.
+    return Diag(OpLoc, diag::err_typecheck_illegal_increment_decrement, type);    
+
+  // 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 (!type.isModifiableLvalue())
+    return Diag(OpLoc, diag::err_typecheck_not_modifiable, type);
+
+  return new UnaryOperator(op, OpCode, type);
 }
 

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

==============================================================================
--- cfe/cfe/trunk/Sema/Sema.h (original)
+++ cfe/cfe/trunk/Sema/Sema.h Wed Jul 11 11:43:42 2007
@@ -16,6 +16,7 @@
 #define LLVM_CLANG_AST_SEMA_H
 
 #include "clang/Parse/Action.h"
+#include "clang/AST/Expr.h"
 #include <vector>
 #include <string>
 
@@ -24,7 +25,6 @@
   class ASTContext;
   class Preprocessor;
   class Decl;
-  class Expr;
   class VarDecl;
   class TypedefDecl;
   class FunctionDecl;
@@ -225,13 +225,18 @@
   Expr *ImplicitConversion(Expr *E); // C99 6.3
   
   /// type checking binary operators (subroutines of ParseBinOp).
-  void CheckMultiplicativeOperands(Expr *op1, Expr *op2); // C99 6.5.5
-  void CheckAdditiveOperands(Expr *op1, Expr *op2);       // C99 6.5.6
-  void CheckShiftOperands(Expr *op1, Expr *op2);          // C99 6.5.7
-  void CheckRelationalOperands(Expr *op1, Expr *op2);     // C99 6.5.8
-  void CheckEqualityOperands(Expr *op1, Expr *op2);       // C99 6.5.9
-  void CheckBitwiseOperands(Expr *op1, Expr *op2);        // C99 6.5.[10...12]
-  void CheckLogicalOperands(Expr *op1, Expr *op2);        // C99 6.5.[13,14]
+  /// the following "Check" methods will either return a well formed AST node
+  /// or will return true if the expressions didn't type check properly.
+  ExprResult CheckMultiplicativeOperands(Expr *op1, Expr *op2); // C99 6.5.5
+  ExprResult CheckAdditiveOperands(Expr *op1, Expr *op2);       // C99 6.5.6
+  ExprResult CheckShiftOperands(Expr *op1, Expr *op2);          // C99 6.5.7
+  ExprResult CheckRelationalOperands(Expr *op1, Expr *op2);     // C99 6.5.8
+  ExprResult CheckEqualityOperands(Expr *op1, Expr *op2);       // C99 6.5.9
+  ExprResult CheckBitwiseOperands(Expr *op1, Expr *op2);   // C99 6.5.[10...12]
+  ExprResult CheckLogicalOperands(Expr *op1, Expr *op2);   // C99 6.5.[13,14]
+  
+  ExprResult CheckIncrementDecrementOperand(Expr *op, SourceLocation loc,
+                                            UnaryOperator::Opcode Opc);
 };
 
 

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

==============================================================================
--- cfe/cfe/trunk/Sema/SemaExpr.cpp (original)
+++ cfe/cfe/trunk/Sema/SemaExpr.cpp Wed Jul 11 11:43:42 2007
@@ -173,22 +173,11 @@
     //Opc = UnaryOperator::Extension;
     //break;
   }
-  TypeRef type = ((Expr *)Input)->getTypeRef();
-
-  assert(!type.isNull() && "no type for prefix unary expression");
-
-  if (Opc == UnaryOperator::PreInc || Opc == UnaryOperator::PreDec) {
-    // C99 6.5.3.1: isRealType excludes complex (GCC allows complex).
-    if (!type->isRealType() && !type->isPointerType())
-      return Diag(OpLoc, diag::err_typecheck_illegal_increment_decrement, type);    
-
-    // 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 (!type.isModifiableLvalue())
-      return Diag(OpLoc, diag::err_typecheck_not_modifiable, type);
-  }
-  return new UnaryOperator((Expr*)Input, Opc, type);
+  if (Opc == UnaryOperator::PreInc || Opc == UnaryOperator::PreDec)
+    return CheckIncrementDecrementOperand((Expr *)Input, OpLoc, Opc);
+  
+  // when all the check functions are written, this will go away...
+  return new UnaryOperator((Expr*)Input, Opc, 0);
 }
 
 Action::ExprResult Sema::
@@ -228,21 +217,7 @@
   case tok::plusplus:   Opc = UnaryOperator::PostInc; break;
   case tok::minusminus: Opc = UnaryOperator::PostDec; break;
   }
-  TypeRef type = ((Expr *)Input)->getTypeRef();
-
-  assert(!type.isNull() && "no type for postfix unary expression");
-  
-  // C99 6.5.2.4: isRealType excludes complex (GCC allows complex).
-  if (!type->isRealType() && !type->isPointerType())
-    return Diag(OpLoc, diag::err_typecheck_illegal_increment_decrement, type);    
-
-  // 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 (!type.isModifiableLvalue())
-    return Diag(OpLoc, diag::err_typecheck_not_modifiable, type);
-    
-  return new UnaryOperator((Expr*)Input, Opc, type);
+  return CheckIncrementDecrementOperand((Expr *)Input, OpLoc, Opc);
 }
 
 Action::ExprResult Sema::
@@ -273,6 +248,7 @@
   if (!indexType->isIntegralType())
     return Diag(LLoc, diag::err_typecheck_subscript);
 
+  // FIXME: need to deal with const...
   TypeRef resultType;
   if (ArrayType *ary = dyn_cast<ArrayType>(baseType)) {
     resultType = ary->getElementType();
@@ -412,24 +388,54 @@
   return E;
 }
 
-void Sema::CheckMultiplicativeOperands(Expr *op1, Expr *op2) {
+Action::ExprResult Sema::CheckMultiplicativeOperands(Expr *op1, Expr *op2) {
+  return false;
+}
+
+Action::ExprResult Sema::CheckAdditiveOperands(Expr *op1, Expr *op2) {
+  return false;
 }
 
-void Sema::CheckAdditiveOperands(Expr *op1, Expr *op2) {
+Action::ExprResult Sema::CheckShiftOperands(Expr *op1, Expr *op2) {
+  return false;
 }
 
-void Sema::CheckShiftOperands(Expr *op1, Expr *op2) {
+Action::ExprResult Sema::CheckRelationalOperands(Expr *op1, Expr *op2) {
+  return false;
 }
 
-void Sema::CheckRelationalOperands(Expr *op1, Expr *op2) {
+Action::ExprResult Sema::CheckEqualityOperands(Expr *op1, Expr *op2) {
+  return false;
 }
 
-void Sema::CheckEqualityOperands(Expr *op1, Expr *op2) {
+Action::ExprResult Sema::CheckBitwiseOperands(Expr *op1, Expr *op2) {
+  return false;
 }
 
-void Sema::CheckBitwiseOperands(Expr *op1, Expr *op2) {
+Action::ExprResult Sema::CheckLogicalOperands(Expr *op1, Expr *op2) {
+  return false;
 }
 
-void Sema::CheckLogicalOperands(Expr *op1, Expr *op2) {
+Action::ExprResult
+Sema::CheckIncrementDecrementOperand(Expr *op, SourceLocation OpLoc,
+                                               UnaryOperator::Opcode OpCode) {
+  TypeRef type = op->getTypeRef();
+
+  assert(!type.isNull() && "no type for increment/decrement expression");
+  
+  if (const PointerType *pt = dyn_cast<PointerType>(type)) {
+    if (!pt->getPointeeType()->isObjectType()) // C99 6.5.6p2
+      return Diag(OpLoc, diag::err_typecheck_arithmetic_incomplete_type, type);    
+  } else if (!type->isRealType()) // C99 6.5.2.4: isRealType excludes complex.
+    // FIXME: Allow Complex as a GCC extension.
+    return Diag(OpLoc, diag::err_typecheck_illegal_increment_decrement, type);    
+
+  // 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 (!type.isModifiableLvalue())
+    return Diag(OpLoc, diag::err_typecheck_not_modifiable, type);
+
+  return new UnaryOperator(op, OpCode, type);
 }
 

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

==============================================================================
--- cfe/cfe/trunk/include/clang/AST/Type.h (original)
+++ cfe/cfe/trunk/include/clang/AST/Type.h Wed Jul 11 11:43:42 2007
@@ -117,6 +117,11 @@
   /// appropriate type qualifiers on it.
   inline TypeRef getCanonicalType() const;
 
+  /// isModifiableLvalue - C99 6.3.2.1p1: returns true if the type is 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 struct/union, does not 
+  /// have any member (including, recursively, any member or element of all
+  /// contained aggregates or unions) with a const-qualified type.
   bool isModifiableLvalue() const;
     
   void getAsString(std::string &S) const;
@@ -225,7 +230,7 @@
 private:
   // this forces clients to use isModifiableLvalue on TypeRef, the class that 
   // knows if the type is const. This predicate is a helper to TypeRef. 
-  bool isModifiableLvalue() const; // C99 6.3.2.1
+  bool isModifiableLvalue() const; // C99 6.3.2.1p1
   friend class TypeRef;
 public:
   virtual void getAsString(std::string &InnerString) const = 0;
@@ -471,7 +476,10 @@
   RecordDecl *getDecl() const {
     return reinterpret_cast<RecordDecl*>(TagType::getDecl());
   }
-  bool isModifiableLvalue() const { return true; } // FIXME
+  // FIXME: This predicate is a helper to TypeRef/Type. It needs to 
+  // recursively check all fields for const-ness. If any field is declared
+  // const, it needs to return false. 
+  bool isModifiableLvalue() const { return true; } 
   
   static bool classof(const Type *T);
   static bool classof(const RecordType *) { return true; }

Modified: cfe/cfe/trunk/include/clang/Basic/DiagnosticKinds.def
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/include/clang/Basic/DiagnosticKinds.def?rev=39370&r1=39369&r2=39370&view=diff

==============================================================================
--- cfe/cfe/trunk/include/clang/Basic/DiagnosticKinds.def (original)
+++ cfe/cfe/trunk/include/clang/Basic/DiagnosticKinds.def Wed Jul 11 11:43:42 2007
@@ -502,6 +502,8 @@
      "cannot modify value of type '%s'")
 DIAG(err_typecheck_not_modifiable, ERROR,
      "cannot modify read-only value of type '%s'")
+DIAG(err_typecheck_arithmetic_incomplete_type, ERROR,
+     "arithmetic on pointer to incomplete type '%s'")
 
 // Statements.
 DIAG(err_continue_not_in_loop, ERROR,





More information about the cfe-commits mailing list