[cfe-commits] r39451 - in /cfe/cfe/trunk: AST/SemaExpr.cpp AST/Type.cpp Sema/SemaExpr.cpp clang.xcodeproj/project.pbxproj include/clang/Basic/DiagnosticKinds.def
Steve Naroff
snaroff at apple.com
Wed Jul 11 09:44:35 PDT 2007
Author: snaroff
Date: Wed Jul 11 11:44:34 2007
New Revision: 39451
URL: http://llvm.org/viewvc/llvm-project?rev=39451&view=rev
Log:
Bug #:
Submitted by:
Reviewed by:
- Implement type checking for Sema::CheckConditionalOperands.
- Fixed crasher in Sema::UsualUnaryConversion (incorrect use of cast<>).
- Added a few diagnostics and started passing 2 args! (Thanks Chris!).
Here's some diagnostic output that is much nicer than gcc...
[dylan:~/llvm/tools/clang] admin% ../../Debug/bin/clang cond.c
cond.c:12:14: error: used type 'struct foo' where arithmetic or pointer type is required
result = s ? 1 : 2;
^
cond.c:13:14: error: incompatible operand types ('struct foo' and 'struct bar')
result = a ? s : s2;
^
cond.c:14:14: warning: pointer type mismatch ('struct foo *' and 'struct bar *')
result = a ? ps : ps2;
^
cond.c:14:10: warning: assignment makes integer from pointer without a cast
result = a ? ps : ps2;
^
cond.c:15:14: error: incompatible operand types ('struct foo *' and 'struct foo')
result = a ? ps : s;
^
cond.c:16:14: warning: pointer type mismatch ('void (*)(int)' and 'void (*)(int, int)')
result = a ? func : func2;
^
cond.c:16:10: warning: assignment makes integer from pointer without a cast
result = a ? func : func2;
^
7 diagnostics generated.
[dylan:~/llvm/tools/clang] admin% cc -c cond.c
cond.c: In function 'main':
cond.c:12: error: used struct type value where scalar is required
cond.c:13: error: type mismatch in conditional expression
cond.c:14: warning: pointer type mismatch in conditional expression
cond.c:14: warning: assignment makes integer from pointer without a cast
cond.c:15: error: type mismatch in conditional expression
cond.c:16: warning: pointer type mismatch in conditional expression
cond.c:16: warning: assignment makes integer from pointer without a cast
Modified:
cfe/cfe/trunk/AST/SemaExpr.cpp
cfe/cfe/trunk/AST/Type.cpp
cfe/cfe/trunk/Sema/SemaExpr.cpp
cfe/cfe/trunk/clang.xcodeproj/project.pbxproj
cfe/cfe/trunk/include/clang/Basic/DiagnosticKinds.def
Modified: cfe/cfe/trunk/AST/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/AST/SemaExpr.cpp?rev=39451&r1=39450&r2=39451&view=diff
==============================================================================
--- cfe/cfe/trunk/AST/SemaExpr.cpp (original)
+++ cfe/cfe/trunk/AST/SemaExpr.cpp Wed Jul 11 11:44:34 2007
@@ -170,6 +170,8 @@
return e;
}
+/// The UsualUnaryConversion() function is *not* called by this routine.
+/// See C99 6.3.2.1p[2-4] for more details.
QualType Sema::CheckSizeOfAlignOfOperand(QualType exprType,
SourceLocation OpLoc, bool isSizeof) {
// C99 6.5.3.4p1:
@@ -386,16 +388,78 @@
inline QualType Sema::CheckConditionalOperands( // C99 6.5.15
Expr *Cond, Expr *LHS, Expr *RHS, SourceLocation questionLoc) {
- QualType cond = Cond->getType().getCanonicalType();
- QualType lhs = LHS->getType().getCanonicalType();
- QualType rhs = RHS->getType().getCanonicalType();
-
+ QualType cond = Cond->getType();
+ QualType lhs = LHS->getType();
+ QualType rhs = RHS->getType();
+
assert(!cond.isNull() && "ParseConditionalOp(): no conditional type");
assert(!lhs.isNull() && "ParseConditionalOp(): no lhs type");
assert(!rhs.isNull() && "ParseConditionalOp(): no rhs type");
- // C99 6.5.15p2,3
- return rhs;
+ cond = UsualUnaryConversion(cond);
+ lhs = UsualUnaryConversion(lhs);
+ rhs = UsualUnaryConversion(rhs);
+
+ // first, check the condition.
+ if (!cond->isScalarType()) { // C99 6.5.15p2
+ // FIXME: need to compute the location from the Cond expr node...
+ Diag(questionLoc, diag::err_typecheck_cond_expect_scalar,
+ cond.getAsString());
+ return QualType();
+ }
+ // now check the two expressions.
+ if (lhs->isArithmeticType() && rhs->isArithmeticType()) // C99 6.5.15p3,5
+ return UsualArithmeticConversions(lhs, rhs);
+
+ if ((lhs->isStructureType() && rhs->isStructureType()) || // C99 6.5.15p3
+ (lhs->isUnionType() && rhs->isUnionType())) {
+ TagType *lTag = cast<TagType>(lhs.getCanonicalType());
+ TagType *rTag = cast<TagType>(rhs.getCanonicalType());
+
+ if (lTag->getDecl()->getIdentifier() == rTag->getDecl()->getIdentifier())
+ return lhs;
+ else {
+ Diag(questionLoc, diag::err_typecheck_cond_incompatible_operands,
+ lhs.getAsString(), rhs.getAsString());
+ return QualType();
+ }
+ }
+ if (lhs->isPointerType() && rhs->isPointerType()) { // C99 6.5.15p3,6
+ QualType lhptee, rhptee;
+
+ // get the "pointed to" type
+ lhptee = cast<PointerType>(lhs.getCanonicalType())->getPointeeType();
+ rhptee = cast<PointerType>(rhs.getCanonicalType())->getPointeeType();
+
+ // ignore qualifiers on void (C99 6.5.15p3, clause 6)
+ if (lhptee.getUnqualifiedType()->isVoidType() &&
+ (rhptee->isObjectType() || rhptee->isIncompleteType()))
+ return lhs;
+ if (rhptee.getUnqualifiedType()->isVoidType() &&
+ (lhptee->isObjectType() || lhptee->isIncompleteType()))
+ return rhs;
+
+ // FIXME: C99 6.5.15p6: If both operands are pointers to compatible types
+ // *or* to differently qualified versions of compatible types, the result
+ // type is a pointer to an appropriately qualified version of the
+ // *composite* type.
+ if (!Type::typesAreCompatible(lhptee.getUnqualifiedType(),
+ rhptee.getUnqualifiedType())) {
+ Diag(questionLoc, diag::ext_typecheck_cond_incompatible_pointers,
+ lhs.getAsString(), rhs.getAsString());
+ return lhs; // FIXME: this is an _ext - is this return o.k?
+ }
+ }
+ if (lhs->isVoidType() && rhs->isVoidType()) // C99 6.5.15p3
+ return lhs;
+ if (lhs->isPointerType() && RHS->isNullPointerConstant()) // C99 6.5.15p3
+ return lhs;
+ if (rhs->isPointerType() && LHS->isNullPointerConstant()) // C99 6.5.15p3
+ return rhs;
+
+ Diag(questionLoc, diag::err_typecheck_cond_incompatible_operands,
+ lhs.getAsString(), rhs.getAsString());
+ return QualType();
}
/// ParseConditionalOp - Parse a ?: operation. Note that 'LHS' may be null
@@ -421,10 +485,10 @@
if (t->isPromotableIntegerType()) // C99 6.3.1.1p2
return Context.IntTy;
- else if (t->isFunctionType()) // C99 6.3.2.1p4
- return Context.getPointerType(t);
- else if (t->isArrayType()) // C99 6.3.2.1p3
- return Context.getPointerType(cast<ArrayType>(t)->getElementType());
+ if (t->isFunctionType()) // C99 6.3.2.1p4
+ return Context.getPointerType(t.getCanonicalType());
+ if (const ArrayType *ary = dyn_cast<ArrayType>(t.getCanonicalType()))
+ return Context.getPointerType(ary->getElementType()); // C99 6.3.2.1p3
return t;
}
@@ -800,7 +864,7 @@
/// designator or an lvalue designating an object. If it is an lvalue, the
/// object cannot be declared with storage class register or be a bit field.
/// Note: The usual conversions are *not* applied to the operand of the &
-/// operator, and its result is never an lvalue.
+/// operator (C99 6.3.2.1p[2-4]), and its result is never an lvalue.
QualType Sema::CheckAddressOfOperand(Expr *op, SourceLocation OpLoc) {
Decl *dcl = getPrimaryDeclaration(op);
Modified: cfe/cfe/trunk/AST/Type.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/AST/Type.cpp?rev=39451&r1=39450&r2=39451&view=diff
==============================================================================
--- cfe/cfe/trunk/AST/Type.cpp (original)
+++ cfe/cfe/trunk/AST/Type.cpp Wed Jul 11 11:44:34 2007
@@ -258,16 +258,20 @@
if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType))
return BT->getKind() >= BuiltinType::Bool &&
BT->getKind() <= BuiltinType::LongDoubleComplex;
- if (const TagType *TT = dyn_cast<TagType>(CanonicalType))
+ if (const TagType *TT = dyn_cast<TagType>(CanonicalType)) {
if (TT->getDecl()->getKind() == Decl::Enum)
return true;
+ return false;
+ }
return CanonicalType->getTypeClass() == Pointer;
}
bool Type::isAggregateType() const {
- if (const TagType *TT = dyn_cast<TagType>(CanonicalType))
+ if (const TagType *TT = dyn_cast<TagType>(CanonicalType)) {
if (TT->getDecl()->getKind() == Decl::Struct)
return true;
+ return false;
+ }
return CanonicalType->getTypeClass() == Array;
}
Modified: cfe/cfe/trunk/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/Sema/SemaExpr.cpp?rev=39451&r1=39450&r2=39451&view=diff
==============================================================================
--- cfe/cfe/trunk/Sema/SemaExpr.cpp (original)
+++ cfe/cfe/trunk/Sema/SemaExpr.cpp Wed Jul 11 11:44:34 2007
@@ -170,6 +170,8 @@
return e;
}
+/// The UsualUnaryConversion() function is *not* called by this routine.
+/// See C99 6.3.2.1p[2-4] for more details.
QualType Sema::CheckSizeOfAlignOfOperand(QualType exprType,
SourceLocation OpLoc, bool isSizeof) {
// C99 6.5.3.4p1:
@@ -386,16 +388,78 @@
inline QualType Sema::CheckConditionalOperands( // C99 6.5.15
Expr *Cond, Expr *LHS, Expr *RHS, SourceLocation questionLoc) {
- QualType cond = Cond->getType().getCanonicalType();
- QualType lhs = LHS->getType().getCanonicalType();
- QualType rhs = RHS->getType().getCanonicalType();
-
+ QualType cond = Cond->getType();
+ QualType lhs = LHS->getType();
+ QualType rhs = RHS->getType();
+
assert(!cond.isNull() && "ParseConditionalOp(): no conditional type");
assert(!lhs.isNull() && "ParseConditionalOp(): no lhs type");
assert(!rhs.isNull() && "ParseConditionalOp(): no rhs type");
- // C99 6.5.15p2,3
- return rhs;
+ cond = UsualUnaryConversion(cond);
+ lhs = UsualUnaryConversion(lhs);
+ rhs = UsualUnaryConversion(rhs);
+
+ // first, check the condition.
+ if (!cond->isScalarType()) { // C99 6.5.15p2
+ // FIXME: need to compute the location from the Cond expr node...
+ Diag(questionLoc, diag::err_typecheck_cond_expect_scalar,
+ cond.getAsString());
+ return QualType();
+ }
+ // now check the two expressions.
+ if (lhs->isArithmeticType() && rhs->isArithmeticType()) // C99 6.5.15p3,5
+ return UsualArithmeticConversions(lhs, rhs);
+
+ if ((lhs->isStructureType() && rhs->isStructureType()) || // C99 6.5.15p3
+ (lhs->isUnionType() && rhs->isUnionType())) {
+ TagType *lTag = cast<TagType>(lhs.getCanonicalType());
+ TagType *rTag = cast<TagType>(rhs.getCanonicalType());
+
+ if (lTag->getDecl()->getIdentifier() == rTag->getDecl()->getIdentifier())
+ return lhs;
+ else {
+ Diag(questionLoc, diag::err_typecheck_cond_incompatible_operands,
+ lhs.getAsString(), rhs.getAsString());
+ return QualType();
+ }
+ }
+ if (lhs->isPointerType() && rhs->isPointerType()) { // C99 6.5.15p3,6
+ QualType lhptee, rhptee;
+
+ // get the "pointed to" type
+ lhptee = cast<PointerType>(lhs.getCanonicalType())->getPointeeType();
+ rhptee = cast<PointerType>(rhs.getCanonicalType())->getPointeeType();
+
+ // ignore qualifiers on void (C99 6.5.15p3, clause 6)
+ if (lhptee.getUnqualifiedType()->isVoidType() &&
+ (rhptee->isObjectType() || rhptee->isIncompleteType()))
+ return lhs;
+ if (rhptee.getUnqualifiedType()->isVoidType() &&
+ (lhptee->isObjectType() || lhptee->isIncompleteType()))
+ return rhs;
+
+ // FIXME: C99 6.5.15p6: If both operands are pointers to compatible types
+ // *or* to differently qualified versions of compatible types, the result
+ // type is a pointer to an appropriately qualified version of the
+ // *composite* type.
+ if (!Type::typesAreCompatible(lhptee.getUnqualifiedType(),
+ rhptee.getUnqualifiedType())) {
+ Diag(questionLoc, diag::ext_typecheck_cond_incompatible_pointers,
+ lhs.getAsString(), rhs.getAsString());
+ return lhs; // FIXME: this is an _ext - is this return o.k?
+ }
+ }
+ if (lhs->isVoidType() && rhs->isVoidType()) // C99 6.5.15p3
+ return lhs;
+ if (lhs->isPointerType() && RHS->isNullPointerConstant()) // C99 6.5.15p3
+ return lhs;
+ if (rhs->isPointerType() && LHS->isNullPointerConstant()) // C99 6.5.15p3
+ return rhs;
+
+ Diag(questionLoc, diag::err_typecheck_cond_incompatible_operands,
+ lhs.getAsString(), rhs.getAsString());
+ return QualType();
}
/// ParseConditionalOp - Parse a ?: operation. Note that 'LHS' may be null
@@ -421,10 +485,10 @@
if (t->isPromotableIntegerType()) // C99 6.3.1.1p2
return Context.IntTy;
- else if (t->isFunctionType()) // C99 6.3.2.1p4
- return Context.getPointerType(t);
- else if (t->isArrayType()) // C99 6.3.2.1p3
- return Context.getPointerType(cast<ArrayType>(t)->getElementType());
+ if (t->isFunctionType()) // C99 6.3.2.1p4
+ return Context.getPointerType(t.getCanonicalType());
+ if (const ArrayType *ary = dyn_cast<ArrayType>(t.getCanonicalType()))
+ return Context.getPointerType(ary->getElementType()); // C99 6.3.2.1p3
return t;
}
@@ -800,7 +864,7 @@
/// designator or an lvalue designating an object. If it is an lvalue, the
/// object cannot be declared with storage class register or be a bit field.
/// Note: The usual conversions are *not* applied to the operand of the &
-/// operator, and its result is never an lvalue.
+/// operator (C99 6.3.2.1p[2-4]), and its result is never an lvalue.
QualType Sema::CheckAddressOfOperand(Expr *op, SourceLocation OpLoc) {
Decl *dcl = getPrimaryDeclaration(op);
Modified: cfe/cfe/trunk/clang.xcodeproj/project.pbxproj
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/clang.xcodeproj/project.pbxproj?rev=39451&r1=39450&r2=39451&view=diff
==============================================================================
--- cfe/cfe/trunk/clang.xcodeproj/project.pbxproj (original)
+++ cfe/cfe/trunk/clang.xcodeproj/project.pbxproj Wed Jul 11 11:44:34 2007
@@ -94,6 +94,23 @@
DED7D9E50A5257F6003AD0FB /* ScratchBuffer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DED7D9E40A5257F6003AD0FB /* ScratchBuffer.cpp */; };
/* End PBXBuildFile section */
+/* Begin PBXBuildStyle section */
+ 84D221650BFB885000DAAD04 /* Development */ = {
+ isa = PBXBuildStyle;
+ buildSettings = {
+ COPY_PHASE_STRIP = NO;
+ };
+ name = Development;
+ };
+ 84D221660BFB885000DAAD04 /* Deployment */ = {
+ isa = PBXBuildStyle;
+ buildSettings = {
+ COPY_PHASE_STRIP = YES;
+ };
+ name = Deployment;
+ };
+/* End PBXBuildStyle section */
+
/* Begin PBXCopyFilesBuildPhase section */
8DD76F690486A84900D96B5E /* CopyFiles */ = {
isa = PBXCopyFilesBuildPhase;
@@ -476,6 +493,12 @@
08FB7793FE84155DC02AAC07 /* Project object */ = {
isa = PBXProject;
buildConfigurationList = 1DEB923508733DC60010E9CD /* Build configuration list for PBXProject "clang" */;
+ buildSettings = {
+ };
+ buildStyles = (
+ 84D221650BFB885000DAAD04 /* Development */,
+ 84D221660BFB885000DAAD04 /* Deployment */,
+ );
hasScannedForEncodings = 1;
mainGroup = 08FB7794FE84155DC02AAC07 /* clang */;
projectDirPath = "";
Modified: cfe/cfe/trunk/include/clang/Basic/DiagnosticKinds.def
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/include/clang/Basic/DiagnosticKinds.def?rev=39451&r1=39450&r2=39451&view=diff
==============================================================================
--- cfe/cfe/trunk/include/clang/Basic/DiagnosticKinds.def (original)
+++ cfe/cfe/trunk/include/clang/Basic/DiagnosticKinds.def Wed Jul 11 11:44:34 2007
@@ -577,6 +577,12 @@
"passing argument %0 from incompatible pointer type")
DIAG(ext_typecheck_passing_discards_qualifiers, EXTENSION,
"passing argument %0 discards qualifiers from pointer target type")
+DIAG(err_typecheck_cond_expect_scalar, ERROR,
+ "used type '%0' where arithmetic or pointer type is required")
+DIAG(err_typecheck_cond_incompatible_operands, ERROR,
+ "incompatible operand types ('%0' and '%1')")
+DIAG(ext_typecheck_cond_incompatible_pointers, EXTENSION,
+ "pointer type mismatch ('%0' and '%1')")
// Statements.
DIAG(err_continue_not_in_loop, ERROR,
More information about the cfe-commits
mailing list