[cfe-commits] r68902 - in /cfe/trunk: include/clang/Parse/Action.h lib/Parse/ParseDeclCXX.cpp lib/Sema/Sema.h lib/Sema/SemaDeclCXX.cpp lib/Sema/SemaExprCXX.cpp lib/Sema/SemaOverload.cpp lib/Sema/SemaStmt.cpp test/SemaCXX/deleted-function.cpp test/SemaCXX/rval-references.cpp

Sebastian Redl sebastian.redl at getdesigned.at
Sun Apr 12 10:16:30 PDT 2009


Author: cornedbee
Date: Sun Apr 12 12:16:29 2009
New Revision: 68902

URL: http://llvm.org/viewvc/llvm-project?rev=68902&view=rev
Log:
Parse deleted member functions. Parsing member declarations goes through a different code path that I forgot previously.
Implement the rvalue reference overload dance for returning local objects. Returning a local object first tries to find a move constructor now.
The error message when no move constructor is defined (or is not applicable) and the copy constructor is deleted is quite ugly, though.

Modified:
    cfe/trunk/include/clang/Parse/Action.h
    cfe/trunk/lib/Parse/ParseDeclCXX.cpp
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp
    cfe/trunk/lib/Sema/SemaExprCXX.cpp
    cfe/trunk/lib/Sema/SemaOverload.cpp
    cfe/trunk/lib/Sema/SemaStmt.cpp
    cfe/trunk/test/SemaCXX/deleted-function.cpp
    cfe/trunk/test/SemaCXX/rval-references.cpp

Modified: cfe/trunk/include/clang/Parse/Action.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Action.h?rev=68902&r1=68901&r2=68902&view=diff

==============================================================================
--- cfe/trunk/include/clang/Parse/Action.h (original)
+++ cfe/trunk/include/clang/Parse/Action.h Sun Apr 12 12:16:29 2009
@@ -1038,11 +1038,13 @@
   /// declarator is parsed. 'AS' is the access specifier, 'BitfieldWidth'
   /// specifies the bitfield width if there is one and 'Init' specifies the
   /// initializer if any. 'LastInGroup' is non-null for cases where one declspec
-  /// has multiple declarators on it.
+  /// has multiple declarators on it. 'Deleted' is true if there's a =delete
+  /// specifier on the function.
   virtual DeclPtrTy ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS,
                                              Declarator &D,
                                              ExprTy *BitfieldWidth,
-                                             ExprTy *Init) {
+                                             ExprTy *Init,
+                                             bool Deleted = false) {
     return DeclPtrTy();
   }
 

Modified: cfe/trunk/lib/Parse/ParseDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDeclCXX.cpp?rev=68902&r1=68901&r2=68902&view=diff

==============================================================================
--- cfe/trunk/lib/Parse/ParseDeclCXX.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDeclCXX.cpp Sun Apr 12 12:16:29 2009
@@ -668,7 +668,7 @@
 ///         declarator constant-initializer[opt]
 ///         identifier[opt] ':' constant-expression
 ///
-///       pure-specifier:   [TODO]
+///       pure-specifier:
 ///         '= 0'
 ///
 ///       constant-initializer:
@@ -767,6 +767,7 @@
   llvm::SmallVector<DeclPtrTy, 8> DeclsInGroup;
   OwningExprResult BitfieldSize(Actions);
   OwningExprResult Init(Actions);
