Skip to content

Integer promotions not performed for qualified types (const, volatile) #270

Open
@PhilippWendler

Description

@PhilippWendler

Bug Description

Consider the following C code:

const unsigned short mask = 0;
mask+mask;
~mask;

The types of mask+mask and ~mask are int because of integer promotion, I can confirm this with a _Static_assert and gcc. However, if I parse this with Eclipse CDT and call getExpressionType() on the two expressions, I wrongly get const unsigned short.

The same problem also exists if the variable is declared volatile instead of const or with other qualifiers.

Code Analysis

Binary Expression

CASTBinaryExpression::getExpressionType() first removes typedefs and then calls this:

/**
* Performs an arithmetic conversion as described in section 6.3.1.8 of the C99 standard,
* or 5.0.9 of C++ standard
*/
public final IType convertOperandTypes(int operator, IType op1, IType op2) {
op1 = SemanticUtil.getNestedType(op1, TDEF);
op2 = SemanticUtil.getNestedType(op2, TDEF);
if (!isArithmeticOrUnscopedEnum(op1) || !isArithmeticOrUnscopedEnum(op2)) {
return null;

Typedefs are removed again, but qualifiers are kept. However, isArithmeticOrUnscopedEnum() only checks for IBasicType or IEnumeration and returns false for all other types including the CQualifierType that is passed. Then CASTBinaryExpression produces the type of the first operand as expression type.

Unary Expression

For arithmetic unary expressions, CASTUnaryExpression::getExpressionType() also removes typedefs and then calls this:

public final IType promoteType(IType type) {
if (!isIntegralOrUnscopedEnum(type))
return null;
return promote(type, getDomain(type));

The same problem as above exists, just with isIntegralOrUnscopedEnum().

Side Note: Ternary Operator

Notably, this problem does not exist for the ternary operator, although arithmetic conversion including integer promotion is also applied here. This is because CASTConditionalExpression removes qualifiers before calling CArithmeticConversion:

private IType computeResultType(IASTExpression positiveExpression, IASTExpression negativeExpression,
IType positiveType, IType negativeType) {
// Unwrap any top-level cv-qualifiers.
positiveType = CVisitor.unwrapCV(positiveType);
negativeType = CVisitor.unwrapCV(negativeType);

This was added in df6ebf0 for bug 495423.

Potential Fix

I guess that at some point before the final call to ArithmeticConversion::promote(IType, Domain) a call needs to be inserted that removes qualifiers. However, I do now know at which level this is expected to be, i.e., inside the CAST*Expression or in ArithmeticConversion. I also do not know how this applies to C++ (for which ArithmeticConversion is used as well). At least, for C code only binary expressions, unary expressions, and the ternary operator trigger calls to promote(), so there should be no unwanted side effects.

Metadata

Metadata

Assignees

No one assigned

    Labels

    languageC/C++ Language Support

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions