[cfe-commits] r39451 - in /cfe/cfe/trunk: AST/SemaExpr.cpp AST/Type.cpp Sema/SemaExpr.cpp clang.xcodeproj/project.pbxproj include/clang/Basic/DiagnosticKinds.def

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


Author: snaroff
Date: Wed Jul 11 11:44:34 2007
New Revision: 39451

URL: http://llvm.org/viewvc/llvm-project?rev=39451&view=rev
Log:
Bug #:
Submitted by:
Reviewed by:
- Implement type checking for Sema::CheckConditionalOperands.
- Fixed crasher in Sema::UsualUnaryConversion (incorrect use of cast<>).
- Added a few diagnostics and started passing 2 args! (Thanks Chris!).

Here's some diagnostic output that is much nicer than gcc...

[dylan:~/llvm/tools/clang] admin% ../../Debug/bin/clang cond.c
cond.c:12:14: error: used type 'struct foo' where arithmetic or pointer type is required
  result = s ? 1 : 2;
             ^
cond.c:13:14: error: incompatible operand types ('struct foo' and 'struct bar')
  result = a ? s : s2;
             ^
cond.c:14:14: warning: pointer type mismatch ('struct foo *' and 'struct bar *')
  result = a ? ps : ps2;
             ^
cond.c:14:10: warning: assignment makes integer from pointer without a cast
  result = a ? ps : ps2;
         ^
cond.c:15:14: error: incompatible operand types ('struct foo *' and 'struct foo')
  result = a ? ps : s;
             ^
cond.c:16:14: warning: pointer type mismatch ('void (*)(int)' and 'void (*)(int, int)')
  result = a ? func : func2;
             ^
cond.c:16:10: warning: assignment makes integer from pointer without a cast
  result = a ? func : func2;
         ^
7 diagnostics generated.
[dylan:~/llvm/tools/clang] admin% cc -c cond.c
cond.c: In function 'main':
cond.c:12: error: used struct type value where scalar is required
cond.c:13: error: type mismatch in conditional expression
cond.c:14: warning: pointer type mismatch in conditional expression
cond.c:14: warning: assignment makes integer from pointer without a cast
cond.c:15: error: type mismatch in conditional expression
cond.c:16: warning: pointer type mismatch in conditional expression
cond.c:16: warning: assignment makes integer from pointer without a cast

Modified:
    cfe/cfe/trunk/AST/SemaExpr.cpp
    cfe/cfe/trunk/AST/Type.cpp
    cfe/cfe/trunk/Sema/SemaExpr.cpp
    cfe/cfe/trunk/clang.xcodeproj/project.pbxproj
    cfe/cfe/trunk/include/clang/Basic/DiagnosticKinds.def

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

==============================================================================
--- cfe/cfe/trunk/AST/SemaExpr.cpp (original)
+++ cfe/cfe/trunk/AST/SemaExpr.cpp Wed Jul 11 11:44:34 2007
@@ -170,6 +170,8 @@
   return e;
 }
 