+  bool Deleted = false;
 
   while (1) {
 
@@ -787,12 +788,21 @@
     //
     // constant-initializer:
     //   '=' constant-expression
+    //
+    // defaulted/deleted function-definition:
+    //   '=' 'default'                          [TODO]
+    //   '=' 'delete'
 
     if (Tok.is(tok::equal)) {
       ConsumeToken();
-      Init = ParseInitializer();
-      if (Init.isInvalid())
-        SkipUntil(tok::comma, true, true);
+      if (getLang().CPlusPlus0x && Tok.is(tok::kw_delete)) {
+        ConsumeToken();
+        Deleted = true;
+      } else {
+        Init = ParseInitializer();
+        if (Init.isInvalid())
+          SkipUntil(tok::comma, true, true);
+      }
     }
 
     // If attributes exist after the declarator, parse them.
@@ -808,7 +818,8 @@
     DeclPtrTy ThisDecl = Actions.ActOnCXXMemberDeclarator(CurScope, AS,
                                                           DeclaratorInfo,
                                                           BitfieldSize.release(),
-                                                          Init.release());
+                                                          Init.release(),
+                                                          Deleted);
     if (ThisDecl)
       DeclsInGroup.push_back(ThisDecl);
 
@@ -858,6 +869,7 @@
     DeclaratorInfo.clear();
     BitfieldSize = 0;
     Init = 0;
+    Deleted = false;
     
     // Attributes are only allowed on the second declarator.
     if (Tok.is(tok::kw___attribute)) {

Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=68902&r1=68901&r2=68902&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Sun Apr 12 12:16:29 2009
@@ -504,7 +504,8 @@
   ImplicitConversionSequence 
   TryImplicitConversion(Expr* From, QualType ToType,
                         bool SuppressUserConversions = false,
-                        bool AllowExplicit = false);
+                        bool AllowExplicit = false,
+                        bool ForceRValue = false);
   bool IsStandardConversion(Expr *From, QualType ToType, 
                             StandardConversionSequence& SCS);
   bool IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType);
@@ -522,7 +523,7 @@
   bool IsUserDefinedConversion(Expr *From, QualType ToType, 
                                UserDefinedConversionSequence& User,
                                bool AllowConversionFunctions,
-                               bool AllowExplicit);
+                               bool AllowExplicit, bool ForceRValue);
 
   ImplicitConversionSequence::CompareKind 
   CompareImplicitConversionSequences(const ImplicitConversionSequence& ICS1,
@@ -542,9 +543,10 @@
 
   ImplicitConversionSequence 
   TryCopyInitialization(Expr* From, QualType ToType,
-                        bool SuppressUserConversions = false);
+                        bool SuppressUserConversions = false,
+                        bool ForceRValue = false);
   bool PerformCopyInitialization(Expr *&From, QualType ToType, 
-                                 const char *Flavor);
+                                 const char *Flavor, bool Elidable = false);
 
   ImplicitConversionSequence
   TryObjectArgumentInitialization(Expr *From, CXXMethodDecl *Method);
@@ -569,7 +571,8 @@
   void AddOverloadCandidate(FunctionDecl *Function, 
                             Expr **Args, unsigned NumArgs,
                             OverloadCandidateSet& CandidateSet,
-                            bool SuppressUserConversions = false);
+                            bool SuppressUserConversions = false,
+                            bool ForceRValue = false);
   void AddFunctionCandidates(const FunctionSet &Functions,
                              Expr **Args, unsigned NumArgs,
                              OverloadCandidateSet& CandidateSet,
@@ -577,7 +580,8 @@
   void AddMethodCandidate(CXXMethodDecl *Method,
                           Expr *Object, Expr **Args, unsigned NumArgs,
                           OverloadCandidateSet& CandidateSet,
-                          bool SuppressUserConversions = false);
+                          bool SuppressUserConversions = false,
+                          bool ForceRValue = false);
   void AddConversionCandidate(CXXConversionDecl *Conversion,
                               Expr *From, QualType ToType,
                               OverloadCandidateSet& CandidateSet);
@@ -1590,11 +1594,12 @@
   //
   virtual bool isCurrentClassName(const IdentifierInfo &II, Scope *S,
                                   const CXXScopeSpec *SS);
-  
+
   virtual DeclPtrTy ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS,
                                              Declarator &D,
                                              ExprTy *BitfieldWidth,
