]> granicus.if.org Git - clang/commitdiff
Rvalue references for *this:
authorDouglas Gregor <dgregor@apple.com>
Wed, 26 Jan 2011 05:01:58 +0000 (05:01 +0000)
committerDouglas Gregor <dgregor@apple.com>
Wed, 26 Jan 2011 05:01:58 +0000 (05:01 +0000)
  - Add ref-qualifiers to the type system; they are part of the
  canonical type. Print & profile ref-qualifiers
  - Translate the ref-qualifier from the Declarator chunk for
    functions to the function type.
  - Diagnose mis-uses of ref-qualifiers w.r.t. static member
  functions, free functions, constructors, destructors, etc.
  - Add serialization and deserialization of ref-qualifiers.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@124281 91177308-0d34-0410-b5e6-96231b3b80d8

14 files changed:
include/clang/AST/Type.h
include/clang/Basic/DiagnosticSemaKinds.td
include/clang/Sema/Sema.h
lib/AST/Type.cpp
lib/AST/TypePrinter.cpp
lib/Sema/SemaDeclCXX.cpp
lib/Sema/SemaTemplateDeduction.cpp
lib/Sema/SemaType.cpp
lib/Sema/TreeTransform.h
lib/Serialization/ASTReader.cpp
lib/Serialization/ASTWriter.cpp
test/CXX/dcl.decl/dcl.meaning/dcl.fct/p6-0x.cpp [new file with mode: 0644]
test/CXX/special/class.ctor/p4-0x.cpp [new file with mode: 0644]
test/CXX/special/class.dtor/p2-0x.cpp [new file with mode: 0644]

index 95c5797e5b0199bba90271d2003961a057d60208..cc365a2f87ed0478b0f3b89b148214923926aec7 100644 (file)
@@ -823,6 +823,18 @@ public:
   }
 };
 
+/// \brief The kind of C++0x ref-qualifier associated with a function type, 
+/// which determines whether a member function's "this" object can be an 
+/// lvalue, rvalue, or neither.
+enum RefQualifierKind {
+  /// \brief No ref-qualifier was provided.
+  RQ_None = 0,
+  /// \brief An lvalue ref-qualifier was provided (\c &).
+  RQ_LValue,
+  /// \brief An rvalue ref-qualifier was provided (\c &&).
+  RQ_RValue
+};
+  
 /// Type - This is the base class of the type hierarchy.  A central concept
 /// with types is that each type always has a canonical type.  A canonical type
 /// is the type with any typedef names stripped out of it or the types it
@@ -961,6 +973,11 @@ protected:
     /// C++ 8.3.5p4: The return type, the parameter type list and the
     /// cv-qualifier-seq, [...], are part of the function type.
     unsigned TypeQuals : 3;
