aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2010-02-16 21:39:57 +0000
committerDouglas Gregor <dgregor@apple.com>2010-02-16 21:39:57 +0000
commite873fb74219f48407ae0b8fa083aa7f0b6ff1427 (patch)
treeb7bf0aa0ea04227da90991cae0cf3df06830b111
parent647a1ec397fa13af176d07d9f5d071560a94c7a9 (diff)
Introduce a new kind of failed result for isLvalue/isModifiableLvalue
which describes temporary objects of class type in C++. Use this to provide a more-specific, remappable diagnostic when takin the address of such a temporary. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@96396 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/AST/Expr.h6
-rw-r--r--include/clang/Basic/DiagnosticGroups.td3
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td5
-rw-r--r--lib/AST/Expr.cpp31
-rw-r--r--lib/Sema/SemaExpr.cpp11
-rw-r--r--test/SemaCXX/address-of-temporary.cpp12
6 files changed, 62 insertions, 6 deletions
diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h
index 114a19800f..23076b93e1 100644
--- a/include/clang/AST/Expr.h
+++ b/include/clang/AST/Expr.h
@@ -150,7 +150,8 @@ public:
LV_InvalidExpression,
LV_MemberFunction,
LV_SubObjCPropertySetting,
- LV_SubObjCPropertyGetterSetting
+ LV_SubObjCPropertyGetterSetting,
+ LV_ClassTemporary
};
isLvalueResult isLvalue(ASTContext &Ctx) const;
@@ -181,7 +182,8 @@ public:
MLV_NoSetterProperty,
MLV_MemberFunction,
MLV_SubObjCPropertySetting,
- MLV_SubObjCPropertyGetterSetting
+ MLV_SubObjCPropertyGetterSetting,
+ MLV_ClassTemporary
};
isModifiableLvalueResult isModifiableLvalue(ASTContext &Ctx,
SourceLocation *Loc = 0) const;
diff --git a/include/clang/Basic/DiagnosticGroups.td b/include/clang/Basic/DiagnosticGroups.td
index 82f9eca129..3fb011c28b 100644
--- a/include/clang/Basic/DiagnosticGroups.td
+++ b/include/clang/Basic/DiagnosticGroups.td
@@ -18,8 +18,9 @@ def Implicit : DiagGroup<"implicit", [
-// Empty DiagGroups: these are recognized by clang but ignored.
+// Empty DiagGroups are recognized by clang but ignored.
def : DiagGroup<"address">;
+def AddressOfTemporary : DiagGroup<"address-of-temporary">;
def : DiagGroup<"aggregate-return">;
def : DiagGroup<"attributes">;
def : DiagGroup<"bad-function-cast">;
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index a53b259829..3af80e4c1b 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -1783,6 +1783,11 @@ def err_unqualified_pointer_member_function : Error<
"must explicitly qualify member function %0 when taking its address">;
def err_typecheck_invalid_lvalue_addrof : Error<
"address expression must be an lvalue or a function designator">;
+def ext_typecheck_addrof_class_temporary : ExtWarn<
+ "taking the address of a temporary object of type %0">,
+ InGroup<DiagGroup<"address-of-temporary">>, DefaultError;
+def err_typecheck_addrof_class_temporary : Error<
+ "taking the address of a temporary object of type %0">;
def err_typecheck_unary_expr : Error<
"invalid argument type %0 to unary expression">;
def err_typecheck_indirection_requires_pointer : Error<
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index 4cb0aa4560..fac65064c0 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -1120,8 +1120,15 @@ Expr::isLvalueResult Expr::isLvalueInternal(ASTContext &Ctx) const {
return LV_Valid;
break;
case ImplicitCastExprClass:
- return cast<ImplicitCastExpr>(this)->isLvalueCast()? LV_Valid
- : LV_InvalidExpression;
+ if (cast<ImplicitCastExpr>(this)->isLvalueCast())
+ return LV_Valid;
+
+ // If this is a conversion to a class temporary, make a note of
+ // that.
+ if (Ctx.getLangOptions().CPlusPlus && getType()->isRecordType())
+ return LV_ClassTemporary;
+
+ break;
case ParenExprClass: // C99 6.5.1p5
return cast<ParenExpr>(this)->getSubExpr()->isLvalue(Ctx);
case BinaryOperatorClass:
@@ -1171,9 +1178,15 @@ Expr::isLvalueResult Expr::isLvalueInternal(ASTContext &Ctx) const {
if (ReturnType->isLValueReferenceType())
return LV_Valid;
+ // If the function is returning a class temporary, make a note of
+ // that.
+ if (Ctx.getLangOptions().CPlusPlus && ReturnType->isRecordType())
+ return LV_ClassTemporary;
+
break;
}
case CompoundLiteralExprClass: // C99 6.5.2.5p5
+ // FIXME: Is this what we want in C++?
return LV_Valid;
case ChooseExprClass:
// __builtin_choose_expr is an lvalue if the selected operand is.
@@ -1207,6 +1220,13 @@ Expr::isLvalueResult Expr::isLvalueInternal(ASTContext &Ctx) const {
if (cast<ExplicitCastExpr>(this)->getTypeAsWritten()->
isLValueReferenceType())
return LV_Valid;
+
+ // If this is a conversion to a class temporary, make a note of
+ // that.
+ if (Ctx.getLangOptions().CPlusPlus &&
+ cast<ExplicitCastExpr>(this)->getTypeAsWritten()->isRecordType())
+ return LV_ClassTemporary;
+
break;
case CXXTypeidExprClass:
// C++ 5.2.8p1: The result of a typeid expression is an lvalue of ...
@@ -1253,6 +1273,11 @@ Expr::isLvalueResult Expr::isLvalueInternal(ASTContext &Ctx) const {
return LV_Valid;
break;
+ case Expr::CXXConstructExprClass:
+ case Expr::CXXTemporaryObjectExprClass:
+ case Expr::CXXZeroInitValueExprClass:
+ return LV_ClassTemporary;
+
default:
break;
}
@@ -1296,6 +1321,8 @@ Expr::isModifiableLvalue(ASTContext &Ctx, SourceLocation *Loc) const {
case LV_SubObjCPropertySetting: return MLV_SubObjCPropertySetting;
case LV_SubObjCPropertyGetterSetting:
return MLV_SubObjCPropertyGetterSetting;
+ case LV_ClassTemporary:
+ return MLV_ClassTemporary;
}
// The following is illegal:
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 633884f673..e950be0485 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -5697,7 +5697,6 @@ static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) {
unsigned Diag = 0;
bool NeedType = false;
switch (IsLV) { // C99 6.5.16p2
- default: assert(0 && "Unknown result from isModifiableLvalue!");
case Expr::MLV_ConstQualified: Diag = diag::err_typecheck_assign_const; break;
case Expr::MLV_ArrayType:
Diag = diag::err_typecheck_array_not_modifiable_lvalue;
@@ -5710,7 +5709,11 @@ static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) {
case Expr::MLV_LValueCast:
Diag = diag::err_typecheck_lvalue_casts_not_supported;
break;
+ case Expr::MLV_Valid:
+ llvm_unreachable("did not take early return for MLV_Valid");
case Expr::MLV_InvalidExpression:
+ case Expr::MLV_MemberFunction:
+ case Expr::MLV_ClassTemporary:
Diag = diag::err_typecheck_expression_not_modifiable_lvalue;
break;
case Expr::MLV_IncompleteType:
@@ -5995,6 +5998,12 @@ QualType Sema::CheckAddressOfOperand(Expr *op, SourceLocation OpLoc) {
return Context.getMemberPointerType(op->getType(),
Context.getTypeDeclType(cast<RecordDecl>(dcl->getDeclContext()))
.getTypePtr());
+ } else if (lval == Expr::LV_ClassTemporary) {
+ Diag(OpLoc, isSFINAEContext()? diag::err_typecheck_addrof_class_temporary
+ : diag::ext_typecheck_addrof_class_temporary)
+ << op->getType() << op->getSourceRange();
+ if (isSFINAEContext())
+ return QualType();
} else if (lval != Expr::LV_Valid && lval != Expr::LV_IncompleteVoidType) {
// C99 6.5.3.2p1
// The operand must be either an l-value or a function designator
diff --git a/test/SemaCXX/address-of-temporary.cpp b/test/SemaCXX/address-of-temporary.cpp
new file mode 100644
index 0000000000..decdc955b6
--- /dev/null
+++ b/test/SemaCXX/address-of-temporary.cpp
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -fsyntax-only -Wno-error=address-of-temporary -verify %s
+struct X {
+ X();
+ X(int);
+ X(int, int);
+};
+
+void *f0() { return &X(); } // expected-warning{{taking the address of a temporary object}}
+void *f1() { return &X(1); } // expected-warning{{taking the address of a temporary object}}
+void *f2() { return &X(1, 2); } // expected-warning{{taking the address of a temporary object}}
+void *f3() { return &(X)1; } // expected-warning{{taking the address of a temporary object}}
+