-                                             ExprTy *Init);
+                                             ExprTy *Init,
+                                             bool Deleted = false);
 
   virtual MemInitResult ActOnMemInitializer(DeclPtrTy ConstructorD,
                                             Scope *S,
@@ -2319,7 +2324,9 @@
   bool IsStringLiteralToNonConstPointerConversion(Expr *From, QualType ToType);
 
   bool PerformImplicitConversion(Expr *&From, QualType ToType, 
-                                 const char *Flavor, bool AllowExplicit = false);
+                                 const char *Flavor,
+                                 bool AllowExplicit = false,
+                                 bool Elidable = false);
   bool PerformImplicitConversion(Expr *&From, QualType ToType, 
                                  const ImplicitConversionSequence& ICS,
                                  const char *Flavor);
@@ -2415,7 +2422,8 @@
   bool CheckReferenceInit(Expr *&simpleInit_or_initList, QualType &declType,
                           ImplicitConversionSequence *ICS = 0,
                           bool SuppressUserConversions = false,
-                          bool AllowExplicit = false);
+                          bool AllowExplicit = false,
+                          bool ForceRValue = false);
 
   /// CheckCastTypes - Check type constraints for casting between types.
   bool CheckCastTypes(SourceRange TyRange, QualType CastTy, Expr *&CastExpr);

Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=68902&r1=68901&r2=68902&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Sun Apr 12 12:16:29 2009
@@ -473,7 +473,7 @@
 /// declarators on it.
 Sema::DeclPtrTy
 Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
-                               ExprTy *BW, ExprTy *InitExpr) {
+                               ExprTy *BW, ExprTy *InitExpr, bool Deleted) {
   const DeclSpec &DS = D.getDeclSpec();
   DeclarationName Name = GetNameForDeclarator(D);
   Expr *BitWidth = static_cast<Expr*>(BW);
@@ -591,6 +591,8 @@
 
   if (Init)
     AddInitializerToDecl(DeclPtrTy::make(Member), ExprArg(*this, Init), false);
+  if (Deleted) // FIXME: Source location is not very good.
+    SetDeclDeleted(DeclPtrTy::make(Member), D.getSourceRange().getBegin());
 
   if (isInstField) {
     FieldCollector->Add(cast<FieldDecl>(Member));
@@ -1981,11 +1983,12 @@
 /// suppressed.
 /// When @p AllowExplicit, we also permit explicit user-defined
 /// conversion functions.
+/// When @p ForceRValue, we unconditionally treat the initializer as an rvalue.
 bool 
 Sema::CheckReferenceInit(Expr *&Init, QualType &DeclType, 
                          ImplicitConversionSequence *ICS,
                          bool SuppressUserConversions,
-                         bool AllowExplicit) {
+                         bool AllowExplicit, bool ForceRValue) {
   assert(DeclType->isReferenceType() && "Reference init needs a reference");
 
   QualType T1 = DeclType->getAsReferenceType()->getPointeeType();
@@ -2014,7 +2017,8 @@
   // Compute some basic properties of the types and the initializer.
   bool isRValRef = DeclType->isRValueReferenceType();
   bool DerivedToBase = false;
-  Expr::isLvalueResult InitLvalue = Init->isLvalue(Context);
+  Expr::isLvalueResult InitLvalue = ForceRValue ? Expr::LV_InvalidExpression :
+                                                  Init->isLvalue(Context);
   ReferenceCompareResult RefRelationship 
     = CompareReferenceRelationship(T1, T2, DerivedToBase);
 

Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=68902&r1=68901&r2=68902&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Sun Apr 12 12:16:29 2009
@@ -737,13 +737,23 @@
 /// error, false otherwise. The expression From is replaced with the
 /// converted expression. Flavor is the kind of conversion we're
 /// performing, used in the error message. If @p AllowExplicit,
-/// explicit user-defined conversions are permitted.
-bool 
+/// explicit user-defined conversions are permitted. @p Elidable should be true
+/// when called for copies which may be elided (C++ 12.8p15). C++0x overload
+/// resolution works differently in that case.
+bool
 Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
-                                const char *Flavor, bool AllowExplicit)
+                                const char *Flavor, bool AllowExplicit,
+                                bool Elidable)
 {
-  ImplicitConversionSequence ICS = TryImplicitConversion(From, ToType, false,
-                                                         AllowExplicit);
+  ImplicitConversionSequence ICS;
+  ICS.ConversionKind = ImplicitConversionSequence::BadConversion;
+  if (Elidable && getLangOptions().CPlusPlus0x) {
+    ICS = TryImplicitConversion(From, ToType, /*SuppressUserConversions*/false,
+                                AllowExplicit, /*ForceRValue*/true);
+  }
+  if (ICS.ConversionKind == ImplicitConversionSequence::BadConversion) {
+    ICS = TryImplicitConversion(From, ToType, false, AllowExplicit);
+  }
   return PerformImplicitConversion(From, ToType, ICS, Flavor);
 }
 

Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=68902&r1=68901&r2=68902&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Sun Apr 12 12:16:29 2009
@@ -376,17 +376,20 @@
 /// not permitted.
 /// If @p AllowExplicit, then explicit user-defined conversions are
 /// permitted.
+/// If @p ForceRValue, then overloading is performed as if From was an rvalue,
+/// no matter its actual lvalueness.
 ImplicitConversionSequence
 Sema::TryImplicitConversion(Expr* From, QualType ToType,
                             bool SuppressUserConversions,
-                            bool AllowExplicit)
+                            bool AllowExplicit, bool ForceRValue)
 {
   ImplicitConversionSequence ICS;
   if (IsStandardConversion(From, ToType, ICS.Standard))
     ICS.ConversionKind = ImplicitConversionSequence::StandardConversion;
   else if (getLangOptions().CPlusPlus &&
            IsUserDefinedConversion(From, ToType, ICS.UserDefined, 
-                                   !SuppressUserConversions, AllowExplicit)) {
+                                   !SuppressUserConversions, AllowExplicit,
+                                   ForceRValue)) {
     ICS.ConversionKind = ImplicitConversionSequence::UserDefinedConversion;
     // C++ [over.ics.user]p4:
     //   A conversion of an expression of class type to the same class
@@ -1313,10 +1316,13 @@
 /// \param AllowExplicit  true if the conversion should consider C++0x
 /// "explicit" conversion functions as well as non-explicit conversion
 /// functions (C++0x [class.conv.fct]p2).
+///
+/// \param ForceRValue  true if the expression should be treated as an rvalue
+/// for overload resolution.
 bool Sema::IsUserDefinedConversion(Expr *From, QualType ToType, 
                                    UserDefinedConversionSequence& User,
                                    bool AllowConversionFunctions,
-                                   bool AllowExplicit)
+                                   bool AllowExplicit, bool ForceRValue)
 {
   OverloadCandidateSet CandidateSet;
   if (const RecordType *ToRecordType = ToType->getAsRecordType()) {
@@ -1340,7 +1346,7 @@
         CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(*Con);
         if (Constructor->isConvertingConstructor())
           AddOverloadCandidate(Constructor, &From, 1, CandidateSet,
-                               /*SuppressUserConversions=*/true);
+                               /*SuppressUserConversions=*/true, ForceRValue);
       }
     }
   }
@@ -1856,24 +1862,29 @@
 /// sequence required to pass this argument, which may be a bad
 /// conversion sequence (meaning that the argument cannot be passed to
 /// a parameter of this type). If @p SuppressUserConversions, then we
