[cfe-commits] r39408 - in /cfe/cfe/trunk: AST/Expr.cpp AST/Sema.h AST/SemaExpr.cpp Sema/Sema.h Sema/SemaExpr.cpp clang.xcodeproj/project.pbxproj include/clang/AST/Decl.h include/clang/AST/Expr.h include/clang/AST/ExprCXX.h include/clang/Basic/DiagnosticKinds.def

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


Author: snaroff
Date: Wed Jul 11 11:44:03 2007
New Revision: 39408

URL: http://llvm.org/viewvc/llvm-project?rev=39408&view=rev
Log:
Bug #:
Submitted by:
Reviewed by:
Continue working on type checking for unary operators. Added:

- Two 3 private functions to Sema: CheckAddressOfOperand(), CheckIndirectionOperand(),
and getDecl().
- Added Expr::isLvalue() - it was needed for CheckAddressOfOperand(). It will
also be needed for ++/-- and the assignment operators.
- Added a couple diagnostics for invalid lvalues (for & of).

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/clang.xcodeproj/project.pbxproj
    cfe/cfe/trunk/include/clang/AST/Decl.h
    cfe/cfe/trunk/include/clang/AST/Expr.h
    cfe/cfe/trunk/include/clang/AST/ExprCXX.h
    cfe/cfe/trunk/include/clang/Basic/DiagnosticKinds.def

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

==============================================================================
--- cfe/cfe/trunk/AST/Expr.cpp (original)
+++ cfe/cfe/trunk/AST/Expr.cpp Wed Jul 11 11:44:03 2007
@@ -117,3 +117,41 @@
   case Comma:     return ",";
   }
 }
+
+/// Expressions that can be lvalues:
+///  - name, where name must be a variable
+///  - e[i]
+///  - (e), where e must be an lvalue
+///  - e.name, where e must be an lvalue
+///  - e->name
+///  - *e
+///  - string-constant
+///
+bool Expr::isLvalue() {
+  switch (getStmtClass()) {
+  case StringLiteralClass:
+    return true;
+  case ArraySubscriptExprClass:
+    return true;
+  case DeclRefExprClass:
+    const DeclRefExpr *d = cast<DeclRefExpr>(this);
+	  if (isa<VarDecl>(d->getDecl()))
+      return true;
+    return false;
+  case MemberExprClass:
+    const MemberExpr *m = cast<MemberExpr>(this);
+    if (m->isArrow())
+      return true;
+    return m->getBase()->isLvalue(); // make sure "." is an lvalue
+  case UnaryOperatorClass:
+    const UnaryOperator *u = cast<UnaryOperator>(this);
+    if (u->getOpcode() == UnaryOperator::Deref)
+      return true;
+    return false;
+  case ParenExprClass:
+    const ParenExpr *pref = cast<ParenExpr>(this);
+    return pref->getSubExpr()->isLvalue();
+  default: 
+    return false;
+  }
+}

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

==============================================================================
--- cfe/cfe/trunk/AST/Sema.h (original)
+++ cfe/cfe/trunk/AST/Sema.h Wed Jul 11 11:44:03 2007
@@ -223,10 +223,11 @@
                                          tok::TokenKind Kind);
 private:
   Expr *ImplicitConversion(Expr *E); // C99 6.3
-  
-  /// type checking binary operators (subroutines of ParseBinOp).
+
   /// the following "Check" methods will either return a well formed AST node
   /// or will return true if the expressions didn't type check properly.
+  
+  /// type checking binary operators (subroutines of ParseBinOp).
   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
@@ -235,6 +236,12 @@
   ExprResult CheckBitwiseOperands(Expr *op1, Expr *op2);   // C99 6.5.[10...12]
   ExprResult CheckLogicalOperands(Expr *op1, Expr *op2);   // C99 6.5.[13,14]
   