+/// The UsualUnaryConversion() function is *not* called by this routine.
+/// See C99 6.3.2.1p[2-4] for more details.
 QualType Sema::CheckSizeOfAlignOfOperand(QualType exprType, 
                                          SourceLocation OpLoc, bool isSizeof) {
   // C99 6.5.3.4p1:
@@ -386,16 +388,78 @@
 
 inline QualType Sema::CheckConditionalOperands( // C99 6.5.15
   Expr *Cond, Expr *LHS, Expr *RHS, SourceLocation questionLoc) {
-  QualType cond = Cond->getType().getCanonicalType();
-  QualType lhs = LHS->getType().getCanonicalType();
-  QualType rhs = RHS->getType().getCanonicalType();
-
+  QualType cond = Cond->getType();
+  QualType lhs = LHS->getType();
+  QualType rhs = RHS->getType();
+  
   assert(!cond.isNull() && "ParseConditionalOp(): no conditional type");
   assert(!lhs.isNull() && "ParseConditionalOp(): no lhs type");
   assert(!rhs.isNull() && "ParseConditionalOp(): no rhs type");
 
-  // C99 6.5.15p2,3
-  return rhs;
+  cond = UsualUnaryConversion(cond);
+  lhs = UsualUnaryConversion(lhs);
+  rhs = UsualUnaryConversion(rhs);
+  
+  // first, check the condition.
+  if (!cond->isScalarType()) { // C99 6.5.15p2
+    // FIXME: need to compute the location from the Cond expr node...
+    Diag(questionLoc, diag::err_typecheck_cond_expect_scalar, 
+                      cond.getAsString());
+    return QualType();
+  }
+  // now check the two expressions.
+  if (lhs->isArithmeticType() && rhs->isArithmeticType()) // C99 6.5.15p3,5
+    return UsualArithmeticConversions(lhs, rhs);
+    
+  if ((lhs->isStructureType() && rhs->isStructureType()) || // C99 6.5.15p3
+      (lhs->isUnionType() && rhs->isUnionType())) {
+    TagType *lTag = cast<TagType>(lhs.getCanonicalType());
+    TagType *rTag = cast<TagType>(rhs.getCanonicalType());
+    
+    if (lTag->getDecl()->getIdentifier() == rTag->getDecl()->getIdentifier()) 
+      return lhs;
+    else {
+      Diag(questionLoc, diag::err_typecheck_cond_incompatible_operands,
+           lhs.getAsString(), rhs.getAsString());
+      return QualType();
+    }
+  }
+  if (lhs->isPointerType() && rhs->isPointerType()) { // C99 6.5.15p3,6
+    QualType lhptee, rhptee;
+    
+    // get the "pointed to" type
+    lhptee = cast<PointerType>(lhs.getCanonicalType())->getPointeeType();
+    rhptee = cast<PointerType>(rhs.getCanonicalType())->getPointeeType();
+
+    // ignore qualifiers on void (C99 6.5.15p3, clause 6)
+    if (lhptee.getUnqualifiedType()->isVoidType() &&
+        (rhptee->isObjectType() || rhptee->isIncompleteType()))
+      return lhs;
+    if (rhptee.getUnqualifiedType()->isVoidType() &&
+        (lhptee->isObjectType() || lhptee->isIncompleteType()))
+      return rhs;
+
+    // FIXME: C99 6.5.15p6: If both operands are pointers to compatible types
+    // *or* to differently qualified versions of compatible types, the result
+    // type is a pointer to an appropriately qualified version of the 
+    // *composite* type.
+    if (!Type::typesAreCompatible(lhptee.getUnqualifiedType(), 
+                                  rhptee.getUnqualifiedType())) {
+      Diag(questionLoc, diag::ext_typecheck_cond_incompatible_pointers,
+                        lhs.getAsString(), rhs.getAsString());
+      return lhs; // FIXME: this is an _ext - is this return o.k?
+    }
+  }
+  if (lhs->isVoidType() && rhs->isVoidType()) // C99 6.5.15p3
+    return lhs;
+  if (lhs->isPointerType() && RHS->isNullPointerConstant()) // C99 6.5.15p3
+    return lhs;
+  if (rhs->isPointerType() && LHS->isNullPointerConstant()) // C99 6.5.15p3
+    return rhs;
+    
+  Diag(questionLoc, diag::err_typecheck_cond_incompatible_operands,
+      lhs.getAsString(), rhs.getAsString());
+  return QualType();
 }
 
 /// ParseConditionalOp - Parse a ?: operation.  Note that 'LHS' may be null
@@ -421,10 +485,10 @@
   
   if (t->isPromotableIntegerType()) // C99 6.3.1.1p2
     return Context.IntTy;
-  else if (t->isFunctionType()) // C99 6.3.2.1p4
-    return Context.getPointerType(t);
-  else if (t->isArrayType()) // C99 6.3.2.1p3
-    return Context.getPointerType(cast<ArrayType>(t)->getElementType());
+  if (t->isFunctionType()) // C99 6.3.2.1p4
+    return Context.getPointerType(t.getCanonicalType());
+  if (const ArrayType *ary = dyn_cast<ArrayType>(t.getCanonicalType()))
+    return Context.getPointerType(ary->getElementType()); // C99 6.3.2.1p3
   return t;
 }
 
@@ -800,7 +864,7 @@
 /// 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.
+/// operator (C99 6.3.2.1p[2-4]), and its result is never an lvalue.
 QualType Sema::CheckAddressOfOperand(Expr *op, SourceLocation OpLoc) {
   Decl *dcl = getPrimaryDeclaration(op);
   

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

==============================================================================
--- cfe/cfe/trunk/AST/Type.cpp (original)
+++ cfe/cfe/trunk/AST/Type.cpp Wed Jul 11 11:44:34 2007
@@ -258,16 +258,20 @@
   if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType))
     return BT->getKind() >= BuiltinType::Bool &&
            BT->getKind() <= BuiltinType::LongDoubleComplex;