-/// do not permit any user-defined conversion sequences.
+/// do not permit any user-defined conversion sequences. If @p ForceRValue,
+/// then we treat @p From as an rvalue, even if it is an lvalue.
 ImplicitConversionSequence 
 Sema::TryCopyInitialization(Expr *From, QualType ToType, 
-                            bool SuppressUserConversions) {
+                            bool SuppressUserConversions, bool ForceRValue) {
   if (ToType->isReferenceType()) {
     ImplicitConversionSequence ICS;
-    CheckReferenceInit(From, ToType, &ICS, SuppressUserConversions);
+    CheckReferenceInit(From, ToType, &ICS, SuppressUserConversions,
+                       /*AllowExplicit=*/false, ForceRValue);
     return ICS;
   } else {
-    return TryImplicitConversion(From, ToType, SuppressUserConversions);
+    return TryImplicitConversion(From, ToType, SuppressUserConversions,
+                                 ForceRValue);
   }
 }
 
-/// PerformArgumentPassing - Pass the argument Arg into a parameter of
-/// type ToType. Returns true (and emits a diagnostic) if there was
-/// an error, returns false if the initialization succeeded.
+/// PerformCopyInitialization - Copy-initialize an object of type @p ToType with
+/// the expression @p From. Returns true (and emits a diagnostic) if there was
+/// an error, returns false if the initialization succeeded. Elidable should
+/// be true when the copy may be elided (C++ 12.8p15). Overload resolution works
+/// differently in C++0x for this case.
 bool Sema::PerformCopyInitialization(Expr *&From, QualType ToType, 
-                                     const char* Flavor) {
+                                     const char* Flavor, bool Elidable) {
   if (!getLangOptions().CPlusPlus) {
     // In C, argument passing is the same as performing an assignment.
     QualType FromType = From->getType();
@@ -1883,13 +1894,14 @@
     return DiagnoseAssignmentResult(ConvTy, From->getLocStart(), ToType,
                                     FromType, From, Flavor);
   }
-  
+
   if (ToType->isReferenceType())
     return CheckReferenceInit(From, ToType);
 
-  if (!PerformImplicitConversion(From, ToType, Flavor))
+  if (!PerformImplicitConversion(From, ToType, Flavor,
+                                 /*AllowExplicit=*/false, Elidable))
     return false;
-  
+
   return Diag(From->getSourceRange().getBegin(),
               diag::err_typecheck_convert_incompatible)
     << ToType << From->getType() << Flavor << From->getSourceRange();
@@ -1997,11 +2009,15 @@
 /// candidate functions, using the given function call arguments.  If
 /// @p SuppressUserConversions, then don't allow user-defined
 /// conversions via constructors or conversion operators.
+/// If @p ForceRValue, treat all arguments as rvalues. This is a slightly
+/// hacky way to implement the overloading rules for elidable copy
+/// initialization in C++0x (C++0x 12.8p15).
 void 
 Sema::AddOverloadCandidate(FunctionDecl *Function, 
                            Expr **Args, unsigned NumArgs,
                            OverloadCandidateSet& CandidateSet,
-                           bool SuppressUserConversions)
+                           bool SuppressUserConversions,
+                           bool ForceRValue)
 {
   const FunctionProtoType* Proto 
     = dyn_cast<FunctionProtoType>(Function->getType()->getAsFunctionType());
@@ -2017,7 +2033,7 @@
     // function, e.g., X::f(). We use a NULL object as the implied
     // object argument (C++ [over.call.func]p3).
     AddMethodCandidate(Method, 0, Args, NumArgs, CandidateSet, 
-                       SuppressUserConversions);
+                       SuppressUserConversions, ForceRValue);
     return;
   }
 
