[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