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

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


Author: snaroff
Date: Wed Jul 11 11:44:19 2007
New Revision: 39432

URL: http://llvm.org/viewvc/llvm-project?rev=39432&view=rev
Log:
Bug #:
Submitted by:
Reviewed by:
Work on finishing up typechecking for simple assignments (=) and function
calls. Here is an overview:
- implemented type checking for function calls (in Sema::ParseCallExpr).
- refactored UsualAssignmentConversions to return the result of the conversion.
This enum will allow all clients to emit different diagnostics based on context.
- fixed bug in Expr::isLvalue()...it wasn't handling arrays properly. Also
changed the name to isModifiableLvalue, which is consistent with the function on QualType.
- Added 6 diagnostics (3 errors, 3 extensions).

Modified:
    cfe/cfe/trunk/AST/Expr.cpp
    cfe/cfe/trunk/AST/Sema.h
    cfe/cfe/trunk/AST/SemaExpr.cpp
    cfe/cfe/trunk/Driver/clang.cpp
    cfe/cfe/trunk/Sema/Sema.h
    cfe/cfe/trunk/Sema/SemaExpr.cpp
    cfe/cfe/trunk/include/clang/AST/Expr.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=39432&r1=39431&r2=39432&view=diff

==============================================================================
--- cfe/cfe/trunk/AST/Expr.cpp (original)
+++ cfe/cfe/trunk/AST/Expr.cpp Wed Jul 11 11:44:19 2007
@@ -118,7 +118,7 @@
   }
 }
 
-/// Expressions that can be lvalues:
+/// Nonarray expressions that can be lvalues:
 ///  - name, where name must be a variable
 ///  - e[i]
 ///  - (e), where e must be an lvalue
@@ -127,7 +127,7 @@
 ///  - *e
 ///  - string-constant
 ///