-  if (const TagType *TT = dyn_cast<TagType>(CanonicalType))
+  if (const TagType *TT = dyn_cast<TagType>(CanonicalType)) {
     if (TT->getDecl()->getKind() == Decl::Enum)
       return true;
+    return false;
+  }
   return CanonicalType->getTypeClass() == Pointer;
 }
 
 bool Type::isAggregateType() const {
-  if (const TagType *TT = dyn_cast<TagType>(CanonicalType))
+  if (const TagType *TT = dyn_cast<TagType>(CanonicalType)) {
     if (TT->getDecl()->getKind() == Decl::Struct)
       return true;
+    return false;
+  }
   return CanonicalType->getTypeClass() == Array;
 }
 

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

==============================================================================
--- cfe/cfe/trunk/Sema/SemaExpr.cpp (original)
+++ cfe/cfe/trunk/Sema/SemaExpr.cpp Wed Jul 11 11:44:34 2007
@@ -170,6 +170,8 @@
   return e;
 }
 
+/// The UsualUnaryConversion() function is *not* called by this routine.
+/// See C99 6.3.2.1p[2-4] for more details.
 QualType Sema::CheckSizeOfAlignOfOperand(QualType exprType, 
                                          SourceLocation OpLoc, bool isSizeof) {
   // C99 6.5.3.4p1:
@@ -386,16 +388,78 @@
 
 inline QualType Sema::CheckConditionalOperands( // C99 6.5.15
   Expr *Cond, Expr *LHS, Expr *RHS, SourceLocation questionLoc) {
-  QualType cond = Cond->getType().getCanonicalType();
-  QualType lhs = LHS->getType().getCanonicalType();
-  QualType rhs = RHS->getType().getCanonicalType();
-
+  QualType cond = Cond->getType();
+  QualType lhs = LHS->getType();
+  QualType rhs = RHS->getType();
+  
   assert(!cond.isNull() && "ParseConditionalOp(): no conditional type");
   assert(!lhs.isNull() && "ParseConditionalOp(): no lhs type");
   assert(!rhs.isNull() && "ParseConditionalOp(): no rhs type");
 
-  // C99 6.5.15p2,3
-  return rhs;
+  cond = UsualUnaryConversion(cond);
+  lhs = UsualUnaryConversion(lhs);
+  rhs = UsualUnaryConversion(rhs);
+  
+  // first, check the condition.
+  if (!cond->isScalarType()) { // C99 6.5.15p2
+    // FIXME: need to compute the location from the Cond expr node...
+    Diag(questionLoc, diag::err_typecheck_cond_expect_scalar, 
+                      cond.getAsString());
+    return QualType();
+  }
+  // now check the two expressions.
+  if (lhs->isArithmeticType() && rhs->isArithmeticType()) // C99 6.5.15p3,5
+    return UsualArithmeticConversions(lhs, rhs);
+    
+  if ((lhs->isStructureType() && rhs->isStructureType()) || // C99 6.5.15p3
+      (lhs->isUnionType() && rhs->isUnionType())) {
+    TagType *lTag = cast<TagType>(lhs.getCanonicalType());
+    TagType *rTag = cast<TagType>(rhs.getCanonicalType());
+    
+    if (lTag->getDecl()->getIdentifier() == rTag->getDecl()->getIdentifier()) 
+      return lhs;
+    else {
+      Diag(questionLoc, diag::err_typecheck_cond_incompatible_operands,
+           lhs.getAsString(), rhs.getAsString());
+      return QualType();
+    }
+  }
+  if (lhs->isPointerType() && rhs->isPointerType()) { // C99 6.5.15p3,6
+    QualType lhptee, rhptee;
+    
+    // get the "pointed to" type
+    lhptee = cast<PointerType>(lhs.getCanonicalType())->getPointeeType();
+    rhptee = cast<PointerType>(rhs.getCanonicalType())->getPointeeType();
+
+    // ignore qualifiers on void (C99 6.5.15p3, clause 6)
+    if (lhptee.getUnqualifiedType()->isVoidType() &&
+        (rhptee->isObjectType() || rhptee->isIncompleteType()))
+      return lhs;
+    if (rhptee.getUnqualifiedType()->isVoidType() &&
+        (lhptee->isObjectType() || lhptee->isIncompleteType()))
+      return rhs;
+
+    // FIXME: C99 6.5.15p6: If both operands are pointers to compatible types
+    // *or* to differently qualified versions of compatible types, the result
+    // type is a pointer to an appropriately qualified version of the 
+    // *composite* type.
+    if (!Type::typesAreCompatible(lhptee.getUnqualifiedType(), 
+                                  rhptee.getUnqualifiedType())) {
+      Diag(questionLoc, diag::ext_typecheck_cond_incompatible_pointers,
+                        lhs.getAsString(), rhs.getAsString());
+      return lhs; // FIXME: this is an _ext - is this return o.k?
+    }
+  }
+  if (lhs->isVoidType() && rhs->isVoidType()) // C99 6.5.15p3
+    return lhs;
+  if (lhs->isPointerType() && RHS->isNullPointerConstant()) // C99 6.5.15p3
+    return lhs;
+  if (rhs->isPointerType() && LHS->isNullPointerConstant()) // C99 6.5.15p3
+    return rhs;
+    
+  Diag(questionLoc, diag::err_typecheck_cond_incompatible_operands,
+      lhs.getAsString(), rhs.getAsString());
+  return QualType();
 }
 
 /// ParseConditionalOp - Parse a ?: operation.  Note that 'LHS' may be null
@@ -421,10 +485,10 @@
   
   if (t->isPromotableIntegerType()) // C99 6.3.1.1p2
     return Context.IntTy;
-  else if (t->isFunctionType()) // C99 6.3.2.1p4
-    return Context.getPointerType(t);
-  else if (t->isArrayType()) // C99 6.3.2.1p3
-    return Context.getPointerType(cast<ArrayType>(t)->getElementType());
+  if (t->isFunctionType()) // C99 6.3.2.1p4
+    return Context.getPointerType(t.getCanonicalType());
+  if (const ArrayType *ary = dyn_cast<ArrayType>(t.getCanonicalType()))
+    return Context.getPointerType(ary->getElementType()); // C99 6.3.2.1p3
   return t;
 }
 