+    
+    /// \brief The ref-qualifier associated with a \c FunctionProtoType.
+    ///
+    /// This is a value of type \c RefQualifierKind.
+    unsigned RefQualifier : 2;
   };
 
   class ObjCObjectTypeBitfields {
@@ -2267,7 +2284,8 @@ class FunctionType : public Type {
 
 protected:
   FunctionType(TypeClass tc, QualType res, bool variadic,
-               unsigned typeQuals, QualType Canonical, bool Dependent,
+               unsigned typeQuals, RefQualifierKind RefQualifier,
+               QualType Canonical, bool Dependent,
                bool VariablyModified, bool ContainsUnexpandedParameterPack, 
                ExtInfo Info)
     : Type(tc, Canonical, Dependent, VariablyModified, 
@@ -2276,9 +2294,15 @@ protected:
     FunctionTypeBits.ExtInfo = Info.Bits;
     FunctionTypeBits.Variadic = variadic;
     FunctionTypeBits.TypeQuals = typeQuals;
+    FunctionTypeBits.RefQualifier = static_cast<unsigned>(RefQualifier);
   }
   bool isVariadic() const { return FunctionTypeBits.Variadic; }
   unsigned getTypeQuals() const { return FunctionTypeBits.TypeQuals; }
+  
+  RefQualifierKind getRefQualifier() const {
+    return static_cast<RefQualifierKind>(FunctionTypeBits.RefQualifier);
+  }
+
 public:
 
   QualType getResultType() const { return ResultType; }
@@ -2307,7 +2331,7 @@ public:
 /// no information available about its arguments.
 class FunctionNoProtoType : public FunctionType, public llvm::FoldingSetNode {
   FunctionNoProtoType(QualType Result, QualType Canonical, ExtInfo Info)
-    : FunctionType(FunctionNoProto, Result, false, 0, Canonical,
+    : FunctionType(FunctionNoProto, Result, false, 0, RQ_None, Canonical,
                    /*Dependent=*/false, Result->isVariablyModifiedType(), 
                    /*ContainsUnexpandedParameterPack=*/false, Info) {}
 
@@ -2345,13 +2369,14 @@ public:
   struct ExtProtoInfo {
     ExtProtoInfo() :
       Variadic(false), HasExceptionSpec(false), HasAnyExceptionSpec(false),
-      TypeQuals(0), NumExceptions(0), Exceptions(0) {}
+      TypeQuals(0), RefQualifier(RQ_None), NumExceptions(0), Exceptions(0) {}
 
     FunctionType::ExtInfo ExtInfo;
     bool Variadic;
     bool HasExceptionSpec;
     bool HasAnyExceptionSpec;
     unsigned char TypeQuals;
+    RefQualifierKind RefQualifier;
     unsigned NumExceptions;
     const QualType *Exceptions;
   };
@@ -2405,6 +2430,7 @@ public:
     EPI.HasExceptionSpec = hasExceptionSpec();
     EPI.HasAnyExceptionSpec = hasAnyExceptionSpec();
     EPI.TypeQuals = static_cast<unsigned char>(getTypeQuals());
+    EPI.RefQualifier = getRefQualifier();
     EPI.NumExceptions = NumExceptions;
     EPI.Exceptions = exception_begin();
     return EPI;
@@ -2434,6 +2460,12 @@ public:
   
   unsigned getTypeQuals() const { return FunctionType::getTypeQuals(); }
 
+  
+  /// \brief Retrieve the ref-qualifier associated with this function type.
+  RefQualifierKind getRefQualifier() const {
+    return FunctionType::getRefQualifier();
+  }
+  
   typedef const QualType *arg_type_iterator;
   arg_type_iterator arg_type_begin() const {
     return reinterpret_cast<const QualType *>(this+1);
index 55e9ca31338e85688eded01314f5af650d580a57..fe4c182cfecc9e5a803b2a0fe7f3c16bb50edad7 100644 (file)
@@ -730,6 +730,9 @@ def err_covariant_return_type_class_type_more_qualified : Error<
 def err_constructor_cannot_be : Error<"constructor cannot be declared '%0'">;
 def err_invalid_qualified_constructor : Error<
   "'%0' qualifier is not allowed on a constructor">;
+def err_ref_qualifier_constructor : Error<
+  "ref-qualifier '%select{&&|&}0' is not allowed on a constructor">;
+
 def err_constructor_return_type : Error<
   "constructor cannot have a return type">;
 def err_constructor_redeclared : Error<"constructor cannot be redeclared">;
@@ -749,6 +752,8 @@ def err_destructor_not_member : Error<
 def err_destructor_cannot_be : Error<"destructor cannot be declared '%0'">;
 def err_invalid_qualified_destructor : Error<
   "'%0' qualifier is not allowed on a destructor">;
+def err_ref_qualifier_destructor : Error<
+  "ref-qualifier '%select{&&|&}0' is not allowed on a destructor">;
 def err_destructor_return_type : Error<"destructor cannot have a return type">;
 def err_destructor_redeclared : Error<"destructor cannot be redeclared">;
 def err_destructor_with_params : Error<"destructor cannot have any parameters">;
@@ -2461,11 +2466,17 @@ def err_invalid_member_use_in_static_method : Error<
   "invalid use of member %0 in static member function">;
 def err_invalid_qualified_function_type : Error<
   "type qualifier is not allowed on this function">;
+def err_invalid_ref_qualifier_function_type : Error<
+  "ref-qualifier '%select{&&|&}0' is only allowed on non-static member functions,"
+  " member function pointers, and typedefs of function types">;
 def err_invalid_qualified_function_pointer : Error<
   "type qualifier is not allowed on this function %select{pointer|reference}0">;
 def err_invalid_qualified_typedef_function_type_use : Error<
   "a qualified function type cannot be used to declare a "
   "%select{static member|nonmember}0 function">;
+def err_invalid_ref_qualifier_typedef_function_type_use : Error<
+  "%select{static member|nonmember}0 function cannot have a ref-qualifier "
+  "'%select{&&|&}1'">;
 
 def err_invalid_non_static_member_use : Error<
   "invalid use of nonstatic data member %0">;
index 90242e6192528a4cc341cd39ca97da19854b217c..cc6493541b5a2775580ecf3c610570ffa2ec910a 100644 (file)
@@ -620,7 +620,8 @@ public:
                               SourceLocation AttrLoc);
   QualType BuildFunctionType(QualType T,
                              QualType *ParamTypes, unsigned NumParamTypes,
-                             bool Variadic, unsigned Quals,
+                             bool Variadic, unsigned Quals, 
+                             RefQualifierKind RefQualifier,
                              SourceLocation Loc, DeclarationName Entity,
                              FunctionType::ExtInfo Info);
   QualType BuildMemberPointerType(QualType T, QualType Class,
index d8939cc123ed3ede93898122e6158a48bd8a1d48..36d501577c4fd6628a5e07d24900c3c4850b6d46 100644 (file)
@@ -1112,7 +1112,8 @@ llvm::StringRef FunctionType::getNameForCallConv(CallingConv CC) {
 FunctionProtoType::FunctionProtoType(QualType result, const QualType *args,
                                      unsigned numArgs, QualType canonical,
                                      const ExtProtoInfo &epi)
-  : FunctionType(FunctionProto, result, epi.Variadic, epi.TypeQuals, canonical,
+  : FunctionType(FunctionProto, result, epi.Variadic, epi.TypeQuals, 
+                 epi.RefQualifier, canonical,
                  result->isDependentType(),
                  result->isVariablyModifiedType(),
                  result->containsUnexpandedParameterPack(),
@@ -1162,6 +1163,7 @@ void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID, QualType Result,
     ID.AddPointer(ArgTys[i].getAsOpaquePtr());
   ID.AddBoolean(epi.Variadic);
   ID.AddInteger(epi.TypeQuals);
+  ID.AddInteger(epi.RefQualifier);
   if (epi.HasExceptionSpec) {
     ID.AddBoolean(epi.HasAnyExceptionSpec);
     for (unsigned i = 0; i != epi.NumExceptions; ++i)
index 8a740d4ad8a6bd4faf0f1069ff1731a0c4a7769d..c0ce1f25bf578489e9d77fcd270241407000842a 100644 (file)
@@ -354,6 +354,21 @@ void TypePrinter::printFunctionProto(const FunctionProtoType *T,
     S += " __attribute__((regparm (" +
         llvm::utostr_32(Info.getRegParm()) + ")))";
   
+  AppendTypeQualList(S, T->getTypeQuals());
+
+  switch (T->getRefQualifier()) {
+  case RQ_None:
+    break;
+    
+  case RQ_LValue:
+    S += " &";
+    break;
+    
+  case RQ_RValue:
+    S += " &&";
+    break;
+  }
+  
   if (T->hasExceptionSpec()) {
     S += " throw(";
     if (T->hasAnyExceptionSpec())
@@ -370,8 +385,6 @@ void TypePrinter::printFunctionProto(const FunctionProtoType *T,
     S += ")";
   }
 
-  AppendTypeQualList(S, T->getTypeQuals());
-  
   print(T->getResultType(), S);
 }
 
index d5dea78230672e3d95e3f02f25249f6115d5b8f7..78d9a5b959acc0f6ce2474ae53d32fec2dca3632 100644 (file)
@@ -3023,6 +3023,15 @@ QualType Sema::CheckConstructorDeclarator(Declarator &D, QualType R,
     D.setInvalidType();
   }
 
+  // C++0x [class.ctor]p4:
+  //   A constructor shall not be declared with a ref-qualifier.
+  if (FTI.hasRefQualifier()) {
+    Diag(FTI.getRefQualifierLoc(), diag::err_ref_qualifier_constructor)
+      << FTI.RefQualifierIsLValueRef 
+      << FixItHint::CreateRemoval(FTI.getRefQualifierLoc());
+    D.setInvalidType();
+  }
+  
   // Rebuild the function type "R" without any type qualifiers (in
   // case any of the errors above fired) and with "void" as the
   // return type, since constructors don't have return types.
@@ -3032,7 +3041,8 @@ QualType Sema::CheckConstructorDeclarator(Declarator &D, QualType R,
 
   FunctionProtoType::ExtProtoInfo EPI = Proto->getExtProtoInfo();
   EPI.TypeQuals = 0;
-
+  EPI.RefQualifier = RQ_None;
+  
   return Context.getFunctionType(Context.VoidTy, Proto->arg_type_begin(),
                                  Proto->getNumArgs(), EPI);
 }
@@ -3173,6 +3183,15 @@ QualType Sema::CheckDestructorDeclarator(Declarator &D, QualType R,
     D.setInvalidType();
   }
 
+  // C++0x [class.dtor]p2:
+  //   A destructor shall not be declared with a ref-qualifier.
+  if (FTI.hasRefQualifier()) {
+    Diag(FTI.getRefQualifierLoc(), diag::err_ref_qualifier_destructor)
+      << FTI.RefQualifierIsLValueRef
+      << FixItHint::CreateRemoval(FTI.getRefQualifierLoc());
+    D.setInvalidType();
+  }
+  
   // Make sure we don't have any parameters.
   if (FTI.NumArgs > 0 && !FTIHasSingleVoidArgument(FTI)) {
     Diag(D.getIdentifierLoc(), diag::err_destructor_with_params);
@@ -3199,6 +3218,7 @@ QualType Sema::CheckDestructorDeclarator(Declarator &D, QualType R,
   FunctionProtoType::ExtProtoInfo EPI = Proto->getExtProtoInfo();
   EPI.Variadic = false;
   EPI.TypeQuals = 0;
+  EPI.RefQualifier = RQ_None;
   return Context.getFunctionType(Context.VoidTy, 0, 0, EPI);
 }
 
index 00d92bc6b535e7da4ac8e2ee1318adeb49fd678d..70e9973946531638d3644b997991c417e1dd8906 100644 (file)
@@ -2106,6 +2106,7 @@ Sema::SubstituteExplicitTemplateArguments(
                                       ParamTypes.data(), ParamTypes.size(),
                                       Proto->isVariadic(),
                                       Proto->getTypeQuals(),
+                                      Proto->getRefQualifier(),
                                       Function->getLocation(),
                                       Function->getDeclName(),
                                       Proto->getExtInfo());
index b663f58f0328f5a2a6dd0a3a459fe32d75ef3be8..64d5c428f3d308a0dc2365b23eee28590425e3be 100644 (file)
@@ -1269,6 +1269,7 @@ QualType Sema::BuildFunctionType(QualType T,
                                  QualType *ParamTypes,
                                  unsigned NumParamTypes,
                                  bool Variadic, unsigned Quals,
+                                 RefQualifierKind RefQualifier,
                                  SourceLocation Loc, DeclarationName Entity,
                                  FunctionType::ExtInfo Info) {
   if (T->isArrayType() || T->isFunctionType()) {
@@ -1294,6 +1295,7 @@ QualType Sema::BuildFunctionType(QualType T,
   FunctionProtoType::ExtProtoInfo EPI;
   EPI.Variadic = Variadic;
   EPI.TypeQuals = Quals;
+  EPI.RefQualifier = RefQualifier;
   EPI.ExtInfo = Info;
 
   return Context.getFunctionType(T, ParamTypes, NumParamTypes, EPI);
@@ -1722,7 +1724,10 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
         FunctionProtoType::ExtProtoInfo EPI;
         EPI.Variadic = FTI.isVariadic;
         EPI.TypeQuals = FTI.TypeQuals;
-
+        EPI.RefQualifier = !FTI.hasRefQualifier()? RQ_None
+                    : FTI.RefQualifierIsLValueRef? RQ_LValue
+                    : RQ_RValue;
+        
         // Otherwise, we have a function with an argument list that is
         // potentially variadic.
         llvm::SmallVector<QualType, 16> ArgTys;
@@ -1876,21 +1881,44 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
       FreeFunction = (DC && !DC->isRecord());
     }
 
-    if (FnTy->getTypeQuals() != 0 &&
+    // C++0x [dcl.fct]p6:
+    //   A ref-qualifier shall only be part of the function type for a
+    //   non-static member function, the function type to which a pointer to
+    //   member refers, or the top-level function type of a function typedef 
+    //   declaration.
+    if ((FnTy->getTypeQuals() != 0 || FnTy->getRefQualifier()) &&
         D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef &&
         (FreeFunction ||
          D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static)) {
-      if (D.isFunctionDeclarator())
-        Diag(D.getIdentifierLoc(), diag::err_invalid_qualified_function_type);
-      else
-        Diag(D.getIdentifierLoc(),
-             diag::err_invalid_qualified_typedef_function_type_use)
-          << FreeFunction;
-
-      // Strip the cv-quals from the type.
+      if (FnTy->getTypeQuals() != 0) {
+        if (D.isFunctionDeclarator())
+          Diag(D.getIdentifierLoc(), diag::err_invalid_qualified_function_type);
+        else
+          Diag(D.getIdentifierLoc(),
+               diag::err_invalid_qualified_typedef_function_type_use)
+            << FreeFunction;
+      }
+          
+      if (FnTy->getRefQualifier()) {
+        if (D.isFunctionDeclarator()) {
+          SourceLocation Loc
+            = D.getTypeObject(D.getNumTypeObjects()-1).Fun.getRefQualifierLoc();
+          Diag(Loc, diag::err_invalid_ref_qualifier_function_type)
+            << (FnTy->getRefQualifier() == RQ_LValue)
+            << FixItHint::CreateRemoval(Loc);
+        } else {
+          Diag(D.getIdentifierLoc(), 
+               diag::err_invalid_ref_qualifier_typedef_function_type_use)
+            << FreeFunction
+            << (FnTy->getRefQualifier() == RQ_LValue);
+        }
+      }
+          
+      // Strip the cv-quals and ref-qualifier from the type.
       FunctionProtoType::ExtProtoInfo EPI = FnTy->getExtProtoInfo();
       EPI.TypeQuals = 0;
-
+      EPI.RefQualifier = RQ_None;
+          
       T = Context.getFunctionType(FnTy->getResultType(), FnTy->arg_type_begin(),
                                   FnTy->getNumArgs(), EPI);
     }
index 04c45b8da71ce054f93efd5ec4c316ce9837ec88..3f8d3e5ec4044039e8ce5c174f1d31961463b356 100644 (file)
@@ -633,6 +633,7 @@ public:
                                     QualType *ParamTypes,
                                     unsigned NumParamTypes,
                                     bool Variadic, unsigned Quals,
+                                    RefQualifierKind RefQualifier,
                                     const FunctionType::ExtInfo &Info);
 
   /// \brief Build a new unprototyped function type.
@@ -3796,6 +3797,7 @@ TreeTransform<Derived>::TransformFunctionProtoType(TypeLocBuilder &TLB,
                                                    ParamTypes.size(),
                                                    T->isVariadic(),
                                                    T->getTypeQuals(),
+                                                   T->getRefQualifier(),
                                                    T->getExtInfo());
     if (Result.isNull())
       return QualType();
@@ -7178,7 +7180,7 @@ TreeTransform<Derived>::TransformBlockExpr(BlockExpr *E) {
                                                         ParamTypes.data(),
                                                         ParamTypes.size(),
                                                         BD->isVariadic(),
-                                                        0,
+                                                        0, RQ_None,
                                                BExprFunctionType->getExtInfo());
   CurBlock->FunctionType = FunctionType;
 
@@ -7373,9 +7375,10 @@ QualType TreeTransform<Derived>::RebuildFunctionProtoType(QualType T,
                                                         unsigned NumParamTypes,
                                                           bool Variadic,
                                                           unsigned Quals,
+                                                  RefQualifierKind RefQualifier,
                                             const FunctionType::ExtInfo &Info) {
   return SemaRef.BuildFunctionType(T, ParamTypes, NumParamTypes, Variadic,
-                                   Quals,
+                                   Quals, RefQualifier,
                                    getDerived().getBaseLocation(),
                                    getDerived().getBaseEntity(),
                                    Info);
index a722df707ee273ab3477c65091aa3e9a82f7cb12..b569f4b6219fd72aa3cd3238fc35812fb8db8492 100644 (file)
@@ -2873,6 +2873,7 @@ QualType ASTReader::ReadTypeRecord(unsigned Index) {
 
     EPI.Variadic = Record[Idx++];
     EPI.TypeQuals = Record[Idx++];
+    EPI.RefQualifier = static_cast<RefQualifierKind>(Record[Idx++]);
     EPI.HasExceptionSpec = Record[Idx++];
     EPI.HasAnyExceptionSpec = Record[Idx++];
     EPI.NumExceptions = Record[Idx++];
index 1e296e85143fdd65b902a596013a62437312d845..e90640711f9e2a2371f38d8df183f5785bdd4b42 100644 (file)
@@ -176,6 +176,7 @@ void ASTTypeWriter::VisitFunctionProtoType(const FunctionProtoType *T) {
     Writer.AddTypeRef(T->getArgType(I), Record);
   Record.push_back(T->isVariadic());
   Record.push_back(T->getTypeQuals());
+  Record.push_back(static_cast<unsigned>(T->getRefQualifier()));
   Record.push_back(T->hasExceptionSpec());
   Record.push_back(T->hasAnyExceptionSpec());
   Record.push_back(T->getNumExceptions());
diff --git a/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p6-0x.cpp b/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p6-0x.cpp
new file mode 100644 (file)
index 0000000..a2533ca
--- /dev/null
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+
+void f0() &; // expected-error{{ref-qualifier '&' is only allowed on non-static member functions, member function pointers, and typedefs of function types}}
+void f1() &&; // expected-error{{ref-qualifier '&&' is only allowed on non-static member functions, member function pointers, and typedefs of function types}}
+
+struct X {
+  void f0() &; 
+  void f1() &&;
+  static void f2() &; // expected-error{{ref-qualifier '&' is only allowed on non-static member functions, member function pointers, and typedefs of function types}}
+  static void f3() &&; // expected-error{{ref-qualifier '&&' is only allowed on non-static member functions, member function pointers, and typedefs of function types}}
+};
+
+typedef void func_type_lvalue() &;
+typedef void func_type_rvalue() &&;
+
+func_type_lvalue f2; // expected-error{{nonmember function cannot have a ref-qualifier '&'}}
+func_type_rvalue f3; // expected-error{{nonmember function cannot have a ref-qualifier '&&'}}
+
+struct Y {
+  func_type_lvalue f0;
+  func_type_rvalue f1;
+};
+
+void (X::*mpf1)() & = &X::f0;
+void (X::*mpf2)() && = &X::f1;
+
diff --git a/test/CXX/special/class.ctor/p4-0x.cpp b/test/CXX/special/class.ctor/p4-0x.cpp
new file mode 100644 (file)
index 0000000..e3508e2
--- /dev/null
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+
+// A constructor shall not be declared with a ref-qualifier.
+struct X {
+  X() &; // expected-error{{ref-qualifier '&' is not allowed on a constructor}}
+  X(int) &&; // expected-error{{ref-qualifier '&&' is not allowed on a constructor}}
+};
diff --git a/test/CXX/special/class.dtor/p2-0x.cpp b/test/CXX/special/class.dtor/p2-0x.cpp
new file mode 100644 (file)
index 0000000..53a2e03
--- /dev/null
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+
+// A destructor shall not be declared with a ref-qualifier.
+struct X {
+  ~X() &; // expected-error{{ref-qualifier '&' is not allowed on a destructor}}
+};
+
+struct Y {
+  ~Y() &&; // expected-error{{ref-qualifier '&&' is not allowed on a destructor}}
+};