[cfe-commits] r39440 - in /cfe/cfe/trunk: AST/Sema.h AST/SemaExpr.cpp AST/Type.cpp Sema/Sema.h Sema/SemaExpr.cpp

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


Author: snaroff
Date: Wed Jul 11 11:44:25 2007
New Revision: 39440

URL: http://llvm.org/viewvc/llvm-project?rev=39440&view=rev
Log:
Bug #:
Submitted by:
Reviewed by:
This check-in should finally "nail" complex pointer assignments (involving
qualifiers, etc.).
- Replaced pointerTypeQualifiersAlign() with CheckPointerTypesForAssignment()
This also simplified UsualAssignmentConversions().
- Fixed Type::pointerTypesAreCompatible() and Type::typesAreCompatible()
to closely reflect the spec. They were (unfortunately) compensating for some of the
missing logic in the assignment checking code.

Modified:
    cfe/cfe/trunk/AST/Sema.h
    cfe/cfe/trunk/AST/SemaExpr.cpp
    cfe/cfe/trunk/AST/Type.cpp
    cfe/cfe/trunk/Sema/Sema.h
    cfe/cfe/trunk/Sema/SemaExpr.cpp

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

==============================================================================
--- cfe/cfe/trunk/AST/Sema.h (original)
+++ cfe/cfe/trunk/AST/Sema.h Wed Jul 11 11:44:25 2007
@@ -244,8 +244,9 @@
   // CheckSimpleAssignment, CheckCompoundAssignment and ParseCallExpr. 
   QualType UsualAssignmentConversions(QualType lhs, QualType rhs, // C99 6.5.16
                                       AssignmentConversionResult &r);
-  // Helper function for UsualAssignmentConversions
-  bool pointerTypeQualifiersAlign(QualType lhsType, QualType rhsType);
+  // Helper function for UsualAssignmentConversions (C99 6.5.16.1p1)
+  QualType CheckPointerTypesForAssignment(QualType lhsType, QualType rhsType,
+                                          AssignmentConversionResult &r);
   
   /// the following "Check" methods will return a valid/converted QualType
   /// or a null QualType (indicating an error diagnostic was issued).

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

==============================================================================
--- cfe/cfe/trunk/AST/SemaExpr.cpp (original)
+++ cfe/cfe/trunk/AST/SemaExpr.cpp Wed Jul 11 11:44:25 2007
@@ -452,37 +452,46 @@
   return Context.maxIntegerType(lhs, rhs);
 }
 
-// C99 6.5.16.1p1: both operands are pointers to qualified or 
-// unqualified versions of compatible types, and the type *pointed to* by
-// the left has all the qualifiers of the type *pointed to* by the right;
-bool Sema::pointerTypeQualifiersAlign(QualType lhsType, QualType rhsType) {
-  QualType lPointee, rPointee;
+// CheckPointerTypesForAssignment - This is a very tricky routine (despite
+// being closely modeled after the C99 spec:-). The odd characteristic of this 
+// routine is it effectively iqnores the qualifiers on the top level pointee.
+// This circumvents the usual type rules specified in 6.2.7p1 & 6.7.5.[1-3].
+// FIXME: add a couple examples in this comment.
+QualType Sema::CheckPointerTypesForAssignment(QualType lhsType, 
+                                              QualType rhsType,
+                                              AssignmentConversionResult &r) {
+  QualType lhptee, rhptee;
   
   // get the "pointed to" type (ignoring qualifiers at the top level)
-  lPointee = cast<PointerType>(lhsType.getCanonicalType())->getPointeeType();
-  rPointee = cast<PointerType>(rhsType.getCanonicalType())->getPointeeType();
+  lhptee = cast<PointerType>(lhsType.getCanonicalType())->getPointeeType();
+  rhptee = cast<PointerType>(rhsType.getCanonicalType())->getPointeeType();
   
   // make sure we operate on the canonical type
-  lPointee = lPointee.getCanonicalType();
-  rPointee = rPointee.getCanonicalType();
-    
-  while (!rPointee.isNull() && !lPointee.isNull()) {
-    unsigned rightQuals = rPointee.getQualifiers();
-    if (rightQuals && (rightQuals != lPointee.getQualifiers()))
-      return false; 
-
-    // if necessary, continue checking pointees...
-    if (const PointerType *rPtr = dyn_cast<PointerType>(rPointee))
-      rPointee = rPtr->getPointeeType().getCanonicalType();
-    else
-      rPointee = QualType();
-      
-    if (const PointerType *lPtr = dyn_cast<PointerType>(lPointee))
-      lPointee = lPtr->getPointeeType().getCanonicalType();
-    else
-      rPointee = QualType();
-  }
-  return true;
+  lhptee = lhptee.getCanonicalType();
+  rhptee = rhptee.getCanonicalType();
+
+  // C99 6.5.16.1p1: This following citation is common to constraints 
+  // 3 & 4 (below). ...and the type *pointed to* by the left has all the 
+  // qualifiers of the type *pointed to* by the right; 
+  if ((lhptee.getQualifiers() & rhptee.getQualifiers()) != 
+       rhptee.getQualifiers())
+    r = CompatiblePointerDiscardsQualifiers;
+
+  // C99 6.5.16.1p1 (constraint 4): If one operand is a pointer to an object or 
+  // incomplete type and the other is a pointer to a qualified or unqualified 
+  // version of void...
+  if (lhptee.getUnqualifiedType()->isVoidType() &&
+      (rhptee->isObjectType() || rhptee->isIncompleteType()))
+    ;
+  else if (rhptee.getUnqualifiedType()->isVoidType() &&
+      (lhptee->isObjectType() || lhptee->isIncompleteType()))
+    ;
+  // C99 6.5.16.1p1 (constraint 3): both operands are pointers to qualified or 
+  // unqualified versions of compatible types, ...
+  else if (!Type::typesAreCompatible(lhptee.getUnqualifiedType(), 
+                                     rhptee.getUnqualifiedType()))
+    r = IncompatiblePointer; // this "trumps" PointerAssignDiscardsQualifiers
+  return rhsType;
 }
 
 /// UsualAssignmentConversions (C99 6.5.16) - This routine currently 
@@ -519,14 +528,8 @@
       r = PointerFromInt;
       return rhsType;
     }