@@ -2064,7 +2080,7 @@
       QualType ParamType = Proto->getArgType(ArgIdx);
       Candidate.Conversions[ArgIdx] 
         = TryCopyInitialization(Args[ArgIdx], ParamType, 
-                                SuppressUserConversions);
+                                SuppressUserConversions, ForceRValue);
       if (Candidate.Conversions[ArgIdx].ConversionKind 
             == ImplicitConversionSequence::BadConversion) {
         Candidate.Viable = false;
@@ -2099,12 +2115,14 @@
 /// @c o.f(a1,a2), @c Object will contain @c o and @c Args will contain
 /// both @c a1 and @c a2. If @p SuppressUserConversions, then don't
 /// allow user-defined conversions via constructors or conversion
-/// operators.
+/// operators. If @p ForceRValue, treat all arguments as rvalues. This is
+/// a slightly hacky way to implement the overloading rules for elidable copy
+/// initialization in C++0x (C++0x 12.8p15).
 void 
 Sema::AddMethodCandidate(CXXMethodDecl *Method, Expr *Object,
                          Expr **Args, unsigned NumArgs,
                          OverloadCandidateSet& CandidateSet,
-                         bool SuppressUserConversions)
+                         bool SuppressUserConversions, bool ForceRValue)
 {
   const FunctionProtoType* Proto 
     = dyn_cast<FunctionProtoType>(Method->getType()->getAsFunctionType());
@@ -2169,7 +2187,7 @@
       QualType ParamType = Proto->getArgType(ArgIdx);
       Candidate.Conversions[ArgIdx + 1] 
         = TryCopyInitialization(Args[ArgIdx], ParamType, 
-                                SuppressUserConversions);
+                                SuppressUserConversions, ForceRValue);
       if (Candidate.Conversions[ArgIdx + 1].ConversionKind 
             == ImplicitConversionSequence::BadConversion) {
         Candidate.Viable = false;

Modified: cfe/trunk/lib/Sema/SemaStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaStmt.cpp?rev=68902&r1=68901&r2=68902&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaStmt.cpp (original)
+++ cfe/trunk/lib/Sema/SemaStmt.cpp Sun Apr 12 12:16:29 2009
@@ -754,6 +754,32 @@
   return Owned(new (Context) ReturnStmt(ReturnLoc, RetValExp));
 }
 
