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).

llvm-svn: 39432
This commit is contained in:
Steve Naroff 2007-05-03 21:03:48 +00:00
parent b891de392c
commit 17f76e04d2
8 changed files with 259 additions and 98 deletions

View File

@ -118,7 +118,7 @@ const char *BinaryOperator::getOpcodeStr(Opcode Op) {
}
}
/// 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 @@ const char *BinaryOperator::getOpcodeStr(Opcode Op) {
/// - *e
/// - string-constant
///
bool Expr::isLvalue() {
bool Expr::isModifiableLvalue() {
switch (getStmtClass()) {
case StringLiteralClass:
return true;
@ -135,19 +135,20 @@ bool Expr::isLvalue() {
return true;
case DeclRefExprClass:
const DeclRefExpr *d = cast<DeclRefExpr>(this);
if (isa<VarDecl>(d->getDecl()))
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;
}

View File

@ -226,9 +226,16 @@ private:
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.

View File

@ -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 @@ ParseCallExpr(ExprTy *Fn, SourceLocation LParenLoc,
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 @@ QualType Sema::UsualArithmeticConversions(QualType t1, QualType t2) {
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 @@ QualType Sema::UsualAssignmentConversions(QualType lhsType, QualType rhsType,
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 @@ QualType Sema::UsualAssignmentConversions(QualType lhsType, QualType rhsType,
// 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 @@ QualType Sema::UsualAssignmentConversions(QualType lhsType, QualType rhsType,
// 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 @@ QualType Sema::UsualAssignmentConversions(QualType lhsType, QualType rhsType,
if (Type::unionTypesAreCompatible(lhsType, rhsType))
return rhsType;
}
return QualType(); // incompatible
r = Incompatible;
return QualType();
}
Action::ExprResult Sema::CheckMultiplicativeOperands(
@ -656,23 +720,6 @@ Action::ExprResult Sema::CheckLogicalOperands( // C99 6.5.[13,14]
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 @@ Action::ExprResult Sema::CheckAssignmentOperands(
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);
// 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 @@ Action::ExprResult
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

View File

@ -251,7 +251,7 @@ static void InitializeLanguageStandard(LangOptions &Options) {
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:

View File

@ -226,9 +226,16 @@ private:
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.

View File

@ -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 @@ ParseCallExpr(ExprTy *Fn, SourceLocation LParenLoc,
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 @@ QualType Sema::UsualArithmeticConversions(QualType t1, QualType t2) {
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 @@ QualType Sema::UsualAssignmentConversions(QualType lhsType, QualType rhsType,
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 @@ QualType Sema::UsualAssignmentConversions(QualType lhsType, QualType rhsType,
// 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 @@ QualType Sema::UsualAssignmentConversions(QualType lhsType, QualType rhsType,
// 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 @@ QualType Sema::UsualAssignmentConversions(QualType lhsType, QualType rhsType,
if (Type::unionTypesAreCompatible(lhsType, rhsType))
return rhsType;
}
return QualType(); // incompatible
r = Incompatible;
return QualType();
}
Action::ExprResult Sema::CheckMultiplicativeOperands(
@ -656,23 +720,6 @@ Action::ExprResult Sema::CheckLogicalOperands( // C99 6.5.[13,14]
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 @@ Action::ExprResult Sema::CheckAssignmentOperands(
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);
// 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 @@ Action::ExprResult
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

View File

@ -35,7 +35,7 @@ protected:
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 @@ public:
/// - *e
/// - string-constant
///
bool isLvalue();
bool isModifiableLvalue();
virtual void visit(StmtVisitor &Visitor);
static bool classof(const Stmt *T) {

View File

@ -552,7 +552,19 @@ DIAG(ext_typecheck_assign_pointer_from_int, EXTENSION,
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,