-    if (rhsType->isPointerType()) { 
-      if (Type::pointerTypesAreCompatible(lhsType, rhsType)) {
-        if (!pointerTypeQualifiersAlign(lhsType, rhsType))
-          r = CompatiblePointerDiscardsQualifiers;
-      } else
-        r = IncompatiblePointer;
-      return rhsType;
-    }
+    if (rhsType->isPointerType())
+      return CheckPointerTypesForAssignment(lhsType, rhsType, r);
   } else if (rhsType->isPointerType()) {
     if (lhsType->isIntegerType()) {
       // C99 6.5.16.1p1: the left operand is _Bool and the right is a pointer.
@@ -534,14 +537,8 @@
         r = IntFromPointer;
       return rhsType;
     }
-    if (lhsType->isPointerType()) {
-      if (Type::pointerTypesAreCompatible(lhsType, rhsType)) {
-        if (!pointerTypeQualifiersAlign(lhsType, rhsType))
-          r = CompatiblePointerDiscardsQualifiers;
-      } else
-        r = IncompatiblePointer;
-      return rhsType;
-    }
+    if (lhsType->isPointerType()) 
+      return CheckPointerTypesForAssignment(lhsType, rhsType, r);
   } else if (isa<TagType>(lhsType) && isa<TagType>(rhsType)) {
     if (Type::tagTypesAreCompatible(lhsType, rhsType))
       return rhsType;
@@ -789,6 +786,14 @@
     if (dcl && isa<FunctionDecl>(dcl))
       ;  // C99 6.5.3.2p1: Allow function designators.
     else {
+      /* FIXME: The following produces an (incorrect) error. The 
+         Type::isModifiableLvalue() predicate is causing problems.
+      
+        const char **cpp;
+        const char c = 'A';
+
+        int main() { *cpp = &c;  // valid }
+     */
       Diag(OpLoc, diag::err_typecheck_invalid_lvalue_addrof);
       return QualType();
     }

Modified: cfe/cfe/trunk/AST/Type.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/AST/Type.cpp?rev=39440&r1=39439&r2=39440&view=diff

==============================================================================
--- cfe/cfe/trunk/AST/Type.cpp (original)
+++ cfe/cfe/trunk/AST/Type.cpp Wed Jul 11 11:44:25 2007
@@ -90,12 +90,14 @@
 }
 
 bool Type::pointerTypesAreCompatible(QualType lhs, QualType rhs) {
+  // C99 6.7.5.1p2: For two pointer types to be compatible, both shall be 
+  // identically qualified and both shall be pointers to compatible types.
+  if (lhs.getQualifiers() != rhs.getQualifiers())
+    return false;
+    
   QualType ltype = cast<PointerType>(lhs.getCanonicalType())->getPointeeType();
   QualType rtype = cast<PointerType>(rhs.getCanonicalType())->getPointeeType();
-
-  // handle void first (not sure this is the best place to check for this).
-  if (ltype->isVoidType() || rtype->isVoidType())
-    return true;
+  
   return typesAreCompatible(ltype, rtype);
 }
 