@@ -800,7 +864,7 @@
 /// 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.
+/// operator (C99 6.3.2.1p[2-4]), and its result is never an lvalue.
 QualType Sema::CheckAddressOfOperand(Expr *op, SourceLocation OpLoc) {
   Decl *dcl = getPrimaryDeclaration(op);
   

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

==============================================================================
--- cfe/cfe/trunk/clang.xcodeproj/project.pbxproj (original)
+++ cfe/cfe/trunk/clang.xcodeproj/project.pbxproj Wed Jul 11 11:44:34 2007
@@ -94,6 +94,23 @@
 		DED7D9E50A5257F6003AD0FB /* ScratchBuffer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DED7D9E40A5257F6003AD0FB /* ScratchBuffer.cpp */; };
 /* End PBXBuildFile section */
 
+/* Begin PBXBuildStyle section */
+		84D221650BFB885000DAAD04 /* Development */ = {
+			isa = PBXBuildStyle;
+			buildSettings = {
+				COPY_PHASE_STRIP = NO;
+			};
+			name = Development;
+		};
+		84D221660BFB885000DAAD04 /* Deployment */ = {
+			isa = PBXBuildStyle;
+			buildSettings = {
+				COPY_PHASE_STRIP = YES;
+			};
+			name = Deployment;
+		};
+/* End PBXBuildStyle section */
+
 /* Begin PBXCopyFilesBuildPhase section */
 		8DD76F690486A84900D96B5E /* CopyFiles */ = {
 			isa = PBXCopyFilesBuildPhase;
@@ -476,6 +493,12 @@
 		08FB7793FE84155DC02AAC07 /* Project object */ = {
 			isa = PBXProject;
 			buildConfigurationList = 1DEB923508733DC60010E9CD /* Build configuration list for PBXProject "clang" */;
+			buildSettings = {
+			};
+			buildStyles = (
+				84D221650BFB885000DAAD04 /* Development */,
+				84D221660BFB885000DAAD04 /* Deployment */,
+			);
 			hasScannedForEncodings = 1;
 			mainGroup = 08FB7794FE84155DC02AAC07 /* clang */;
 			projectDirPath = "";

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=39451&r1=39450&r2=39451&view=diff

==============================================================================
--- cfe/cfe/trunk/include/clang/Basic/DiagnosticKinds.def (original)
+++ cfe/cfe/trunk/include/clang/Basic/DiagnosticKinds.def Wed Jul 11 11:44:34 2007
@@ -577,6 +577,12 @@
      "passing argument %0 from incompatible pointer type")
 DIAG(ext_typecheck_passing_discards_qualifiers, EXTENSION,
      "passing argument %0 discards qualifiers from pointer target type")
+DIAG(err_typecheck_cond_expect_scalar, ERROR,
+     "used type '%0' where arithmetic or pointer type is required")
+DIAG(err_typecheck_cond_incompatible_operands, ERROR,
+     "incompatible operand types ('%0' and '%1')")
+DIAG(ext_typecheck_cond_incompatible_pointers, EXTENSION,
+     "pointer type mismatch ('%0' and '%1')")
 
 // Statements.
 DIAG(err_continue_not_in_loop, ERROR,





More information about the cfe-commits mailing list