+  /// type checking unary operators (subroutines of ParseUnaryOp).
+  /// C99 6.5.3.2
+  ExprResult CheckAddressOfOperand(Expr *op, SourceLocation loc, unsigned c);
+  Decl *getDecl(Expr *e);
+  ExprResult CheckIndirectionOperand(Expr *op, SourceLocation loc, unsigned c);
+  
   ExprResult CheckIncrementDecrementOperand(Expr *op, SourceLocation loc,
                                             unsigned /*UnaryOperator::Opcode*/c);
 };

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

==============================================================================
--- cfe/cfe/trunk/AST/SemaExpr.cpp (original)
+++ cfe/cfe/trunk/AST/SemaExpr.cpp Wed Jul 11 11:44:03 2007
@@ -176,6 +176,10 @@
   }
   if (Opc == UnaryOperator::PreInc || Opc == UnaryOperator::PreDec)
     return CheckIncrementDecrementOperand((Expr *)Input, OpLoc, Opc);
+  else if (Opc == UnaryOperator::AddrOf)
+    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());
@@ -451,3 +455,64 @@
   return new UnaryOperator(op, (UnaryOperator::Opcode)OpCode, qType);
 }
 
+/// getDecl - This is currently a helper function for CheckAddressOfOperand().
+/// This routine allows us to typecheck complex/recursive expressions
+/// where the declaration is needed for type checking. Here are some
+/// examples: &s.xx, &s.zz[1].yy, &(1+2), &(XX), &"123"[2].
+Decl *Sema::getDecl(Expr *e) {
+  switch (e->getStmtClass()) {
+  case Stmt::DeclRefExprClass:
+    return cast<DeclRefExpr>(e)->getDecl();
+  case Stmt::MemberExprClass:
+    return getDecl(cast<MemberExpr>(e)->getBase());
+  case Stmt::ArraySubscriptExprClass:
+    return getDecl(cast<ArraySubscriptExpr>(e)->getBase());
+  case Stmt::CallExprClass:
+    return getDecl(cast<CallExpr>(e)->getCallee());
+  case Stmt::UnaryOperatorClass:
+    return getDecl(cast<UnaryOperator>(e)->getSubExpr());
+  case Stmt::ParenExprClass:
+    return getDecl(cast<ParenExpr>(e)->getSubExpr());
+  default:
+    return 0;
+  }
+}
+
+/// CheckAddressOfOperand - The operand of & must be either a function
+/// designator or an lvalue designating an object. If it is an lvalue, the 
+/// 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, unsigned OpCode) {
+  Decl *dcl = getDecl(op);
+  
+  if (!op->isLvalue()) {
+    if (dcl && isa<FunctionDecl>(dcl))
+      ;  // C99 6.5.3.2p1: Allow function designators.
+    else
+      return Diag(OpLoc, diag::err_typecheck_invalid_lvalue_addrof);      
+  } 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);
+    }
+    // FIXME: add check for bitfields!
+  }
+  // If the operand has type "type", the result has type "pointer to type".
+  return new UnaryOperator(op, (UnaryOperator::Opcode)OpCode, 
+                           Context.getPointerType(op->getType()));
+}
+
+Action::ExprResult
+Sema::CheckIndirectionOperand(Expr *op, SourceLocation OpLoc, unsigned OpCode) {
+  QualType qType = op->getType();
+
+  assert(!qType.isNull() && "no type for * expression");
+
+  QualType canonType = qType.getCanonicalType();
+  
+  return new UnaryOperator(op, (UnaryOperator::Opcode)OpCode, QualType());
+}

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

==============================================================================
--- cfe/cfe/trunk/Sema/Sema.h (original)
+++ cfe/cfe/trunk/Sema/Sema.h Wed Jul 11 11:44:03 2007
@@ -223,10 +223,11 @@
                                          tok::TokenKind Kind);
 private:
   Expr *ImplicitConversion(Expr *E); // C99 6.3
-  
-  /// type checking binary operators (subroutines of ParseBinOp).
+
   /// the following "Check" methods will either return a well formed AST node
   /// or will return true if the expressions didn't type check properly.