-bool Expr::isLvalue() {
+bool Expr::isModifiableLvalue() {
   switch (getStmtClass()) {
   case StringLiteralClass:
     return true;
@@ -135,19 +135,20 @@
     return true;
   case DeclRefExprClass:
     const DeclRefExpr *d = cast<DeclRefExpr>(this);
-    if (isa<VarDecl>(d->getDecl()))
-      return true;
+    if (const VarDecl *vd = dyn_cast<VarDecl>(d->getDecl()))
+      if (vd->getType().isModifiableLvalue())
+        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
+    return m->getBase()->isModifiableLvalue(); // make sure "." is an lvalue
   case UnaryOperatorClass:
     const UnaryOperator *u = cast<UnaryOperator>(this);
     return u->getOpcode() == UnaryOperator::Deref;
   case ParenExprClass:
-    return cast<ParenExpr>(this)->getSubExpr()->isLvalue();
+    return cast<ParenExpr>(this)->getSubExpr()->isModifiableLvalue();
   default: 
     return false;
   }

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

==============================================================================
--- cfe/cfe/trunk/AST/Sema.h (original)
+++ cfe/cfe/trunk/AST/Sema.h Wed Jul 11 11:44:19 2007
@@ -226,9 +226,16 @@
   QualType UsualUnaryConversion(QualType t); // C99 6.3
   QualType UsualArithmeticConversions(QualType t1, QualType t2); // C99 6.3.1.8
   
+  enum AssignmentConversionResult {
+    Compatible,
+    Incompatible,
+    PointerFromInt, 
+    IntFromPointer,
+    IncompatiblePointer
+  };
   // Conversions for assignment, argument passing, initialization, or return
-  QualType UsualAssignmentConversions(QualType lhs, QualType rhs, // C99 6.5.16
-                                      Expr *rex, SourceLocation loc); 
+  QualType UsualAssignmentConversions(QualType lhs, Expr *rex, // C99 6.5.16
+                                      AssignmentConversionResult &r); 
   
   /// the following "Check" methods will either return a well formed AST node
   /// or will return true if the expressions didn't type check properly.

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

==============================================================================
--- cfe/cfe/trunk/AST/SemaExpr.cpp (original)
+++ cfe/cfe/trunk/AST/SemaExpr.cpp Wed Jul 11 11:44:19 2007
@@ -22,6 +22,7 @@
 #include "clang/Basic/LangOptions.h"
 #include "clang/Basic/TargetInfo.h"
 #include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringExtras.h"
 using namespace llvm;
 using namespace clang;
 
@@ -336,17 +337,59 @@
 
   assert(!qType.isNull() && "no type for function call expression");
 
-  QualType canonType = qType.getCanonicalType();
-  QualType resultType;
+  const FunctionType *funcT = dyn_cast<FunctionType>(qType.getCanonicalType());
   
-  if (const FunctionType *funcT = dyn_cast<FunctionType>(canonType)) {
-    resultType = funcT->getResultType();
+  assert(funcT && "ParseCallExpr(): not a function type");
+  
+  // If a prototype isn't declared, the parser implicitly defines a func decl
+  QualType resultType = funcT->getResultType();
+    
+  if (const FunctionTypeProto *proto = dyn_cast<FunctionTypeProto>(funcT)) {
+    // C99 6.5.2.2p7 - the arguments are implicitly converted, as if by 
+    // assignment, to the types of the corresponding parameter, ...
+    
+    unsigned NumArgsInProto = proto->getNumArgs();
+    unsigned n = NumArgs;
+    
+    if (NumArgs < NumArgsInProto)
+      Diag(LParenLoc, diag::ext_typecheck_call_too_few_args);
+    else if (NumArgs > NumArgsInProto) { // FIXME: check isVariadic()...
+      Diag(LParenLoc, diag::ext_typecheck_call_too_many_args);
+      n = NumArgsInProto;
+    }
+    // Continue to check argument types (even if we have too few/many args).
+    for (unsigned i = 0; i < n; i++) {
+      QualType lhsType = proto->getArgType(i);
+      QualType rhsType = ((Expr **)Args)[i]->getType();
+      
+      if (lhsType == rhsType) // common case, fast path...
+        continue;
+      AssignmentConversionResult result;
+      UsualAssignmentConversions(lhsType, ((Expr **)Args)[i], result);
+
+      SourceLocation l = (i == 0) ? LParenLoc : CommaLocs[i-1];
+
+      // decode the result (notice that AST's are still created for extensions).
+      // FIXME: consider fancier error diagnostics (since this is quite common).
+      // #1: emit the actual prototype arg...requires adding source loc info.
+      // #2: pass Diag the offending argument type...requires hacking Diag.
+      switch (result) {
+      case Compatible:
+        break;
+      case PointerFromInt:
+        Diag(l, diag::ext_typecheck_passing_pointer_from_int, utostr(i+1));
+        break;
+      case IntFromPointer:
+        Diag(l, diag::ext_typecheck_passing_int_from_pointer, utostr(i+1));
+        break;
+      case IncompatiblePointer:
+        Diag(l, diag::ext_typecheck_passing_incompatible_pointer, utostr(i+1));
+        break;
+      case Incompatible:
+        return Diag(l, diag::err_typecheck_passing_incompatible, utostr(i+1));
+      }
+    }
   }
-  // C99 6.5.2.2p7 - If we have a prototype, the arguments are implicitly
-  // converted, as if by assignment, to the types of the corresponding
-  // parameters, taking the type of each parameter to be the unqualified...
-  //
-  // QualType result = UsualAssignmentConversions(lhsType, rhsType, rex, loc);
   return new CallExpr((Expr*)Fn, (Expr**)Args, NumArgs, resultType);
 }
 
@@ -502,8 +545,27 @@
   return Context.maxIntegerType(lhs, rhs);
 }
 
-QualType Sema::UsualAssignmentConversions(QualType lhsType, QualType rhsType,
-                                          Expr *rex, SourceLocation loc) {
+/// UsualAssignmentConversions (C99 6.5.16) - This routine currently 
+/// has code to accommodate several GCC extensions when type checking 
+/// pointers. Here are some objectionable examples that GCC considers warnings:
+///
+///  int a, *pint;
+///  short *pshort;
+///  struct foo *pfoo;
+///
+///  pint = pshort; // warning: assignment from incompatible pointer type
+///  a = pint; // warning: assignment makes integer from pointer without a cast
+///  pint = a; // warning: assignment makes pointer from integer without a cast
+///  pint = pfoo; // warning: assignment from incompatible pointer type
+///
+/// As a result, the code for dealing with pointers is more complex than the
+/// C99 spec dictates. 
+/// Note: the warning above turn into errors when -pedantic-errors is enabled. 
+///
+QualType Sema::UsualAssignmentConversions(QualType lhsType, Expr *rex,
+                                          AssignmentConversionResult &r) {
+  QualType rhsType = rex->getType();
+  
   // this check seems unnatural, however it necessary to insure the proper
   // conversion of functions/arrays. If the conversion where done for all
   // DeclExpr's (created by ParseIdentifierExpr), it would mess up the
@@ -511,6 +573,7 @@
   if (rhsType->isFunctionType() || rhsType->isArrayType())
     rhsType = UsualUnaryConversion(rhsType);
     
+  r = Compatible;
   if (lhsType->isArithmeticType() && rhsType->isArithmeticType())
     return lhsType;
   else if (lhsType->isPointerType()) {
@@ -518,20 +581,20 @@
       // check for null pointer constant (C99 6.3.2.3p3)
       const IntegerLiteral *constant = dyn_cast<IntegerLiteral>(rex);
       if (!constant || constant->getValue() != 0)
-        Diag(loc, diag::ext_typecheck_assign_pointer_from_int);
+        r = PointerFromInt;
       return rhsType;
     }
     // FIXME: make sure the qualifier are matching
     if (rhsType->isPointerType()) { 
       if (!Type::pointerTypesAreCompatible(lhsType, rhsType))
-        Diag(loc, diag::ext_typecheck_assign_incompatible_pointer);
+        r = IncompatiblePointer;
       return rhsType;
     }
   } else if (rhsType->isPointerType()) {
     if (lhsType->isIntegerType()) {
       // C99 6.5.16.1p1: the left operand is _Bool and the right is a pointer.
       if (lhsType != Context.BoolTy)
-        Diag(loc, diag::ext_typecheck_assign_int_from_pointer);
+        r = IntFromPointer;
       return rhsType;
     }
     // - both operands are pointers to qualified or unqualified versions of
@@ -539,7 +602,7 @@
     // qualifiers of the type pointed to by the right;
     if (lhsType->isPointerType()) {
       if (!Type::pointerTypesAreCompatible(lhsType, rhsType))
-        Diag(loc, diag::ext_typecheck_assign_incompatible_pointer);
+        r = IncompatiblePointer;
       return rhsType;
     }
   } else if (lhsType->isStructureType() && rhsType->isStructureType()) {
@@ -549,7 +612,8 @@
     if (Type::unionTypesAreCompatible(lhsType, rhsType))
       return rhsType;
   }
-  return QualType(); // incompatible
+  r = Incompatible;
+  return QualType();
 }
 
 Action::ExprResult Sema::CheckMultiplicativeOperands(
@@ -656,23 +720,6 @@
   return new BinaryOperator(lex, rex, (BOP)code, Context.IntTy);
 }
 
-/// CheckAssignmentOperands (C99 6.5.16) - This routine currently 
-/// has code to accommodate several GCC extensions when type checking 
-/// pointers. Here are some objectionable examples that GCC considers warnings:
-///
-///  int a, *pint;
-///  short *pshort;
-///  struct foo *pfoo;
-///
-///  pint = pshort; // warning: assignment from incompatible pointer type
-///  a = pint; // warning: assignment makes integer from pointer without a cast
-///  pint = a; // warning: assignment makes pointer from integer without a cast
-///  pint = pfoo; // warning: assignment from incompatible pointer type
-///
-/// As a result, the code for dealing with pointers is more complex than the
-/// C99 spec dictates. 
-/// Note: the warning above turn into errors when -pedantic-errors is enabled. 
-///
 Action::ExprResult Sema::CheckAssignmentOperands( 
   Expr *lex, Expr *rex, SourceLocation loc, unsigned code) 
 {
@@ -680,19 +727,39 @@
   QualType rhsType = rex->getType();
   
   if ((BOP)code == BinaryOperator::Assign) { // C99 6.5.16.1
-    if (!lex->isLvalue())
-      return Diag(loc, diag::ext_typecheck_assign_non_lvalue);
-    if (lhsType.isConstQualified())
+    // FIXME: consider hacking isModifiableLvalue to return an enum that
+    // communicates why the expression/type wasn't a modifiableLvalue.
+    
+    // this check is done first to give a more precise diagnostic.
+    if (lhsType.isConstQualified()) 
       return Diag(loc, diag::err_typecheck_assign_const);
+
+    if (!lex->isModifiableLvalue()) // this includes checking for "const"
+      return Diag(loc, diag::ext_typecheck_assign_non_lvalue);
       
     if (lhsType == rhsType) // common case, fast path...
       return new BinaryOperator(lex, rex, (BOP)code, lhsType);
-      
-    QualType result = UsualAssignmentConversions(lhsType, rhsType, rex, loc);
-    if (result.isNull())
+    
+    AssignmentConversionResult result;
+    QualType resType = UsualAssignmentConversions(lhsType, rex, result);
+
+    // decode the result (notice that AST's are still created for extensions).
+    switch (result) {
+    case Compatible:
+      break;
+    case PointerFromInt:
+      Diag(loc, diag::ext_typecheck_assign_pointer_from_int);
+      break;
+    case IntFromPointer:
+      Diag(loc, diag::ext_typecheck_assign_int_from_pointer);
+      break;
+    case IncompatiblePointer:
+      Diag(loc, diag::ext_typecheck_assign_incompatible_pointer);
+      break;
+    case Incompatible:
       return Diag(loc, diag::err_typecheck_assign_incompatible);
-    else
-      return new BinaryOperator(lex, rex, (BOP)code, result);
+    }
+    return new BinaryOperator(lex, rex, (BOP)code, resType);
   }
   // FIXME: type check compound assignments...
   return new BinaryOperator(lex, rex, (BOP)code, Context.IntTy);
@@ -763,7 +830,7 @@
 Sema::CheckAddressOfOperand(Expr *op, SourceLocation OpLoc) {
   Decl *dcl = getPrimaryDeclaration(op);
   
-  if (!op->isLvalue()) {
+  if (!op->isModifiableLvalue()) {
     if (dcl && isa<FunctionDecl>(dcl))
       ;  // C99 6.5.3.2p1: Allow function designators.
     else

Modified: cfe/cfe/trunk/Driver/clang.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/Driver/clang.cpp?rev=39432&r1=39431&r2=39432&view=diff

==============================================================================
--- cfe/cfe/trunk/Driver/clang.cpp (original)
+++ cfe/cfe/trunk/Driver/clang.cpp Wed Jul 11 11:44:19 2007
@@ -251,7 +251,7 @@
     case langkind_c_cpp:
     case langkind_objc:
     case langkind_objc_cpp:
-      LangStd = lang_gnu89;
+      LangStd = lang_gnu99;
       break;
     case langkind_cxx:
     case langkind_cxx_cpp:

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

==============================================================================
--- cfe/cfe/trunk/Sema/Sema.h (original)
+++ cfe/cfe/trunk/Sema/Sema.h Wed Jul 11 11:44:19 2007
@@ -226,9 +226,16 @@
   QualType UsualUnaryConversion(QualType t); // C99 6.3
   QualType UsualArithmeticConversions(QualType t1, QualType t2); // C99 6.3.1.8
   
+  enum AssignmentConversionResult {
+    Compatible,
+    Incompatible,
+    PointerFromInt, 
+    IntFromPointer,
+    IncompatiblePointer
+  };
   // Conversions for assignment, argument passing, initialization, or return
-  QualType UsualAssignmentConversions(QualType lhs, QualType rhs, // C99 6.5.16
-                                      Expr *rex, SourceLocation loc); 
+  QualType UsualAssignmentConversions(QualType lhs, Expr *rex, // C99 6.5.16
+                                      AssignmentConversionResult &r); 
   
   /// the following "Check" methods will either return a well formed AST node
   /// or will return true if the expressions didn't type check properly.

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

==============================================================================
--- cfe/cfe/trunk/Sema/SemaExpr.cpp (original)
+++ cfe/cfe/trunk/Sema/SemaExpr.cpp Wed Jul 11 11:44:19 2007
@@ -22,6 +22,7 @@
 #include "clang/Basic/LangOptions.h"
 #include "clang/Basic/TargetInfo.h"
 #include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringExtras.h"
 using namespace llvm;
 using namespace clang;
 
@@ -336,17 +337,59 @@
 
   assert(!qType.isNull() && "no type for function call expression");
 
-  QualType canonType = qType.getCanonicalType();
-  QualType resultType;
+  const FunctionType *funcT = dyn_cast<FunctionType>(qType.getCanonicalType());
   
-  if (const FunctionType *funcT = dyn_cast<FunctionType>(canonType)) {
-    resultType = funcT->getResultType();
+  assert(funcT && "ParseCallExpr(): not a function type");
+  
+  // If a prototype isn't declared, the parser implicitly defines a func decl
+  QualType resultType = funcT->getResultType();
+    
+  if (const FunctionTypeProto *proto = dyn_cast<FunctionTypeProto>(funcT)) {
+    // C99 6.5.2.2p7 - the arguments are implicitly converted, as if by 
+    // assignment, to the types of the corresponding parameter, ...
+    
+    unsigned NumArgsInProto = proto->getNumArgs();
+    unsigned n = NumArgs;
+    
+    if (NumArgs < NumArgsInProto)
+      Diag(LParenLoc, diag::ext_typecheck_call_too_few_args);
+    else if (NumArgs > NumArgsInProto) { // FIXME: check isVariadic()...
+      Diag(LParenLoc, diag::ext_typecheck_call_too_many_args);
+      n = NumArgsInProto;
+    }
+    // Continue to check argument types (even if we have too few/many args).
+    for (unsigned i = 0; i < n; i++) {
+      QualType lhsType = proto->getArgType(i);
+      QualType rhsType = ((Expr **)Args)[i]->getType();
+      
+      if (lhsType == rhsType) // common case, fast path...
+        continue;
+      AssignmentConversionResult result;
+      UsualAssignmentConversions(lhsType, ((Expr **)Args)[i], result);
+
+      SourceLocation l = (i == 0) ? LParenLoc : CommaLocs[i-1];
+
+      // decode the result (notice that AST's are still created for extensions).
+      // FIXME: consider fancier error diagnostics (since this is quite common).
+      // #1: emit the actual prototype arg...requires adding source loc info.
+      // #2: pass Diag the offending argument type...requires hacking Diag.
+      switch (result) {
+      case Compatible:
+        break;
+      case PointerFromInt:
+        Diag(l, diag::ext_typecheck_passing_pointer_from_int, utostr(i+1));
+        break;
+      case IntFromPointer:
+        Diag(l, diag::ext_typecheck_passing_int_from_pointer, utostr(i+1));
+        break;
+      case IncompatiblePointer:
+        Diag(l, diag::ext_typecheck_passing_incompatible_pointer, utostr(i+1));
+        break;
+      case Incompatible:
+        return Diag(l, diag::err_typecheck_passing_incompatible, utostr(i+1));
+      }
+    }
   }
-  // C99 6.5.2.2p7 - If we have a prototype, the arguments are implicitly
-  // converted, as if by assignment, to the types of the corresponding
-  // parameters, taking the type of each parameter to be the unqualified...
-  //
-  // QualType result = UsualAssignmentConversions(lhsType, rhsType, rex, loc);
   return new CallExpr((Expr*)Fn, (Expr**)Args, NumArgs, resultType);
 }
 
@@ -502,8 +545,27 @@
   return Context.maxIntegerType(lhs, rhs);
 }
 
-QualType Sema::UsualAssignmentConversions(QualType lhsType, QualType rhsType,
-                                          Expr *rex, SourceLocation loc) {
+/// UsualAssignmentConversions (C99 6.5.16) - This routine currently 
+/// has code to accommodate several GCC extensions when type checking 
+/// pointers. Here are some objectionable examples that GCC considers warnings:
+///
+///  int a, *pint;
+///  short *pshort;
+///  struct foo *pfoo;
+///
+///  pint = pshort; // warning: assignment from incompatible pointer type
+///  a = pint; // warning: assignment makes integer from pointer without a cast
+///  pint = a; // warning: assignment makes pointer from integer without a cast
+///  pint = pfoo; // warning: assignment from incompatible pointer type
+///
+/// As a result, the code for dealing with pointers is more complex than the
+/// C99 spec dictates. 
+/// Note: the warning above turn into errors when -pedantic-errors is enabled. 
+///
+QualType Sema::UsualAssignmentConversions(QualType lhsType, Expr *rex,
+                                          AssignmentConversionResult &r) {
+  QualType rhsType = rex->getType();
+  
   // this check seems unnatural, however it necessary to insure the proper
   // conversion of functions/arrays. If the conversion where done for all
   // DeclExpr's (created by ParseIdentifierExpr), it would mess up the
@@ -511,6 +573,7 @@
   if (rhsType->isFunctionType() || rhsType->isArrayType())
     rhsType = UsualUnaryConversion(rhsType);
     
+  r = Compatible;
   if (lhsType->isArithmeticType() && rhsType->isArithmeticType())
     return lhsType;
   else if (lhsType->isPointerType()) {
@@ -518,20 +581,20 @@
       // check for null pointer constant (C99 6.3.2.3p3)
       const IntegerLiteral *constant = dyn_cast<IntegerLiteral>(rex);
       if (!constant || constant->getValue() != 0)
-        Diag(loc, diag::ext_typecheck_assign_pointer_from_int);
+        r = PointerFromInt;
       return rhsType;
     }
     // FIXME: make sure the qualifier are matching
     if (rhsType->isPointerType()) { 
       if (!Type::pointerTypesAreCompatible(lhsType, rhsType))
-        Diag(loc, diag::ext_typecheck_assign_incompatible_pointer);
+        r = IncompatiblePointer;
       return rhsType;
     }
   } else if (rhsType->isPointerType()) {
     if (lhsType->isIntegerType()) {
       // C99 6.5.16.1p1: the left operand is _Bool and the right is a pointer.
       if (lhsType != Context.BoolTy)
-        Diag(loc, diag::ext_typecheck_assign_int_from_pointer);
+        r = IntFromPointer;
       return rhsType;
     }
     // - both operands are pointers to qualified or unqualified versions of
@@ -539,7 +602,7 @@
     // qualifiers of the type pointed to by the right;
     if (lhsType->isPointerType()) {
       if (!Type::pointerTypesAreCompatible(lhsType, rhsType))
-        Diag(loc, diag::ext_typecheck_assign_incompatible_pointer);
+        r = IncompatiblePointer;
       return rhsType;
     }
   } else if (lhsType->isStructureType() && rhsType->isStructureType()) {
@@ -549,7 +612,8 @@
     if (Type::unionTypesAreCompatible(lhsType, rhsType))
       return rhsType;
   }
-  return QualType(); // incompatible
+  r = Incompatible;
+  return QualType();
 }
 
 Action::ExprResult Sema::CheckMultiplicativeOperands(
@@ -656,23 +720,6 @@
   return new BinaryOperator(lex, rex, (BOP)code, Context.IntTy);
 }
 
-/// CheckAssignmentOperands (C99 6.5.16) - This routine currently 
-/// has code to accommodate several GCC extensions when type checking 
-/// pointers. Here are some objectionable examples that GCC considers warnings:
-///
-///  int a, *pint;
-///  short *pshort;
-///  struct foo *pfoo;
-///
-///  pint = pshort; // warning: assignment from incompatible pointer type
-///  a = pint; // warning: assignment makes integer from pointer without a cast
-///  pint = a; // warning: assignment makes pointer from integer without a cast
-///  pint = pfoo; // warning: assignment from incompatible pointer type
-///
-/// As a result, the code for dealing with pointers is more complex than the
-/// C99 spec dictates. 
-/// Note: the warning above turn into errors when -pedantic-errors is enabled. 
-///
 Action::ExprResult Sema::CheckAssignmentOperands( 
   Expr *lex, Expr *rex, SourceLocation loc, unsigned code) 
 {
@@ -680,19 +727,39 @@
   QualType rhsType = rex->getType();
   
   if ((BOP)code == BinaryOperator::Assign) { // C99 6.5.16.1
-    if (!lex->isLvalue())
-      return Diag(loc, diag::ext_typecheck_assign_non_lvalue);
-    if (lhsType.isConstQualified())
+    // FIXME: consider hacking isModifiableLvalue to return an enum that
+    // communicates why the expression/type wasn't a modifiableLvalue.
+    
+    // this check is done first to give a more precise diagnostic.
+    if (lhsType.isConstQualified()) 
       return Diag(loc, diag::err_typecheck_assign_const);
+
+    if (!lex->isModifiableLvalue()) // this includes checking for "const"
+      return Diag(loc, diag::ext_typecheck_assign_non_lvalue);
       
     if (lhsType == rhsType) // common case, fast path...
       return new BinaryOperator(lex, rex, (BOP)code, lhsType);
-      
-    QualType result = UsualAssignmentConversions(lhsType, rhsType, rex, loc);
-    if (result.isNull())
+    
+    AssignmentConversionResult result;
+    QualType resType = UsualAssignmentConversions(lhsType, rex, result);
+
+    // decode the result (notice that AST's are still created for extensions).
+    switch (result) {
+    case Compatible:
+      break;
+    case PointerFromInt:
+      Diag(loc, diag::ext_typecheck_assign_pointer_from_int);
+      break;
+    case IntFromPointer:
+      Diag(loc, diag::ext_typecheck_assign_int_from_pointer);
+      break;
+    case IncompatiblePointer:
+      Diag(loc, diag::ext_typecheck_assign_incompatible_pointer);
+      break;
+    case Incompatible:
       return Diag(loc, diag::err_typecheck_assign_incompatible);
-    else
-      return new BinaryOperator(lex, rex, (BOP)code, result);
+    }
+    return new BinaryOperator(lex, rex, (BOP)code, resType);
   }
   // FIXME: type check compound assignments...
   return new BinaryOperator(lex, rex, (BOP)code, Context.IntTy);
@@ -763,7 +830,7 @@
 Sema::CheckAddressOfOperand(Expr *op, SourceLocation OpLoc) {
   Decl *dcl = getPrimaryDeclaration(op);
   
-  if (!op->isLvalue()) {
+  if (!op->isModifiableLvalue()) {
     if (dcl && isa<FunctionDecl>(dcl))
       ;  // C99 6.5.3.2p1: Allow function designators.
     else

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=39432&r1=39431&r2=39432&view=diff

==============================================================================
--- cfe/cfe/trunk/include/clang/AST/Expr.h (original)
+++ cfe/cfe/trunk/include/clang/AST/Expr.h Wed Jul 11 11:44:19 2007
@@ -35,7 +35,7 @@
 public:  
   QualType getType() const { return TR; }
   
-  /// isLvalue - return true if the expression is one of the following:
+  /// isModifiableLvalue - 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
@@ -44,7 +44,7 @@
   ///  - *e
   ///  - string-constant
   ///
-  bool isLvalue();
+  bool isModifiableLvalue();
   
   virtual void visit(StmtVisitor &Visitor);
   static bool classof(const Stmt *T) { 

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=39432&r1=39431&r2=39432&view=diff

==============================================================================
--- cfe/cfe/trunk/include/clang/Basic/DiagnosticKinds.def (original)
+++ cfe/cfe/trunk/include/clang/Basic/DiagnosticKinds.def Wed Jul 11 11:44:19 2007
@@ -552,7 +552,19 @@
 DIAG(ext_typecheck_assign_incompatible_pointer, EXTENSION,
      "assignment from incompatible pointer type")
 DIAG(ext_typecheck_assign_non_lvalue, ERROR,
-     "assignment to non-lvalue")
+     "invalid lvalue in assignment")
+DIAG(ext_typecheck_call_too_few_args, ERROR,
+     "too few arguments to function")
+DIAG(ext_typecheck_call_too_many_args, ERROR,
+     "too many arguments to function")
+DIAG(err_typecheck_passing_incompatible, ERROR,
+     "incompatible type for argument %s")
+DIAG(ext_typecheck_passing_int_from_pointer, EXTENSION,
+     "passing argument %s makes integer from pointer without a cast")
+DIAG(ext_typecheck_passing_pointer_from_int, EXTENSION,
+     "passing argument %s makes pointer from integer without a cast")
+DIAG(ext_typecheck_passing_incompatible_pointer, EXTENSION,
+     "passing argument %s from incompatible pointer type")
 
 // Statements.
 DIAG(err_continue_not_in_loop, ERROR,





More information about the cfe-commits mailing list