[cfe-commits] r39501 - in /cfe/cfe/trunk: AST/Expr.cpp Sema/Sema.h Sema/SemaExpr.cpp Sema/SemaStmt.cpp clang.xcodeproj/project.pbxproj include/clang/AST/Decl.h include/clang/AST/Expr.h include/clang/AST/Type.h include/clang/Basic/DiagnosticKinds.def
Steve Naroff
snaroff at apple.com
Wed Jul 11 09:45:02 PDT 2007
Author: snaroff
Date: Wed Jul 11 11:45:02 2007
New Revision: 39501
URL: http://llvm.org/viewvc/llvm-project?rev=39501&view=rev
Log:
Bug #:
Submitted by:
Reviewed by:
- Added type checking to Sema::ParseReturnStmt (still under construction).
- Improved Expr::isLvalue() and Expr::isModifiableLvalue() to return more
info. Used the info in Sema::CheckAssignmentOperands() to produce more
descriptive diagnostics. Added FIXME to other clients of isLvalue()/etc.
- Added a SourceLocation slot to MemberExpr...changed the implementation
of getSourceRange().
- Added getResultType() helper to FunctionDecl.
- Changed many Diag calls to use the SourceRange support (now that it's
a big hit...we better milk it:-).
Modified:
cfe/cfe/trunk/AST/Expr.cpp
cfe/cfe/trunk/Sema/Sema.h
cfe/cfe/trunk/Sema/SemaExpr.cpp
cfe/cfe/trunk/Sema/SemaStmt.cpp
cfe/cfe/trunk/clang.xcodeproj/project.pbxproj
cfe/cfe/trunk/include/clang/AST/Decl.h
cfe/cfe/trunk/include/clang/AST/Expr.h
cfe/cfe/trunk/include/clang/AST/Type.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=39501&r1=39500&r2=39501&view=diff
==============================================================================
--- cfe/cfe/trunk/AST/Expr.cpp (original)
+++ cfe/cfe/trunk/AST/Expr.cpp Wed Jul 11 11:45:02 2007
@@ -133,31 +133,35 @@
/// - *e, the type of e cannot be a function type
/// - string-constant
///
-bool Expr::isLvalue() {
+Expr::isLvalueResult Expr::isLvalue() {
// first, check the type (C99 6.3.2.1)
- if (!TR->isObjectType())
- return false;
+ if (isa<FunctionType>(TR.getCanonicalType())) // from isObjectType()
+ return LV_NotObjectType;
if (TR->isIncompleteType() && TR->isVoidType())
- return false;
+ return LV_IncompleteVoidType;
// the type looks fine, now check the expression
switch (getStmtClass()) {
case StringLiteralClass: // C99 6.5.1p4
- return true;
case ArraySubscriptExprClass: // C99 6.5.3p4 (e1[e2] == (*((e1)+(e2))))
- return true;
+ return LV_Valid;
case DeclRefExprClass: // C99 6.5.1p2
- return isa<VarDecl>(cast<DeclRefExpr>(this)->getDecl());
+ if (isa<VarDecl>(cast<DeclRefExpr>(this)->getDecl()))
+ return LV_Valid;
+ break;
case MemberExprClass: // C99 6.5.2.3p4
const MemberExpr *m = cast<MemberExpr>(this);
- return m->isArrow() ? true : m->getBase()->isLvalue();
+ return m->isArrow() ? LV_Valid : m->getBase()->isLvalue();
case UnaryOperatorClass: // C99 6.5.3p4
- return cast<UnaryOperator>(this)->getOpcode() == UnaryOperator::Deref;
+ if (cast<UnaryOperator>(this)->getOpcode() == UnaryOperator::Deref)
+ return LV_Valid;
+ break;
case ParenExprClass: // C99 6.5.1p5
return cast<ParenExpr>(this)->getSubExpr()->isLvalue();
- default:
- return false;
+ default:
+ break;
}
+ return LV_InvalidExpression;
}
/// isModifiableLvalue - C99 6.3.2.1: an lvalue that does not have array type,
@@ -165,19 +169,27 @@
/// if it is a structure or union, does not have any member (including,
/// recursively, any member or element of all contained aggregates or unions)
/// with a const-qualified type.
-bool Expr::isModifiableLvalue() {
- if (!isLvalue())
- return false;
-
+Expr::isModifiableLvalueResult Expr::isModifiableLvalue() {
+ isLvalueResult lvalResult = isLvalue();
+
+ switch (lvalResult) {
+ case LV_Valid: break;
+ case LV_NotObjectType: return MLV_NotObjectType;
+ case LV_IncompleteVoidType: return MLV_IncompleteVoidType;
+ case LV_InvalidExpression: return MLV_InvalidExpression;
+ }
if (TR.isConstQualified())
- return false;
+ return MLV_ConstQualified;
if (TR->isArrayType())
- return false;
+ return MLV_ArrayType;
if (TR->isIncompleteType())
- return false;
- if (const RecordType *r = dyn_cast<RecordType>(TR.getCanonicalType()))
- return r->isModifiableLvalue();
- return true;
+ return MLV_IncompleteType;
+
+ if (const RecordType *r = dyn_cast<RecordType>(TR.getCanonicalType())) {
+ if (r->hasConstFields())
+ return MLV_ConstQualified;
+ }
+ return MLV_Valid;
}
/// isConstantExpr - this recursive routine will test if an expression is
Modified: cfe/cfe/trunk/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/Sema/Sema.h?rev=39501&r1=39500&r2=39501&view=diff
==============================================================================
--- cfe/cfe/trunk/Sema/Sema.h (original)
+++ cfe/cfe/trunk/Sema/Sema.h Wed Jul 11 11:45:02 2007
@@ -292,7 +292,7 @@
Expr *cond, Expr *lhs, Expr *rhs, SourceLocation questionLoc);
/// type checking unary operators (subroutines of ParseUnaryOp).
- // C99 6.5.3.1, 6.5.3.2, 6.5.3.4
+ /// C99 6.5.3.1, 6.5.3.2, 6.5.3.4
QualType CheckIncrementDecrementOperand(Expr *op, SourceLocation OpLoc);
QualType CheckAddressOfOperand(Expr *op, SourceLocation OpLoc);
QualType CheckIndirectionOperand(Expr *op, SourceLocation OpLoc);
Modified: cfe/cfe/trunk/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/Sema/SemaExpr.cpp?rev=39501&r1=39500&r2=39501&view=diff
==============================================================================
--- cfe/cfe/trunk/Sema/SemaExpr.cpp (original)
+++ cfe/cfe/trunk/Sema/SemaExpr.cpp Wed Jul 11 11:45:02 2007
@@ -352,7 +352,8 @@
if (!MemberDecl)
return Diag(OpLoc, diag::err_typecheck_no_member, Member.getName());
- return new MemberExpr((Expr*)Base, OpKind == tok::arrow, MemberDecl);
+ return new MemberExpr((Expr*)Base, OpKind == tok::arrow,
+ MemberDecl, MemberLoc);
}
/// ParseCallExpr - Handle a call to Fn with the specified array of arguments.
@@ -835,15 +836,32 @@
QualType lhsType = lex->getType();
QualType rhsType = compoundType.isNull() ? rex->getType() : compoundType;
bool hadError = false;
-
- // this check is done first to give a more precise diagnostic.
- // isModifiableLvalue() will also check for "const".
- if (lhsType.isConstQualified()) {
- Diag(loc, diag::err_typecheck_assign_const, lex->getSourceRange());
- hadError = true;
- } else if (!lex->isModifiableLvalue()) { // C99 6.5.16p2
- Diag(loc, diag::err_typecheck_assign_non_lvalue, lex->getSourceRange());
- return QualType(); // no need to continue checking...
+ Expr::isModifiableLvalueResult mlval = lex->isModifiableLvalue();
+
+ switch (mlval) { // C99 6.5.16p2
+ case Expr::MLV_Valid:
+ break;
+ case Expr::MLV_ConstQualified:
+ Diag(loc, diag::err_typecheck_assign_const, lex->getSourceRange());
+ hadError = true;
+ break;
+ case Expr::MLV_ArrayType:
+ Diag(loc, diag::err_typecheck_array_not_modifiable_lvalue,
+ lhsType.getAsString(), lex->getSourceRange());
+ return QualType();
+ case Expr::MLV_NotObjectType:
+ Diag(loc, diag::err_typecheck_non_object_not_modifiable_lvalue,
+ lhsType.getAsString(), lex->getSourceRange());
+ return QualType();
+ case Expr::MLV_InvalidExpression:
+ Diag(loc, diag::err_typecheck_expression_not_modifiable_lvalue,
+ lex->getSourceRange());
+ return QualType();
+ case Expr::MLV_IncompleteType:
+ case Expr::MLV_IncompleteVoidType:
+ Diag(loc, diag::err_typecheck_incomplete_type_not_modifiable_lvalue,
+ lhsType.getAsString(), lex->getSourceRange());
+ return QualType();
}
if (lhsType == rhsType) // common case, fast path...
return lhsType;
@@ -864,16 +882,22 @@
case PointerFromInt:
// check for null pointer constant (C99 6.3.2.3p3)
if (compoundType.isNull() && !rex->isNullPointerConstant())
- Diag(loc, diag::ext_typecheck_assign_pointer_from_int);
+ Diag(loc, diag::ext_typecheck_assign_pointer_from_int,
+ lex->getSourceRange(), rex->getSourceRange());
break;
case IntFromPointer:
- Diag(loc, diag::ext_typecheck_assign_int_from_pointer);
+ Diag(loc, diag::ext_typecheck_assign_int_from_pointer,
+ lex->getSourceRange(), rex->getSourceRange());
break;
case IncompatiblePointer:
- Diag(loc, diag::ext_typecheck_assign_incompatible_pointer);
+ Diag(loc, diag::ext_typecheck_assign_incompatible_pointer,
+ lhsType.getAsString(), rhsType.getAsString(),
+ lex->getSourceRange(), rex->getSourceRange());
break;
case CompatiblePointerDiscardsQualifiers:
- Diag(loc, diag::ext_typecheck_assign_discards_qualifiers);
+ Diag(loc, diag::ext_typecheck_assign_discards_qualifiers,
+ lhsType.getAsString(), rhsType.getAsString(),
+ lex->getSourceRange(), rex->getSourceRange());
break;
}
return hadError ? QualType() : resType;
@@ -903,7 +927,9 @@
}
// At this point, we know we have a real or pointer type. Now make sure
// the operand is a modifiable lvalue.
- if (!op->isModifiableLvalue()) {
+ Expr::isModifiableLvalueResult mlval = op->isModifiableLvalue();
+ if (mlval != Expr::MLV_Valid) {
+ // FIXME: emit a more precise diagnostic...
Diag(OpLoc, diag::err_typecheck_invalid_lvalue_incr_decr,
op->getSourceRange());
return QualType();
@@ -941,11 +967,12 @@
/// 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);
+ Expr::isLvalueResult lval = op->isLvalue();
- if (!op->isLvalue()) { // C99 6.5.3.2p1
+ if (lval != Expr::LV_Valid) { // C99 6.5.3.2p1
if (dcl && isa<FunctionDecl>(dcl)) // allow function designators
;
- else {
+ else { // FIXME: emit more specific diag...
Diag(OpLoc, diag::err_typecheck_invalid_lvalue_addrof,
op->getSourceRange());
return QualType();
@@ -973,6 +1000,7 @@
assert(!qType.isNull() && "no type for * expression");
+ // FIXME: need to check if the pointee is an incomplete type. Find spec ref.
if (PointerType *PT = dyn_cast<PointerType>(qType.getCanonicalType()))
return PT->getPointeeType();
Diag(OpLoc, diag::err_typecheck_indirection_expr, qType.getAsString(),
Modified: cfe/cfe/trunk/Sema/SemaStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/Sema/SemaStmt.cpp?rev=39501&r1=39500&r2=39501&view=diff
==============================================================================
--- cfe/cfe/trunk/Sema/SemaStmt.cpp (original)
+++ cfe/cfe/trunk/Sema/SemaStmt.cpp Wed Jul 11 11:45:02 2007
@@ -122,6 +122,54 @@
Action::StmtResult
Sema::ParseReturnStmt(SourceLocation ReturnLoc, ExprTy *RetValExp) {
+ // C99 6.8.6.4p3(136): The return statement is not an assignment. The
+ // overlap restriction of subclause 6.5.16.1 does not apply to the case of
+ // function return.
+ QualType lhsType = CurFunctionDecl->getResultType();
+
+ if (!RetValExp)
+ return new ReturnStmt((Expr*)RetValExp);
+
+ // C99 6.8.6.4p1
+ if (lhsType->isVoidType()) {
+ // a void function may not return a value
+ // non-void function "voidFunc" should return a value
+ }
+
+ QualType rhsType = ((Expr *)RetValExp)->getType();
+
+ if (lhsType == rhsType) // common case, fast path...
+ return new ReturnStmt((Expr*)RetValExp);
+
+ AssignmentConversionResult result;
+ QualType resType = UsualAssignmentConversions(lhsType, rhsType, result);
+ bool hadError = false;
+
+ // decode the result (notice that extensions still return a type).
+ switch (result) {
+ case Compatible:
+ break;
+ case Incompatible:
+ Diag(ReturnLoc, diag::err_typecheck_return_incompatible,
+ lhsType.getAsString(), rhsType.getAsString(),
+ ((Expr *)RetValExp)->getSourceRange());
+ hadError = true;
+ break;
+ case PointerFromInt:
+ // check for null pointer constant (C99 6.3.2.3p3)
+ if (!((Expr *)RetValExp)->isNullPointerConstant())
+ Diag(ReturnLoc, diag::ext_typecheck_return_pointer_from_int);
+ break;
+ case IntFromPointer:
+ Diag(ReturnLoc, diag::ext_typecheck_return_int_from_pointer);
+ break;
+ case IncompatiblePointer:
+ Diag(ReturnLoc, diag::ext_typecheck_return_incompatible_pointer);
+ break;
+ case CompatiblePointerDiscardsQualifiers:
+ Diag(ReturnLoc, diag::ext_typecheck_return_discards_qualifiers);
+ break;
+ }
return new ReturnStmt((Expr*)RetValExp);
}
Modified: cfe/cfe/trunk/clang.xcodeproj/project.pbxproj
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/clang.xcodeproj/project.pbxproj?rev=39501&r1=39500&r2=39501&view=diff
==============================================================================
--- cfe/cfe/trunk/clang.xcodeproj/project.pbxproj (original)
+++ cfe/cfe/trunk/clang.xcodeproj/project.pbxproj Wed Jul 11 11:45:02 2007
@@ -100,6 +100,23 @@
DED7D9E50A5257F6003AD0FB /* ScratchBuffer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DED7D9E40A5257F6003AD0FB /* ScratchBuffer.cpp */; };
/* End PBXBuildFile section */
+/* Begin PBXBuildStyle section */
+ 84FCE23B0C08F6EF00F0C622 /* Development */ = {
+ isa = PBXBuildStyle;
+ buildSettings = {
+ COPY_PHASE_STRIP = NO;
+ };
+ name = Development;
+ };
+ 84FCE23C0C08F6EF00F0C622 /* Deployment */ = {
+ isa = PBXBuildStyle;
+ buildSettings = {
+ COPY_PHASE_STRIP = YES;
+ };
+ name = Deployment;
+ };
+/* End PBXBuildStyle section */
+
/* Begin PBXCopyFilesBuildPhase section */
8DD76F690486A84900D96B5E /* CopyFiles */ = {
isa = PBXCopyFilesBuildPhase;
@@ -528,10 +545,15 @@
08FB7793FE84155DC02AAC07 /* Project object */ = {
isa = PBXProject;
buildConfigurationList = 1DEB923508733DC60010E9CD /* Build configuration list for PBXProject "clang" */;
+ buildSettings = {
+ };
+ buildStyles = (
+ 84FCE23B0C08F6EF00F0C622 /* Development */,
+ 84FCE23C0C08F6EF00F0C622 /* Deployment */,
+ );
hasScannedForEncodings = 1;
mainGroup = 08FB7794FE84155DC02AAC07 /* clang */;
projectDirPath = "";
- projectRoot = "";
targets = (
8DD76F620486A84900D96B5E /* clang */,
);
Modified: cfe/cfe/trunk/include/clang/AST/Decl.h
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/include/clang/AST/Decl.h?rev=39501&r1=39500&r2=39501&view=diff
==============================================================================
--- cfe/cfe/trunk/include/clang/AST/Decl.h (original)
+++ cfe/cfe/trunk/include/clang/AST/Decl.h Wed Jul 11 11:45:02 2007
@@ -210,6 +210,9 @@
}
void setParams(VarDecl **NewParamInfo, unsigned NumParams);
+ QualType getResultType() {
+ return cast<FunctionType>(getType())->getResultType();
+ }
StorageClass getStorageClass() const { return SClass; }
// Implement isa/cast/dyncast/etc.
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=39501&r1=39500&r2=39501&view=diff
==============================================================================
--- cfe/cfe/trunk/include/clang/AST/Expr.h (original)
+++ cfe/cfe/trunk/include/clang/AST/Expr.h Wed Jul 11 11:45:02 2007
@@ -53,14 +53,29 @@
/// - *e, the type of e cannot be a function type
/// - string-constant
///
- bool isLvalue();
+ enum isLvalueResult {
+ LV_Valid,
+ LV_NotObjectType,
+ LV_IncompleteVoidType,
+ LV_InvalidExpression
+ };
+ isLvalueResult isLvalue();
/// isModifiableLvalue - C99 6.3.2.1: an lvalue that does not have array type,
/// does not have an incomplete type, does not have a const-qualified type,
/// and if it is a structure or union, does not have any member (including,
/// recursively, any member or element of all contained aggregates or unions)
/// with a const-qualified type.
- bool isModifiableLvalue();
+ enum isModifiableLvalueResult {
+ MLV_Valid,
+ MLV_NotObjectType,
+ MLV_IncompleteVoidType,
+ MLV_InvalidExpression,
+ MLV_IncompleteType,
+ MLV_ConstQualified,
+ MLV_ArrayType
+ };
+ isModifiableLvalueResult isModifiableLvalue();
bool isNullPointerConstant() const;
@@ -354,18 +369,18 @@
class MemberExpr : public Expr {
Expr *Base;
FieldDecl *MemberDecl;
+ SourceLocation MemberLoc;
bool IsArrow; // True if this is "X->F", false if this is "X.F".
public:
- MemberExpr(Expr *base, bool isarrow, FieldDecl *memberdecl)
+ MemberExpr(Expr *base, bool isarrow, FieldDecl *memberdecl, SourceLocation l)
: Expr(MemberExprClass, memberdecl->getType()),
- Base(base), MemberDecl(memberdecl), IsArrow(isarrow) {}
+ Base(base), MemberDecl(memberdecl), MemberLoc(l), IsArrow(isarrow) {}
Expr *getBase() const { return Base; }
FieldDecl *getMemberDecl() const { return MemberDecl; }
bool isArrow() const { return IsArrow; }
virtual SourceRange getSourceRange() const {
- return SourceRange(getBase()->getLocStart(),
- getMemberDecl()->getLocation());
+ return SourceRange(getBase()->getLocStart(), MemberLoc);
}
virtual void visit(StmtVisitor &Visitor);
static bool classof(const Stmt *T) {
Modified: cfe/cfe/trunk/include/clang/AST/Type.h
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/include/clang/AST/Type.h?rev=39501&r1=39500&r2=39501&view=diff
==============================================================================
--- cfe/cfe/trunk/include/clang/AST/Type.h (original)
+++ cfe/cfe/trunk/include/clang/AST/Type.h Wed Jul 11 11:45:02 2007
@@ -519,7 +519,7 @@
// FIXME: This predicate is a helper to QualType/Type. It needs to
// recursively check all fields for const-ness. If any field is declared
// const, it needs to return false.
- bool isModifiableLvalue() const { return true; }
+ bool hasConstFields() const { return false; }
static bool classof(const Type *T);
static bool classof(const RecordType *) { return true; }
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=39501&r1=39500&r2=39501&view=diff
==============================================================================
--- cfe/cfe/trunk/include/clang/Basic/DiagnosticKinds.def (original)
+++ cfe/cfe/trunk/include/clang/Basic/DiagnosticKinds.def Wed Jul 11 11:45:02 2007
@@ -546,13 +546,13 @@
DIAG(err_typecheck_unary_expr, ERROR,
"invalid argument type to unary expression '%0'")
DIAG(err_typecheck_indirection_expr, ERROR,
- "indirection requires a pointer ('%0' operand invalid)")
+ "indirection requires a pointer operand ('%0' invalid)")
DIAG(err_typecheck_invalid_operands, ERROR,
"invalid operands to binary expression ('%0' and '%1')")
DIAG(ext_typecheck_comparison_of_pointer_integer, EXTENSION,
"comparison between pointer and integer")
DIAG(err_typecheck_assign_const, ERROR,
- "assignment of read-only variable")
+ "read-only variable is not assignable")
DIAG(err_typecheck_assign_incompatible, ERROR,
"incompatible types in assignment ('%0' and '%1')")
DIAG(ext_typecheck_assign_int_from_pointer, EXTENSION,
@@ -560,11 +560,17 @@
DIAG(ext_typecheck_assign_pointer_from_int, EXTENSION,
"assignment makes pointer from integer without a cast")
DIAG(ext_typecheck_assign_incompatible_pointer, EXTENSION,
- "assignment from incompatible pointer type")
+ "assignment from incompatible pointer type ('%0' and '%1')")
DIAG(ext_typecheck_assign_discards_qualifiers, EXTENSION,
- "assignment discards qualifiers from pointer target type")
-DIAG(err_typecheck_assign_non_lvalue, ERROR,
- "invalid lvalue in assignment")
+ "assignment discards qualifiers from pointer target type ('%0' and '%1')")
+DIAG(err_typecheck_array_not_modifiable_lvalue, ERROR,
+ "array type '%0' is not assignable")
+DIAG(err_typecheck_non_object_not_modifiable_lvalue, ERROR,
+ "non-object type '%0' is not assignable")
+DIAG(err_typecheck_expression_not_modifiable_lvalue, ERROR,
+ "expression is not assignable")
+DIAG(err_typecheck_incomplete_type_not_modifiable_lvalue, ERROR,
+ "incomplete type '%0' is not assignable")
DIAG(err_typecheck_call_too_few_args, ERROR,
"too few arguments to function")
DIAG(err_typecheck_call_too_many_args, ERROR,
@@ -579,6 +585,16 @@
"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_return_incompatible, ERROR,
+ "incompatible types in return ('%0' and '%1')")
+DIAG(ext_typecheck_return_int_from_pointer, EXTENSION,
+ "return makes integer from pointer without a cast")
+DIAG(ext_typecheck_return_pointer_from_int, EXTENSION,
+ "return makes pointer from integer without a cast")
+DIAG(ext_typecheck_return_incompatible_pointer, EXTENSION,
+ "return from incompatible pointer type")
+DIAG(ext_typecheck_return_discards_qualifiers, EXTENSION,
+ "return 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,
More information about the cfe-commits
mailing list