+  
+  /// type checking binary operators (subroutines of ParseBinOp).
   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
@@ -235,6 +236,12 @@
   ExprResult CheckBitwiseOperands(Expr *op1, Expr *op2);   // C99 6.5.[10...12]
   ExprResult CheckLogicalOperands(Expr *op1, Expr *op2);   // C99 6.5.[13,14]
   
+  /// type checking unary operators (subroutines of ParseUnaryOp).
+  /// C99 6.5.3.2
+  ExprResult CheckAddressOfOperand(Expr *op, SourceLocation loc, unsigned c);
+  Decl *getDecl(Expr *e);
+  ExprResult CheckIndirectionOperand(Expr *op, SourceLocation loc, unsigned c);
+  
   ExprResult CheckIncrementDecrementOperand(Expr *op, SourceLocation loc,
                                             unsigned /*UnaryOperator::Opcode*/c);
 };

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

==============================================================================
--- cfe/cfe/trunk/Sema/SemaExpr.cpp (original)
+++ cfe/cfe/trunk/Sema/SemaExpr.cpp Wed Jul 11 11:44:03 2007
@@ -176,6 +176,10 @@
   }
   if (Opc == UnaryOperator::PreInc || Opc == UnaryOperator::PreDec)
     return CheckIncrementDecrementOperand((Expr *)Input, OpLoc, Opc);
+  else if (Opc == UnaryOperator::AddrOf)
+    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());
@@ -451,3 +455,64 @@
   return new UnaryOperator(op, (UnaryOperator::Opcode)OpCode, qType);
 }
 
+/// getDecl - This is currently a helper function for CheckAddressOfOperand().
+/// This routine allows us to typecheck complex/recursive expressions
+/// where the declaration is needed for type checking. Here are some
+/// examples: &s.xx, &s.zz[1].yy, &(1+2), &(XX), &"123"[2].
+Decl *Sema::getDecl(Expr *e) {
+  switch (e->getStmtClass()) {
+  case Stmt::DeclRefExprClass:
+    return cast<DeclRefExpr>(e)->getDecl();
+  case Stmt::MemberExprClass:
+    return getDecl(cast<MemberExpr>(e)->getBase());
+  case Stmt::ArraySubscriptExprClass:
+    return getDecl(cast<ArraySubscriptExpr>(e)->getBase());
+  case Stmt::CallExprClass:
+    return getDecl(cast<CallExpr>(e)->getCallee());
+  case Stmt::UnaryOperatorClass:
+    return getDecl(cast<UnaryOperator>(e)->getSubExpr());
+  case Stmt::ParenExprClass:
+    return getDecl(cast<ParenExpr>(e)->getSubExpr());
+  default:
+    return 0;
+  }
+}
+
+/// CheckAddressOfOperand - The operand of & must be either a function
+/// designator or an lvalue designating an object. If it is an lvalue, the 
+/// 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, unsigned OpCode) {
+  Decl *dcl = getDecl(op);
+  
+  if (!op->isLvalue()) {
+    if (dcl && isa<FunctionDecl>(dcl))
+      ;  // C99 6.5.3.2p1: Allow function designators.
+    else
+      return Diag(OpLoc, diag::err_typecheck_invalid_lvalue_addrof);      
+  } 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);
+    }
+    // FIXME: add check for bitfields!
+  }
+  // If the operand has type "type", the result has type "pointer to type".
+  return new UnaryOperator(op, (UnaryOperator::Opcode)OpCode, 
+                           Context.getPointerType(op->getType()));
+}
+
+Action::ExprResult
+Sema::CheckIndirectionOperand(Expr *op, SourceLocation OpLoc, unsigned OpCode) {
+  QualType qType = op->getType();
+
+  assert(!qType.isNull() && "no type for * expression");
+
+  QualType canonType = qType.getCanonicalType();
+  
+  return new UnaryOperator(op, (UnaryOperator::Opcode)OpCode, QualType());
+}