@@ -167,8 +169,6 @@
 
   switch (lcanon->getTypeClass()) {
     case Type::Pointer:
-      // C99 6.7.3p9: For two qualified types to be compatible, both shall have
-      // the identically qualified version of a compatible type. ??
       return pointerTypesAreCompatible(lcanon, rcanon);
     case Type::Array:
       return arrayTypesAreCompatible(lcanon, rcanon);
@@ -178,10 +178,16 @@
     case Type::Tagged: // handle structures, unions
       return tagTypesAreCompatible(lcanon, rcanon);
     case Type::Builtin:
-      // exclude type qualifiers...
+      // C99 6.7.3p9: For two qualified types to be compatible, both shall 
+      // have the identically qualified version of a compatible type.
+      if (lhs.getQualifiers() != rhs.getQualifiers())
+        return false;
+        
+      // C99 6.2.7p1: Two types have compatible types if their types are the 
+      // same. See 6.7.[2,3,5] for additional rules.
       if (lcanon.getTypePtr() == rcanon.getTypePtr())
         return true;
-      return false; // C99 6.2.7p1
+      return false; 
     default:
       assert(0 && "unexpected type");
   }

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

==============================================================================
--- cfe/cfe/trunk/Sema/Sema.h (original)
+++ cfe/cfe/trunk/Sema/Sema.h Wed Jul 11 11:44:25 2007
@@ -244,8 +244,9 @@
   // CheckSimpleAssignment, CheckCompoundAssignment and ParseCallExpr. 
   QualType UsualAssignmentConversions(QualType lhs, QualType rhs, // C99 6.5.16
                                       AssignmentConversionResult &r);
-  // Helper function for UsualAssignmentConversions
-  bool pointerTypeQualifiersAlign(QualType lhsType, QualType rhsType);
+  // Helper function for UsualAssignmentConversions (C99 6.5.16.1p1)
+  QualType CheckPointerTypesForAssignment(QualType lhsType, QualType rhsType,
+                                          AssignmentConversionResult &r);
   
   /// the following "Check" methods will return a valid/converted QualType
   /// or a null QualType (indicating an error diagnostic was issued).

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

==============================================================================
--- cfe/cfe/trunk/Sema/SemaExpr.cpp (original)
+++ cfe/cfe/trunk/Sema/SemaExpr.cpp Wed Jul 11 11:44:25 2007
@@ -452,37 +452,46 @@
   return Context.maxIntegerType(lhs, rhs);
 }
 
