Clang miscompiles casted bitfields expression

The following typescript show the problem:

$ cat w.c

struct s {
  int v:8;
};

long long f(struct s *a) {
  return
    ((long long)(a->v)) << 32;
}

$ ~/eclair/src/parser/dest/bin/clang-cc -ast-dump w.c
typedef char *__builtin_va_list;
struct s {
    int v : (IntegerLiteral 0x9933c28 'int' 8)
;
};
long long f(struct s *a) (CompoundStmt 0x9932c28
  (ReturnStmt 0x9933fc0
    (ImplicitCastExpr 0x9933fa0 'long long'
      (BinaryOperator 0x9933f78 'int' '<<'
        (ImplicitCastExpr 0x99120f8 'int'
          (ParenExpr 0x99120b0 'long long'
            (CStyleCastExpr 0x9912088 'long long'
              (ParenExpr 0x9934e68 'int'
                (MemberExpr 0x9934e40 'int' ->v 0x9933c50
                  (DeclRefExpr 0x9933d38 'struct s *' ParmVar='a'
0x9933c90))))))
        (IntegerLiteral 0x99120d0 'int' 32)))))

As you see the long long value is casted to int before the left shift
and this is wrong.

I've tracked down the problem to

Expr *Sema::UsualUnaryConversions(Expr *&Expr)

which calls

QualType isPromotableBitField(Expr *E, ASTContext &Context)

which calls

FieldDecl *Expr::getBitField()

which calls

Expr *Expr::IgnoreParenCasts()

The problem is that the latter goes down in the expression bypassing
also the CStyleCastExpr then inducing isPromotableBitField to return the
type of the bitfield and not the type of CStyleCastExpr.

The fix should be trivial (and the problem is currently rather severe),
but I want to be sure to not misunderstand something.

The following typescript show the problem:

$ cat w.c

struct s {
int v:8;
};

long long f(struct s *a) {
return
   ((long long)(a->v)) << 32;
}

$ ~/eclair/src/parser/dest/bin/clang-cc -ast-dump w.c
typedef char *__builtin_va_list;
struct s {
   int v : (IntegerLiteral 0x9933c28 'int' 8)
;
};
long long f(struct s *a) (CompoundStmt 0x9932c28
(ReturnStmt 0x9933fc0
   (ImplicitCastExpr 0x9933fa0 'long long'
     (BinaryOperator 0x9933f78 'int' '<<'
       (ImplicitCastExpr 0x99120f8 'int'
         (ParenExpr 0x99120b0 'long long'
           (CStyleCastExpr 0x9912088 'long long'
             (ParenExpr 0x9934e68 'int'
               (MemberExpr 0x9934e40 'int' ->v 0x9933c50
                 (DeclRefExpr 0x9933d38 'struct s *' ParmVar='a'
0x9933c90))))))
       (IntegerLiteral 0x99120d0 'int' 32)))))

As you see the long long value is casted to int before the left shift
and this is wrong.

I've tracked down the problem to

Expr *Sema::UsualUnaryConversions(Expr *&Expr)

which calls

QualType isPromotableBitField(Expr *E, ASTContext &Context)

which calls

FieldDecl *Expr::getBitField()

which calls

Expr *Expr::IgnoreParenCasts()

The problem is that the latter goes down in the expression bypassing
also the CStyleCastExpr then inducing isPromotableBitField to return the
type of the bitfield and not the type of CStyleCastExpr.

Oh, that's not good. We should skip ParenExprs, only.

The fix should be trivial (and the problem is currently rather severe),
but I want to be sure to not misunderstand something.

Want to submit the patch to fix this? (If not, please file a bug report so it doesn't get lost)

  - Doug

Douglas Gregor ha scritto:

Oh, that's not good. We should skip ParenExprs, only.

The fix should be trivial (and the problem is currently rather severe),
but I want to be sure to not misunderstand something.

Want to submit the patch to fix this? (If not, please file a bug report
so it doesn't get lost)

I've attached the trivial patch.

I've also verified that it does not add any other failures to the 295
currently in r7462.

bitfields.patch (431 Bytes)

Abramo Bagnara ha scritto:

Douglas Gregor ha scritto:

Oh, that's not good. We should skip ParenExprs, only.

The fix should be trivial (and the problem is currently rather severe),
but I want to be sure to not misunderstand something.

Want to submit the patch to fix this? (If not, please file a bug report
so it doesn't get lost)

I've attached the trivial patch.

There are some problems with this one-line patch?

Sorry to bother you, but I've other patchs to submits and I don't like
to superimpose too many patch in a row and svn does not help very much
to maintain them.

No, you just happened to have the misfortune of sending your patch at the beginning of a long holiday weekend here in the U.S.
I've committed the patch (with test case) here:

    http://lists.cs.uiuc.edu/pipermail/cfe-commits/Week-of-Mon-20090706/018766.html

  - Doug