]> granicus.if.org Git - clang/commitdiff
Introduce a new kind of failed result for isLvalue/isModifiableLvalue
authorDouglas Gregor <dgregor@apple.com>
Tue, 16 Feb 2010 21:39:57 +0000 (21:39 +0000)
committerDouglas Gregor <dgregor@apple.com>
Tue, 16 Feb 2010 21:39:57 +0000 (21:39 +0000)
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

include/clang/AST/Expr.h
include/clang/Basic/DiagnosticGroups.td
include/clang/Basic/DiagnosticSemaKinds.td
lib/AST/Expr.cpp
lib/Sema/SemaExpr.cpp
test/SemaCXX/address-of-temporary.cpp [new file with mode: 0644]

index 114a19800f50f89be0c981b9746c4a883b04fe61..23076b93e13b4b50ed5ca05ae86192e4ba8be58a 100644 (file)
@@ -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;
index 82f9eca129607423b370ba72116c77514cb834f2..3fb011c28bde88d9e27061b9897cdf9ca4acda0f 100644 (file)
@@ -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">;
index a53b259829bf75f31aab4b4e81b9390db440a79d..3af80e4c1b7cc3ecee87fc3965004ffed249207a 100644 (file)
@@ -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<
index 4cb0aa4560deaf2cb2c68eda4c61b534d648a48f..fac65064c07c586092a3716e17082a90c8e571c8 100644 (file)
@@ -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:
index 633884f673ba5f7ac7a0936875b79bd267993a47..e950be04858759b12b83a0592ec86baa74725b8b 100644 (file)
@@ -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 (file)
index 0000000..decdc95
--- /dev/null
@@ -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}}
+