-// C99 6.5.16.1p1: both operands are pointers to qualified or 
-// unqualified versions of compatible types, and the type *pointed to* by
-// the left has all the qualifiers of the type *pointed to* by the right;
-bool Sema::pointerTypeQualifiersAlign(QualType lhsType, QualType rhsType) {
-  QualType lPointee, rPointee;
+// CheckPointerTypesForAssignment - This is a very tricky routine (despite
+// being closely modeled after the C99 spec:-). The odd characteristic of this 
+// routine is it effectively iqnores the qualifiers on the top level pointee.
+// This circumvents the usual type rules specified in 6.2.7p1 & 6.7.5.[1-3].
+// FIXME: add a couple examples in this comment.
+QualType Sema::CheckPointerTypesForAssignment(QualType lhsType, 
+                                              QualType rhsType,
+                                              AssignmentConversionResult &r) {
+  QualType lhptee, rhptee;
   
   // get the "pointed to" type (ignoring qualifiers at the top level)
-  lPointee = cast<PointerType>(lhsType.getCanonicalType())->getPointeeType();
-  rPointee = cast<PointerType>(rhsType.getCanonicalType())->getPointeeType();
+  lhptee = cast<PointerType>(lhsType.getCanonicalType())->getPointeeType();
+  rhptee = cast<PointerType>(rhsType.getCanonicalType())->getPointeeType();
   
   // make sure we operate on the canonical type
-  lPointee = lPointee.getCanonicalType();
-  rPointee = rPointee.getCanonicalType();
-    
-  while (!rPointee.isNull() && !lPointee.isNull()) {
-    unsigned rightQuals = rPointee.getQualifiers();
-    if (rightQuals && (rightQuals != lPointee.getQualifiers()))
-      return false; 
-
-    // if necessary, continue checking pointees...
-    if (const PointerType *rPtr = dyn_cast<PointerType>(rPointee))
-      rPointee = rPtr->getPointeeType().getCanonicalType();
-    else
-      rPointee = QualType();
-      
-    if (const PointerType *lPtr = dyn_cast<PointerType>(lPointee))
-      lPointee = lPtr->getPointeeType().getCanonicalType();
-    else
-      rPointee = QualType();
-  }
-  return true;
+  lhptee = lhptee.getCanonicalType();
+  rhptee = rhptee.getCanonicalType();
+
+  // C99 6.5.16.1p1: This following citation is common to constraints 
+  // 3 & 4 (below). ...and the type *pointed to* by the left has all the 
+  // qualifiers of the type *pointed to* by the right; 
+  if ((lhptee.getQualifiers() & rhptee.getQualifiers()) != 
+       rhptee.getQualifiers())
+    r = CompatiblePointerDiscardsQualifiers;
+
+  // C99 6.5.16.1p1 (constraint 4): If one operand is a pointer to an object or 
+  // incomplete type and the other is a pointer to a qualified or unqualified 
+  // version of void...
+  if (lhptee.getUnqualifiedType()->isVoidType() &&
+      (rhptee->isObjectType() || rhptee->isIncompleteType()))
+    ;
+  else if (rhptee.getUnqualifiedType()->isVoidType() &&
+      (lhptee->isObjectType() || lhptee->isIncompleteType()))
+    ;
+  // C99 6.5.16.1p1 (constraint 3): both operands are pointers to qualified or 
+  // unqualified versions of compatible types, ...
+  else if (!Type::typesAreCompatible(lhptee.getUnqualifiedType(), 
+                                     rhptee.getUnqualifiedType()))
+    r = IncompatiblePointer; // this "trumps" PointerAssignDiscardsQualifiers
+  return rhsType;
 }
 
 /// UsualAssignmentConversions (C99 6.5.16) - This routine currently 
@@ -519,14 +528,8 @@
       r = PointerFromInt;
       return rhsType;
     }
-    if (rhsType->isPointerType()) { 
-      if (Type::pointerTypesAreCompatible(lhsType, rhsType)) {
-        if (!pointerTypeQualifiersAlign(lhsType, rhsType))
-          r = CompatiblePointerDiscardsQualifiers;
-      } else
-        r = IncompatiblePointer;
-      return rhsType;
-    }
+    if (rhsType->isPointerType())
+      return CheckPointerTypesForAssignment(lhsType, rhsType, r);
   } else if (rhsType->isPointerType()) {
     if (lhsType->isIntegerType()) {
       // C99 6.5.16.1p1: the left operand is _Bool and the right is a pointer.
@@ -534,14 +537,8 @@
         r = IntFromPointer;
       return rhsType;
     }
-    if (lhsType->isPointerType()) {
-      if (Type::pointerTypesAreCompatible(lhsType, rhsType)) {
-        if (!pointerTypeQualifiersAlign(lhsType, rhsType))
-          r = CompatiblePointerDiscardsQualifiers;
-      } else
-        r = IncompatiblePointer;
-      return rhsType;
-    }
+    if (lhsType->isPointerType()) 
+      return CheckPointerTypesForAssignment(lhsType, rhsType, r);
   } else if (isa<TagType>(lhsType) && isa<TagType>(rhsType)) {
     if (Type::tagTypesAreCompatible(lhsType, rhsType))
       return rhsType;
@@ -789,6 +786,14 @@
     if (dcl && isa<FunctionDecl>(dcl))
       ;  // C99 6.5.3.2p1: Allow function designators.
     else {
+      /* FIXME: The following produces an (incorrect) error. The 
+         Type::isModifiableLvalue() predicate is causing problems.
+      
+        const char **cpp;
+        const char c = 'A';
+
+        int main() { *cpp = &c;  // valid }
+     */
       Diag(OpLoc, diag::err_typecheck_invalid_lvalue_addrof);
       return QualType();
     }





More information about the cfe-commits mailing list