Modified: cfe/cfe/trunk/clang.xcodeproj/project.pbxproj
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/clang.xcodeproj/project.pbxproj?rev=39408&r1=39407&r2=39408&view=diff

==============================================================================
--- cfe/cfe/trunk/clang.xcodeproj/project.pbxproj (original)
+++ cfe/cfe/trunk/clang.xcodeproj/project.pbxproj Wed Jul 11 11:44:03 2007
@@ -483,10 +483,12 @@
 		08FB7793FE84155DC02AAC07 /* Project object */ = {
 			isa = PBXProject;
 			buildConfigurationList = 1DEB923508733DC60010E9CD /* Build configuration list for PBXProject "clang" */;
+			compatibilityVersion = "Xcode 2.4";
 			hasScannedForEncodings = 1;
 			mainGroup = 08FB7794FE84155DC02AAC07 /* clang */;
 			projectDirPath = "";
 			projectRoot = "";
+			shouldCheckCompatibility = 1;
 			targets = (
 				8DD76F620486A84900D96B5E /* clang */,
 			);

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

==============================================================================
--- cfe/cfe/trunk/include/clang/AST/Decl.h (original)
+++ cfe/cfe/trunk/include/clang/AST/Decl.h Wed Jul 11 11:44:03 2007
@@ -136,7 +136,7 @@
 protected:
   VarDecl(Kind DK, SourceLocation L, IdentifierInfo *Id, QualType T,
           StorageClass SC)
-    : ValueDecl(DK, L, Id, T) {}
+    : ValueDecl(DK, L, Id, T) { SClass = SC; }
 private:
   StorageClass SClass;
   // TODO: Initializer.

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=39408&r1=39407&r2=39408&view=diff

==============================================================================
--- cfe/cfe/trunk/include/clang/AST/Expr.h (original)
+++ cfe/cfe/trunk/include/clang/AST/Expr.h Wed Jul 11 11:44:03 2007
@@ -35,6 +35,17 @@
 public:  
   QualType getType() const { return TR; }
   
+  /// isLvalue - return true if the expression is one of the following:
+  ///  - name, where name must be a variable
+  ///  - e[i]
+  ///  - (e), where e must be an lvalue
+  ///  - e.name, where e must be an lvalue
+  ///  - e->name
+  ///  - *e
+  ///  - string-constant
+  ///
+  bool isLvalue();
+  
   virtual void visit(StmtVisitor &Visitor);
   static bool classof(const Stmt *T) { 
     return T->getStmtClass() >= firstExprConstant &&
@@ -55,7 +66,7 @@
   DeclRefExpr(Decl *d, QualType t) : Expr(DeclRefExprClass, t), D(d) {}
   
   Decl *getDecl() const { return D; }
-  
+    
   virtual void visit(StmtVisitor &Visitor);
   static bool classof(const Stmt *T) { 
     return T->getStmtClass() == DeclRefExprClass; 
@@ -72,6 +83,7 @@
     : Expr(IntegerLiteralClass, type), Value(value) {
     assert(type->isIntegralType() && "Illegal type in IntegerLiteral");
   }
+
   virtual void visit(StmtVisitor &Visitor);
   static bool classof(const Stmt *T) { 
     return T->getStmtClass() == IntegerLiteralClass; 
@@ -84,6 +96,7 @@
 public:
   FloatingLiteral(float value, QualType type) : 
     Expr(FloatingLiteralClass, type), Value(value) {} 
+
   virtual void visit(StmtVisitor &Visitor);
   static bool classof(const Stmt *T) { 
     return T->getStmtClass() == FloatingLiteralClass; 
@@ -119,8 +132,8 @@
   ParenExpr(SourceLocation l, SourceLocation r, Expr *val)
     : Expr(ParenExprClass, QualType()), L(l), R(r), Val(val) {}
   
-  Expr *getSubExpr() { return Val; }
-  
+  Expr *getSubExpr() const { return Val; }
+
   virtual void visit(StmtVisitor &Visitor);
   static bool classof(const Stmt *T) { 
     return T->getStmtClass() == ParenExprClass; 
@@ -156,12 +169,16 @@
   /// isPostfix - Return true if this is a postfix operation, like x++.
   static bool isPostfix(Opcode Op);
 
-  
   Opcode getOpcode() const { return Opc; }
-  Expr *getSubExpr() { return Val; }
+  Expr *getSubExpr() const { return Val; }
   
   bool isPostfix() const { return isPostfix(Opc); }
   
+  /// getDecl - a recursive routine that derives the base decl for an
+  /// expression. For example, it will return the declaration for "s" from
+  /// the following complex expression "s.zz[2].bb.vv".
+  static bool isAddressable(Expr *e);
+
   virtual void visit(StmtVisitor &Visitor);
   static bool classof(const Stmt *T) { 
     return T->getStmtClass() == UnaryOperatorClass; 
@@ -205,7 +222,7 @@
     Expr(ArraySubscriptExprClass, t),
     Base(base), Idx(idx) {}
   
-  Expr *getBase() { return Base; }
+  Expr *getBase() const { return Base; }
   Expr *getIdx() { return Idx; }
   
   virtual void visit(StmtVisitor &Visitor);
@@ -228,7 +245,7 @@
     delete [] Args;
   }
   
-  Expr *getCallee() { return Fn; }
+  Expr *getCallee() const { return Fn; }
   
   /// getNumArgs - Return the number of actual arguments to this call.
   ///
@@ -243,7 +260,7 @@
   /// getNumCommas - Return the number of commas that must have been present in
   /// this function call.
   unsigned getNumCommas() const { return NumArgs ? NumArgs - 1 : 0; }
-  
+
   virtual void visit(StmtVisitor &Visitor);
   static bool classof(const Stmt *T) { 
     return T->getStmtClass() == CallExprClass; 
@@ -262,8 +279,8 @@
     : Expr(MemberExprClass, memberdecl->getType()),
       Base(base), MemberDecl(memberdecl), IsArrow(isarrow) {}
   
-  Expr *getBase() { return Base; }
-  FieldDecl *getMemberDecl() { return MemberDecl; }
+  Expr *getBase() const { return Base; }
+  FieldDecl *getMemberDecl() const { return MemberDecl; }
   bool isArrow() const { return IsArrow; }
   
   virtual void visit(StmtVisitor &Visitor);
@@ -287,6 +304,7 @@
   QualType getDestType() const { return Ty; }
   
   Expr *getSubExpr() { return Op; }
+  
   virtual void visit(StmtVisitor &Visitor);
   static bool classof(const Stmt *T) { 
     return T->getStmtClass() == CastExprClass; 

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

==============================================================================
--- cfe/cfe/trunk/include/clang/AST/ExprCXX.h (original)
+++ cfe/cfe/trunk/include/clang/AST/ExprCXX.h Wed Jul 11 11:44:03 2007
@@ -50,6 +50,9 @@
   public:
     CXXBoolLiteralExpr(bool val) : 
       Expr(CXXBoolLiteralExprClass, QualType()), Value(val) {}
+      
+    virtual Expr *getPrimaryExpr() { return this; }
+
     virtual void visit(StmtVisitor &Visitor);
   };
 

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=39408&r1=39407&r2=39408&view=diff

==============================================================================
--- cfe/cfe/trunk/include/clang/Basic/DiagnosticKinds.def (original)
+++ cfe/cfe/trunk/include/clang/Basic/DiagnosticKinds.def Wed Jul 11 11:44:03 2007
@@ -529,6 +529,10 @@
      "illegal storage class on file-scoped variable")
 DIAG(err_typecheck_sclass_func, ERROR,
      "illegal storage class on function")
+DIAG(err_typecheck_address_of_register, ERROR,
+     "address of register variable requested")
+DIAG(err_typecheck_invalid_lvalue_addrof, ERROR,
+     "invalid lvalue in address expression")
 
 // Statements.
 DIAG(err_continue_not_in_loop, ERROR,





More information about the cfe-commits mailing list