зеркало из https://github.com/microsoft/clang-1.git
Change Sema::CheckAddressOfOperation() to respect C99-only addressof rules.
Remove diagnostics from Sema::CheckIndirectionOperand(). C89/C99 allow dereferencing an incomplete type. clang appears to be emulating some incorrect gcc behavior (see below). void foo (void) { struct b; struct b* x = 0; struct b* y = &*x; // gcc produces an error ("dereferencing pointer to incomplete type") } With this patch, the above is now allowed. Bug/Patch by Eli Friedman! git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@45933 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
d880c18293
Коммит
08f1967167
|
@ -1618,6 +1618,17 @@ static Decl *getPrimaryDeclaration(Expr *e) {
|
|||
/// Note: The usual conversions are *not* applied to the operand of the &
|
||||
/// operator (C99 6.3.2.1p[2-4]), and its result is never an lvalue.
|
||||
QualType Sema::CheckAddressOfOperand(Expr *op, SourceLocation OpLoc) {
|
||||
if (getLangOptions().C99) {
|
||||
// Implement C99-only parts of addressof rules.
|
||||
if (UnaryOperator* uOp = dyn_cast<UnaryOperator>(op)) {
|
||||
if (uOp->getOpcode() == UnaryOperator::Deref)
|
||||
// Per C99 6.5.3.2, the address of a deref always returns a valid result
|
||||
// (assuming the deref expression is valid).
|
||||
return uOp->getSubExpr()->getType();
|
||||
}
|
||||
// Technically, there should be a check for array subscript
|
||||
// expressions here, but the result of one is always an lvalue anyway.
|
||||
}
|
||||
Decl *dcl = getPrimaryDeclaration(op);
|
||||
Expr::isLvalueResult lval = op->isLvalue();
|
||||
|
||||
|
@ -1651,19 +1662,12 @@ QualType Sema::CheckIndirectionOperand(Expr *op, SourceLocation OpLoc) {
|
|||
QualType qType = op->getType();
|
||||
|
||||
if (const PointerType *PT = qType->getAsPointerType()) {
|
||||
QualType ptype = PT->getPointeeType();
|
||||
// C99 6.5.3.2p4. "if it points to an object,...".
|
||||
if (ptype->isIncompleteType()) { // An incomplete type is not an object
|
||||
// GCC compat: special case 'void *' (treat as extension, not error).
|
||||
if (ptype->isVoidType()) {
|
||||
Diag(OpLoc, diag::ext_typecheck_deref_ptr_to_void,op->getSourceRange());
|
||||
} else {
|
||||
Diag(OpLoc, diag::err_typecheck_deref_incomplete_type,
|
||||
ptype.getAsString(), op->getSourceRange());
|
||||
return QualType();
|
||||
}
|
||||
}
|
||||
return ptype;
|
||||
// Note that per both C89 and C99, this is always legal, even
|
||||
// if ptype is an incomplete type or void.
|
||||
// It would be possible to warn about dereferencing a
|
||||
// void pointer, but it's completely well-defined,
|
||||
// and such a warning is unlikely to catch any mistakes.
|
||||
return PT->getPointeeType();
|
||||
}
|
||||
Diag(OpLoc, diag::err_typecheck_indirection_requires_pointer,
|
||||
qType.getAsString(), op->getSourceRange());
|
||||
|
|
|
@ -756,10 +756,6 @@ DIAG(err_typecheck_unary_expr, ERROR,
|
|||
"invalid argument type to unary expression '%0'")
|
||||
DIAG(err_typecheck_indirection_requires_pointer, ERROR,
|
||||
"indirection requires pointer operand ('%0' invalid)")
|
||||
DIAG(err_typecheck_deref_incomplete_type, ERROR,
|
||||
"dereferencing pointer to incomplete type '%0'")
|
||||
DIAG(ext_typecheck_deref_ptr_to_void, WARNING,
|
||||
"dereferencing void pointer")
|
||||
DIAG(err_typecheck_invalid_operands, ERROR,
|
||||
"invalid operands to binary expression ('%0' and '%1')")
|
||||
DIAG(err_typecheck_sub_ptr_object, ERROR,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// RUN: clang -fsyntax-only -verify -pedantic %s
|
||||
void foo() {
|
||||
*(0 ? (double *)0 : (void *)0) = 0;
|
||||
*((void *) 0) = 0; // -expected-warning {{dereferencing void pointer}} -expected-error {{incomplete type 'void' is not assignable}}
|
||||
*((void *) 0) = 0; // -expected-error {{incomplete type 'void' is not assignable}}
|
||||
double *dp;
|
||||
int *ip;
|
||||
void *vp;
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
// RUN: clang -fsyntax-only -verify -std=c90 %s
|
||||
void
|
||||
foo (void)
|
||||
{
|
||||
struct b;
|
||||
struct b* x = 0;
|
||||
struct b* y = &*x;
|
||||
}
|
||||
|
||||
void foo2 (void)
|
||||
{
|
||||
typedef int (*arrayptr)[];
|
||||
arrayptr x = 0;
|
||||
arrayptr y = &*x;
|
||||
}
|
||||
|
||||
void foo3 (void)
|
||||
{
|
||||
void* x = 0;
|
||||
void* y = &*x; // expected-error {{invalid lvalue in address expression}}
|
||||
}
|
||||
|
Загрузка…
Ссылка в новой задаче