aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/AST/Expr.h3
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td2
-rw-r--r--lib/AST/Expr.cpp16
-rw-r--r--lib/Sema/SemaExpr.cpp7
-rw-r--r--test/Sema/deref.c7
-rw-r--r--test/Sema/varargs.c2
6 files changed, 27 insertions, 10 deletions
diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h
index 38d2124e64..441aae2c73 100644
--- a/include/clang/AST/Expr.h
+++ b/include/clang/AST/Expr.h
@@ -147,6 +147,9 @@ public:
LV_MemberFunction
};
isLvalueResult isLvalue(ASTContext &Ctx) const;
+
+ // Same as above, but excluding checks for non-object and void types in C
+ isLvalueResult isLvalueInternal(ASTContext &Ctx) const;
/// isModifiableLvalue - C99 6.3.2.1: an lvalue that does not have array type,
/// does not have an incomplete type, does not have a const-qualified type,
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 0e6ce3b072..1ea237eef5 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -1021,6 +1021,8 @@ def err_typecheck_sclass_func : Error<"illegal storage class on function">;
def err_static_block_func : Error<
"function declared in block scope cannot have 'static' storage class">;
def err_typecheck_address_of : Error<"address of %0 requested">;
+def ext_typecheck_addrof_void : Extension<
+ "ISO C forbids taking the address of an expression of type 'void'">;
def err_typecheck_invalid_lvalue_addrof : Error<
"address expression must be an lvalue or a function designator">;
def err_typecheck_unary_expr : Error<
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index 19d67bb7f8..13d2a1be3f 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -603,18 +603,26 @@ static bool DeclCanBeLvalue(const NamedDecl *Decl, ASTContext &Ctx) {
/// - reference type [C++ [expr]]
///
Expr::isLvalueResult Expr::isLvalue(ASTContext &Ctx) const {
+ assert(!TR->isReferenceType() && "Expressions can't have reference type.");
+
+ isLvalueResult Res = isLvalueInternal(Ctx);
+ if (Res != LV_Valid || Ctx.getLangOptions().CPlusPlus)
+ return Res;
+
// first, check the type (C99 6.3.2.1). Expressions with function
// type in C are not lvalues, but they can be lvalues in C++.
- if (!Ctx.getLangOptions().CPlusPlus && TR->isFunctionType())
+ if (TR->isFunctionType())
return LV_NotObjectType;
// Allow qualified void which is an incomplete type other than void (yuck).
if (TR->isVoidType() && !Ctx.getCanonicalType(TR).getCVRQualifiers())
return LV_IncompleteVoidType;
- assert(!TR->isReferenceType() && "Expressions can't have reference type.");
+ return LV_Valid;
+}
- // the type looks fine, now check the expression
+// Check whether the expression can be sanely treated like an l-value
+Expr::isLvalueResult Expr::isLvalueInternal(ASTContext &Ctx) const {
switch (getStmtClass()) {
case StringLiteralClass: // C99 6.5.1p4
case ObjCEncodeExprClass: // @encode behaves like its string in every way.
@@ -754,8 +762,6 @@ Expr::isLvalueResult Expr::isLvalue(ASTContext &Ctx) const {
return LV_Valid;
case PredefinedExprClass:
return LV_Valid;
- case VAArgExprClass:
- return LV_NotObjectType;
case CXXDefaultArgExprClass:
return cast<CXXDefaultArgExpr>(this)->getExpr()->isLvalue(Ctx);
case CXXConditionDeclExprClass:
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 6ce98cd28f..36ec9c65c1 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -4245,7 +4245,12 @@ QualType Sema::CheckAddressOfOperand(Expr *op, SourceLocation OpLoc) {
if (lval != Expr::LV_Valid) { // C99 6.5.3.2p1
// The operand must be either an l-value or a function designator
- if (!op->getType()->isFunctionType()) {
+ if (op->getType()->isFunctionType()) {
+ // Function designator is valid
+ } else if (lval == Expr::LV_IncompleteVoidType) {
+ Diag(OpLoc, diag::ext_typecheck_addrof_void)
+ << op->getSourceRange();
+ } else {
// FIXME: emit more specific diag...
Diag(OpLoc, diag::err_typecheck_invalid_lvalue_addrof)
<< op->getSourceRange();
diff --git a/test/Sema/deref.c b/test/Sema/deref.c
index fad56430a0..965940e26d 100644
--- a/test/Sema/deref.c
+++ b/test/Sema/deref.c
@@ -1,4 +1,5 @@
-// RUN: clang-cc -fsyntax-only -verify -std=c90 %s
+/* RUN: clang-cc -fsyntax-only -verify -std=c90 -pedantic %s
+ */
void
foo (void)
{
@@ -17,7 +18,7 @@ void foo2 (void)
void foo3 (void)
{
void* x = 0;
- void* y = &*x; // expected-error{{address expression must be an lvalue or a function designator}}
+ void* y = &*x; /* expected-warning{{address of an expression of type 'void'}} */
}
extern const void cv1;
@@ -30,7 +31,7 @@ const void *foo4 (void)
extern void cv2;
void *foo5 (void)
{
- return &cv2; // expected-error{{address expression must be an lvalue or a function designator}}
+ return &cv2; /* expected-warning{{address of an expression of type 'void'}} */
}
typedef const void CVT;
diff --git a/test/Sema/varargs.c b/test/Sema/varargs.c
index d5b4aac6f7..8d2f0b1fa8 100644
--- a/test/Sema/varargs.c
+++ b/test/Sema/varargs.c
@@ -56,7 +56,7 @@ void f7(int a, ...) {
__builtin_va_list ap;
__builtin_va_start(ap, a);
// FIXME: This error message is sub-par.
- __builtin_va_arg(ap, int) = 1; // expected-error {{non-object type 'int' is not assignable}}
+ __builtin_va_arg(ap, int) = 1; // expected-error {{expression is not assignable}}
int *x = &__builtin_va_arg(ap, int); // expected-error {{address expression must be an lvalue or a function designator}}
__builtin_va_end(ap);
}