/// place. This captures the intermediate type which the computation is done
/// in.
class CompoundAssignOperator : public BinaryOperator {
- QualType ComputationType;
+ QualType ComputationLHSType;
+ QualType ComputationResultType;
public:
CompoundAssignOperator(Expr *lhs, Expr *rhs, Opcode opc,
- QualType ResType, QualType CompType,
+ QualType ResType, QualType CompLHSType,
+ QualType CompResultType,
SourceLocation OpLoc)
: BinaryOperator(lhs, rhs, opc, ResType, OpLoc, true),
- ComputationType(CompType) {
+ ComputationLHSType(CompLHSType),
+ ComputationResultType(CompResultType) {
assert(isCompoundAssignmentOp() &&
"Only should be used for compound assignments");
}
- QualType getComputationType() const { return ComputationType; }
+ // The two computation types are the type the LHS is converted
+ // to for the computation and the type of the result; the two are
+ // distinct in a few cases (specifically, int+=ptr and ptr-=ptr).
+ QualType getComputationLHSType() const { return ComputationLHSType; }
+ QualType getComputationResultType() const { return ComputationResultType; }
static bool classof(const CompoundAssignOperator *) { return true; }
static bool classof(const Stmt *S) {
}
void StmtDumper::VisitCompoundAssignOperator(CompoundAssignOperator *Node) {
DumpExpr(Node);
- fprintf(F, " '%s' ComputeTy=",
+ fprintf(F, " '%s' ComputeLHSTy=",
BinaryOperator::getOpcodeStr(Node->getOpcode()));
- DumpType(Node->getComputationType());
+ DumpType(Node->getComputationLHSType());
+ fprintf(F, " ComputeResultTy=");
+ DumpType(Node->getComputationResultType());
}
// GNU extensions.
void CompoundAssignOperator::EmitImpl(Serializer& S) const {
S.Emit(getType());
- S.Emit(ComputationType);
+ S.Emit(ComputationLHSType);
+ S.Emit(ComputationResultType);
S.Emit(getOperatorLoc());
S.EmitInt(getOpcode());
S.BatchEmitOwnedPtrs(getLHS(),getRHS());
CompoundAssignOperator*
CompoundAssignOperator::CreateImpl(Deserializer& D, ASTContext& C) {
QualType t = QualType::ReadVal(D);
- QualType c = QualType::ReadVal(D);
+ QualType cl = QualType::ReadVal(D);
+ QualType cr = QualType::ReadVal(D);
SourceLocation L = SourceLocation::ReadVal(D);
Opcode Opc = static_cast<Opcode>(D.ReadInt());
Expr* LHS, *RHS;
D.BatchReadOwnedPtrs(LHS, RHS, C);
return new (C, llvm::alignof<CompoundAssignOperator>())
- CompoundAssignOperator(LHS,RHS,Opc,t,c,L);
+ CompoundAssignOperator(LHS,RHS,Opc,t,cl,cr,L);
}
void CompoundLiteralExpr::EmitImpl(Serializer& S) const {
// The RHS is not Unknown.
// Get the computation type.
- QualType CTy = cast<CompoundAssignOperator>(B)->getComputationType();
+ QualType CTy = cast<CompoundAssignOperator>(B)->getComputationResultType();
CTy = getContext().getCanonicalType(CTy);
-
+
+ QualType CLHSTy = cast<CompoundAssignOperator>(B)->getComputationLHSType();
+ CLHSTy = getContext().getCanonicalType(CTy);
+
QualType LTy = getContext().getCanonicalType(LHS->getType());
QualType RTy = getContext().getCanonicalType(RHS->getType());
-
- // Perform promotions.
- if (LTy != CTy) V = EvalCast(V, CTy);
- if (RTy != CTy) RightV = EvalCast(RightV, CTy);
-
+
+ // Promote LHS.
+ V = EvalCast(V, CLHSTy);
+
// Evaluate operands and promote to result type.
if (RightV.isUndef()) {
// Propagate undefined values (right-side).
LValue LHSLV = CGF.EmitLValue(E->getLHS());
BinOpInfo OpInfo;
- OpInfo.Ty = E->getComputationType();
+ OpInfo.Ty = E->getComputationResultType();
// We know the LHS is a complex lvalue.
OpInfo.LHS = EmitLoadOfComplex(LHSLV.getAddress(), LHSLV.isVolatileQualified());
BinOpInfo OpInfo;
- // Load the LHS and RHS operands.
- LValue LHSLV = EmitLValue(E->getLHS());
- OpInfo.LHS = EmitLoadOfLValue(LHSLV, LHSTy);
-
- // Determine the computation type. If the RHS is complex, then this is one of
- // the add/sub/mul/div operators. All of these operators can be computed in
- // with just their real component even though the computation domain really is
- // complex.
- QualType ComputeType = E->getComputationType();
-
- // If the computation type is complex, then the RHS is complex. Emit the RHS.
- if (const ComplexType *CT = ComputeType->getAsComplexType()) {
- ComputeType = CT->getElementType();
-
- // Emit the RHS, only keeping the real component.
- OpInfo.RHS = CGF.EmitComplexExpr(E->getRHS()).first;
- RHSTy = RHSTy->getAsComplexType()->getElementType();
- } else {
- // Otherwise the RHS is a simple scalar value.
- OpInfo.RHS = Visit(E->getRHS());
- }
-
- QualType LComputeTy, RComputeTy, ResultTy;
-
- // Compound assignment does not contain enough information about all
- // the types involved for pointer arithmetic cases. Figure it out
- // here for now.
- if (E->getLHS()->getType()->isPointerType()) {
- // Pointer arithmetic cases: ptr +=,-= int and ptr -= ptr,
- assert((E->getOpcode() == BinaryOperator::AddAssign ||
- E->getOpcode() == BinaryOperator::SubAssign) &&
- "Invalid compound assignment operator on pointer type.");
- LComputeTy = E->getLHS()->getType();
-
- if (E->getRHS()->getType()->isPointerType()) {
- // Degenerate case of (ptr -= ptr) allowed by GCC implicit cast
- // extension, the conversion from the pointer difference back to
- // the LHS type is handled at the end.
- assert(E->getOpcode() == BinaryOperator::SubAssign &&
- "Invalid compound assignment operator on pointer type.");
- RComputeTy = E->getLHS()->getType();
- ResultTy = CGF.getContext().getPointerDiffType();
- } else {
- RComputeTy = E->getRHS()->getType();
- ResultTy = LComputeTy;
- }
- } else if (E->getRHS()->getType()->isPointerType()) {
- // Degenerate case of (int += ptr) allowed by GCC implicit cast
- // extension.
- assert(E->getOpcode() == BinaryOperator::AddAssign &&
- "Invalid compound assignment operator on pointer type.");
- LComputeTy = E->getLHS()->getType();
- RComputeTy = E->getRHS()->getType();
- ResultTy = RComputeTy;
- } else {
- LComputeTy = RComputeTy = ResultTy = ComputeType;
+ if (E->getComputationResultType()->isAnyComplexType()) {
+ // FIXME: This needs to go through the complex expression emitter, but
+ // it's a tad complicated to do that... I'm leaving it out for now.
+ // (Note that we do actually need the imaginary part of the RHS for
+ // multiplication and division.)
+ CGF.ErrorUnsupported(E, "complex compound assignment");
+ return llvm::UndefValue::get(CGF.ConvertType(E->getType()));
}
- // Convert the LHS/RHS values to the computation type.
- OpInfo.LHS = EmitScalarConversion(OpInfo.LHS, LHSTy, LComputeTy);
- OpInfo.RHS = EmitScalarConversion(OpInfo.RHS, RHSTy, RComputeTy);
- OpInfo.Ty = ResultTy;
+ // Load/convert the LHS.
+ LValue LHSLV = EmitLValue(E->getLHS());
+ OpInfo.LHS = EmitLoadOfLValue(LHSLV, LHSTy);
+ OpInfo.LHS = EmitScalarConversion(OpInfo.LHS, LHSTy,
+ E->getComputationLHSType());
+ // Emit the RHS.
+ OpInfo.RHS = Visit(E->getRHS());
+ OpInfo.Ty = E->getComputationResultType();
OpInfo.E = E;
// Expand the binary operator.
Value *Result = (this->*Func)(OpInfo);
// Convert the result back to the LHS type.
- Result = EmitScalarConversion(Result, ResultTy, LHSTy);
-
+ Result = EmitScalarConversion(Result, E->getComputationResultType(), LHSTy);
+
// Store the result value into the LHS lvalue. Bit-fields are
// handled specially because the result is altered by the store,
// i.e., [C99 6.5.16p1] 'An assignment expression has the value of
QualType CheckRemainderOperands( // C99 6.5.5
Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isCompAssign = false);
QualType CheckAdditionOperands( // C99 6.5.6
- Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isCompAssign = false);
+ Expr *&lex, Expr *&rex, SourceLocation OpLoc, QualType* CompLHSTy = 0);
QualType CheckSubtractionOperands( // C99 6.5.6
- Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isCompAssign = false);
+ Expr *&lex, Expr *&rex, SourceLocation OpLoc, QualType* CompLHSTy = 0);
QualType CheckShiftOperands( // C99 6.5.7
Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isCompAssign = false);
QualType CheckCompareOperands( // C99 6.5.8/9
/// GCC.
QualType Sema::UsualArithmeticConversions(Expr *&lhsExpr, Expr *&rhsExpr,
bool isCompAssign) {
- if (!isCompAssign) {
+ if (!isCompAssign)
UsualUnaryConversions(lhsExpr);
- UsualUnaryConversions(rhsExpr);
- }
+
+ UsualUnaryConversions(rhsExpr);
// For conversion purposes, we ignore any qualifiers.
// For example, "const float" and "float" are equivalent.
return lhs;
QualType destType = UsualArithmeticConversionsType(lhs, rhs);
- if (!isCompAssign) {
+ if (!isCompAssign)
ImpCastExprToType(lhsExpr, destType);
- ImpCastExprToType(rhsExpr, destType);
- }
+ ImpCastExprToType(rhsExpr, destType);
return destType;
}
}
inline QualType Sema::CheckAdditionOperands( // C99 6.5.6
- Expr *&lex, Expr *&rex, SourceLocation Loc, bool isCompAssign)
+ Expr *&lex, Expr *&rex, SourceLocation Loc, QualType* CompLHSTy)
{
- if (lex->getType()->isVectorType() || rex->getType()->isVectorType())
- return CheckVectorOperands(Loc, lex, rex);
+ if (lex->getType()->isVectorType() || rex->getType()->isVectorType()) {
+ QualType compType = CheckVectorOperands(Loc, lex, rex);
+ if (CompLHSTy) *CompLHSTy = compType;
+ return compType;
+ }
- QualType compType = UsualArithmeticConversions(lex, rex, isCompAssign);
+ QualType compType = UsualArithmeticConversions(lex, rex, CompLHSTy);
// handle the common case first (both operands are arithmetic).
- if (lex->getType()->isArithmeticType() && rex->getType()->isArithmeticType())
+ if (lex->getType()->isArithmeticType() &&
+ rex->getType()->isArithmeticType()) {
+ if (CompLHSTy) *CompLHSTy = compType;
return compType;
+ }
// Put any potential pointer into PExp
Expr* PExp = lex, *IExp = rex;
lex->getType()))
return QualType();
+ if (CompLHSTy) {
+ QualType LHSTy = lex->getType();
+ if (LHSTy->isPromotableIntegerType())
+ LHSTy = Context.IntTy;
+ *CompLHSTy = LHSTy;
+ }
return PExp->getType();
}
}
// C99 6.5.6
QualType Sema::CheckSubtractionOperands(Expr *&lex, Expr *&rex,
- SourceLocation Loc, bool isCompAssign) {
- if (lex->getType()->isVectorType() || rex->getType()->isVectorType())
- return CheckVectorOperands(Loc, lex, rex);
+ SourceLocation Loc, QualType* CompLHSTy) {
+ if (lex->getType()->isVectorType() || rex->getType()->isVectorType()) {
+ QualType compType = CheckVectorOperands(Loc, lex, rex);
+ if (CompLHSTy) *CompLHSTy = compType;
+ return compType;
+ }
- QualType compType = UsualArithmeticConversions(lex, rex, isCompAssign);
+ QualType compType = UsualArithmeticConversions(lex, rex, CompLHSTy);
// Enforce type constraints: C99 6.5.6p3.
// Handle the common case first (both operands are arithmetic).
- if (lex->getType()->isArithmeticType() && rex->getType()->isArithmeticType())
+ if (lex->getType()->isArithmeticType() && rex->getType()->isArithmeticType()) {
+ if (CompLHSTy) *CompLHSTy = compType;
return compType;
+ }
// Either ptr - int or ptr - ptr.
if (const PointerType *LHSPTy = lex->getType()->getAsPointerType()) {
<< ComplainAboutFunc->getType()
<< ComplainAboutFunc->getSourceRange();
+ if (CompLHSTy) *CompLHSTy = lex->getType();
return lex->getType();
}
Diag(Loc, diag::ext_gnu_ptr_func_arith)
<< ComplainAboutFunc->getType()
<< ComplainAboutFunc->getSourceRange();
-
+
+ if (CompLHSTy) *CompLHSTy = lex->getType();
return Context.getPointerDiffType();
}
}
// Shifts don't perform usual arithmetic conversions, they just do integer
// promotions on each operand. C99 6.5.7p3
+ QualType LHSTy;
+ if (lex->getType()->isPromotableIntegerType())
+ LHSTy = Context.IntTy;
+ else
+ LHSTy = lex->getType();
if (!isCompAssign)
- UsualUnaryConversions(lex);
+ ImpCastExprToType(lex, LHSTy);
+
UsualUnaryConversions(rex);
// "The type of the result is that of the promoted left operand."
- return lex->getType();
+ return LHSTy;
}
// C99 6.5.8
Action::OwningExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
unsigned Op,
Expr *lhs, Expr *rhs) {
- QualType ResultTy; // Result type of the binary operator.
- QualType CompTy; // Computation type for compound assignments (e.g. '+=')
+ QualType ResultTy; // Result type of the binary operator.
BinaryOperator::Opcode Opc = (BinaryOperator::Opcode)Op;
+ // The following two variables are used for compound assignment operators
+ QualType CompLHSTy; // Type of LHS after promotions for computation
+ QualType CompResultTy; // Type of computation result
switch (Opc) {
case BinaryOperator::Assign:
break;
case BinaryOperator::MulAssign:
case BinaryOperator::DivAssign:
- CompTy = CheckMultiplyDivideOperands(lhs, rhs, OpLoc, true);
- if (!CompTy.isNull())
- ResultTy = CheckAssignmentOperands(lhs, rhs, OpLoc, CompTy);
+ CompResultTy = CheckMultiplyDivideOperands(lhs, rhs, OpLoc, true);
+ CompLHSTy = CompResultTy;
+ if (!CompResultTy.isNull())
+ ResultTy = CheckAssignmentOperands(lhs, rhs, OpLoc, CompResultTy);
break;
case BinaryOperator::RemAssign:
- CompTy = CheckRemainderOperands(lhs, rhs, OpLoc, true);
- if (!CompTy.isNull())
- ResultTy = CheckAssignmentOperands(lhs, rhs, OpLoc, CompTy);
+ CompResultTy = CheckRemainderOperands(lhs, rhs, OpLoc, true);
+ CompLHSTy = CompResultTy;
+ if (!CompResultTy.isNull())
+ ResultTy = CheckAssignmentOperands(lhs, rhs, OpLoc, CompResultTy);
break;
case BinaryOperator::AddAssign:
- CompTy = CheckAdditionOperands(lhs, rhs, OpLoc, true);
- if (!CompTy.isNull())
- ResultTy = CheckAssignmentOperands(lhs, rhs, OpLoc, CompTy);
+ CompResultTy = CheckAdditionOperands(lhs, rhs, OpLoc, &CompLHSTy);
+ if (!CompResultTy.isNull())
+ ResultTy = CheckAssignmentOperands(lhs, rhs, OpLoc, CompResultTy);
break;
case BinaryOperator::SubAssign:
- CompTy = CheckSubtractionOperands(lhs, rhs, OpLoc, true);
- if (!CompTy.isNull())
- ResultTy = CheckAssignmentOperands(lhs, rhs, OpLoc, CompTy);
+ CompResultTy = CheckSubtractionOperands(lhs, rhs, OpLoc, &CompLHSTy);
+ if (!CompResultTy.isNull())
+ ResultTy = CheckAssignmentOperands(lhs, rhs, OpLoc, CompResultTy);
break;
case BinaryOperator::ShlAssign:
case BinaryOperator::ShrAssign:
- CompTy = CheckShiftOperands(lhs, rhs, OpLoc, true);
- if (!CompTy.isNull())
- ResultTy = CheckAssignmentOperands(lhs, rhs, OpLoc, CompTy);
+ CompResultTy = CheckShiftOperands(lhs, rhs, OpLoc, true);
+ CompLHSTy = CompResultTy;
+ if (!CompResultTy.isNull())
+ ResultTy = CheckAssignmentOperands(lhs, rhs, OpLoc, CompResultTy);
break;
case BinaryOperator::AndAssign:
case BinaryOperator::XorAssign:
case BinaryOperator::OrAssign:
- CompTy = CheckBitwiseOperands(lhs, rhs, OpLoc, true);
- if (!CompTy.isNull())
- ResultTy = CheckAssignmentOperands(lhs, rhs, OpLoc, CompTy);
+ CompResultTy = CheckBitwiseOperands(lhs, rhs, OpLoc, true);
+ CompLHSTy = CompResultTy;
+ if (!CompResultTy.isNull())
+ ResultTy = CheckAssignmentOperands(lhs, rhs, OpLoc, CompResultTy);
break;
case BinaryOperator::Comma:
ResultTy = CheckCommaOperands(lhs, rhs, OpLoc);
}
if (ResultTy.isNull())
return ExprError();
- if (CompTy.isNull())
+ if (CompResultTy.isNull())
return Owned(new (Context) BinaryOperator(lhs, rhs, Opc, ResultTy, OpLoc));
else
return Owned(new (Context) CompoundAssignOperator(lhs, rhs, Opc, ResultTy,
- CompTy, OpLoc));
+ CompLHSTy, CompResultTy,
+ OpLoc));
}
// Binary Operators. 'Tok' is the token for the operator.
double Gr = __real g1;
cf += D;
- D += cf;
+ // FIXME: Currently unsupported!
+ //D += cf;
cf /= g1;
g1 = g1 + D;
g1 = D + g1;
--- /dev/null
+// RUN: clang-cc < %s -emit-llvm -triple i686-pc-linux-gnu > %t &&
+// RUN: grep "div i32" %t &&
+// RUN: grep "shl i32" %t
+
+unsigned char a,b;
+void c(void) {a <<= b;}
+void d(void) {a /= b;}