+/// IsReturnCopyElidable - Whether returning @p RetExpr from a function that
+/// returns a @p RetType fulfills the criteria for copy elision (C++0x 12.8p15).
+static bool IsReturnCopyElidable(ASTContext &Ctx, QualType RetType,
+                                 Expr *RetExpr) {
+  QualType ExprType = RetExpr->getType();
+  // - in a return statement in a function with ...
+  // ... a class return type ...
+  if (!RetType->isRecordType())
+    return false;
+  // ... the same cv-unqualified type as the function return type ...
+  if (Ctx.getCanonicalType(RetType).getUnqualifiedType() !=
+      Ctx.getCanonicalType(ExprType).getUnqualifiedType())
+    return false;
+  // ... the expression is the name of a non-volatile automatic object ...
+  // We ignore parentheses here.
+  // FIXME: Is this compliant?
+  const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(RetExpr->IgnoreParens());
+  if (!DR)
+    return false;
+  const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl());
+  if (!VD)
+    return false;
+  return VD->hasLocalStorage() && !VD->getType()->isReferenceType()
+    && !VD->getType().isVolatileQualified();
+}
+
 Action::OwningStmtResult
 Sema::ActOnReturnStmt(SourceLocation ReturnLoc, ExprArg rex) {
   Expr *RetValExp = static_cast<Expr *>(rex.release());
@@ -800,16 +826,31 @@
 
   if (!FnRetType->isDependentType() && !RetValExp->isTypeDependent()) {
     // we have a non-void function with an expression, continue checking
-    QualType RetValType = RetValExp->getType();
 
     // C99 6.8.6.4p3(136): The return statement is not an assignment. The 
     // overlap restriction of subclause 6.5.16.1 does not apply to the case of 
     // function return.
 
+    // C++0x 12.8p15: When certain criteria are met, an implementation is
+    //   allowed to omit the copy construction of a class object, [...]
+    //   - in a return statement in a function with a class return type, when
+    //     the expression is the name of a non-volatile automatic object with
+    //     the same cv-unqualified type as the function return type, the copy
+    //     operation can be omitted [...]
+    // C++0x 12.8p16: When the criteria for elision of a copy operation are met
+    //   and the object to be copied is designated by an lvalue, overload
+    //   resolution to select the constructor for the copy is first performed
+    //   as if the object were designated by an rvalue.
+    // Note that we only compute Elidable if we're in C++0x, since we don't
+    // care otherwise.
+    bool Elidable = getLangOptions().CPlusPlus0x ?
+                      IsReturnCopyElidable(Context, FnRetType, RetValExp) :
+                      false;
+
     // In C++ the return statement is handled via a copy initialization.
     // the C version of which boils down to CheckSingleAssignmentConstraints.
-    // FIXME: Leaks RetValExp.
-    if (PerformCopyInitialization(RetValExp, FnRetType, "returning"))
+    // FIXME: Leaks RetValExp on error.
+    if (PerformCopyInitialization(RetValExp, FnRetType, "returning", Elidable))
       return StmtError();
 
     if (RetValExp) CheckReturnStackAddr(RetValExp, FnRetType, ReturnLoc);

Modified: cfe/trunk/test/SemaCXX/deleted-function.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/deleted-function.cpp?rev=68902&r1=68901&r2=68902&view=diff

==============================================================================
--- cfe/trunk/test/SemaCXX/deleted-function.cpp (original)
+++ cfe/trunk/test/SemaCXX/deleted-function.cpp Sun Apr 12 12:16:29 2009
@@ -15,8 +15,20 @@
 void ov(int) {} // expected-note {{candidate function}}
 void ov(double) = delete; // expected-note {{candidate function has been explicitly deleted}}
 
+struct WithDel {
+  WithDel() = delete; // expected-note {{candidate function has been explicitly deleted}}
+  void fn() = delete; // expected-note {{function has been explicitly marked deleted here}}
+  operator int() = delete;
+  void operator +(int) = delete;
+};
+
 void test() {
   fn(); // expected-error {{call to deleted function 'fn'}}
   ov(1);
   ov(1.0); // expected-error {{call to deleted function 'ov'}}
+
+  WithDel dd; // expected-error {{call to deleted constructor of 'dd'}}
+  WithDel *d = 0;
+  d->fn(); // expected-error {{attempt to use a deleted function}}
+  int i = *d; // expected-error {{incompatible type initializing}}
 }

Modified: cfe/trunk/test/SemaCXX/rval-references.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/rval-references.cpp?rev=68902&r1=68901&r2=68902&view=diff

==============================================================================
--- cfe/trunk/test/SemaCXX/rval-references.cpp (original)
+++ cfe/trunk/test/SemaCXX/rval-references.cpp Sun Apr 12 12:16:29 2009
@@ -52,3 +52,40 @@
   } catch(int&&) { // expected-error {{cannot catch exceptions by rvalue reference}}
   }
 }
+
+int&& should_warn(int i) {
+  // FIXME: The stack address return test doesn't reason about casts.
+  return static_cast<int&&>(i); // xpected-warning {{returning reference to temporary}}
+}
+int&& should_not_warn(int&& i) { // But GCC 4.4 does
+  return static_cast<int&&>(i);
+}
+
+
+// Test the return dance. This also tests IsReturnCopyElidable.
+struct MoveOnly {
+  MoveOnly();
+  MoveOnly(const MoveOnly&) = delete;
+  MoveOnly(MoveOnly&&);
+  MoveOnly(int&&);
+};
+
+MoveOnly returning() {
+  MoveOnly mo;
+  return mo;
+}
+
+MoveOnly gmo;
+MoveOnly returningNonEligible() {
+  int i;
+  static MoveOnly mo;
+  MoveOnly &r = mo;
+  if (0) // Copy from global can't be elided
+    return gmo; // expected-error {{incompatible type returning}}
+  else if (0) // Copy from local static can't be elided
+    return mo; // expected-error {{incompatible type returning}}
+  else if (0) // Copy from reference can't be elided
+    return r; // expected-error {{incompatible type returning}}
+  else // Construction from different type can't be elided
+    return i; // expected-error {{incompatible type returning}}
+}





More information about the cfe-commits mailing list