]> granicus.if.org Git - clang/commitdiff
Add test case for defaulted copy and move structure validation.
authorSebastian Redl <sebastian.redl@getdesigned.at>
Sun, 4 Sep 2011 18:14:28 +0000 (18:14 +0000)
committerSebastian Redl <sebastian.redl@getdesigned.at>
Sun, 4 Sep 2011 18:14:28 +0000 (18:14 +0000)
Fix bug this uncovered.
Address minor comments from Doug.
Enable cxx_implicit_moves feature.

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

lib/Lex/PPMacroExpansion.cpp
lib/Parse/ParseDeclCXX.cpp
lib/Sema/SemaDecl.cpp
lib/Sema/SemaDeclCXX.cpp
test/CXX/dcl.decl/dcl.meaning/dcl.fct/dcl.fct.def.default/p2.cpp [new file with mode: 0644]
test/Lexer/has_feature_cxx0x.cpp

index 8bc1351f6e619a54329a666633438415d665eb13..d0828d0d5d51a407395fbf15c67fd8c5ec734cd3 100644 (file)
@@ -619,7 +619,7 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) {
            .Case("cxx_deleted_functions", LangOpts.CPlusPlus0x)
            .Case("cxx_explicit_conversions", LangOpts.CPlusPlus0x)
          //.Case("cxx_generalized_initializers", LangOpts.CPlusPlus0x)
-         //.Case("cxx_implicit_moves", false)
+           .Case("cxx_implicit_moves", LangOpts.CPlusPlus0x)
          //.Case("cxx_inheriting_constructors", false)
            .Case("cxx_inline_namespaces", LangOpts.CPlusPlus0x)
          //.Case("cxx_lambdas", false)
index f1dec4ab3f2902a6612e4076de1753bffb8117a8..385683abd6a3979b2d076b9b6dd3a37a34503e69 100644 (file)
@@ -1979,7 +1979,6 @@ ExprResult Parser::ParseCXXMemberInitializer(bool IsFunction,
         return ExprResult();
       }
     } else if (Tok.is(tok::kw_default)) {
-      Diag(ConsumeToken(), diag::err_default_special_members);
       if (IsFunction)
         Diag(Tok, diag::err_default_delete_in_multiple_declaration)
           << 0 /* default */;
index dc16dcae72443ccef908b4666edb8ff3ea98ac1b..e0b69814248b20df7e8223d9b3410f45420ac0ec 100644 (file)
@@ -1529,6 +1529,8 @@ Sema::CXXSpecialMember Sema::getSpecialMember(const CXXMethodDecl *MD) {
     return Sema::CXXDestructor;
   } else if (MD->isCopyAssignmentOperator()) {
     return Sema::CXXCopyAssignment;
+  } else if (MD->isMoveAssignmentOperator()) {
+    return Sema::CXXMoveAssignment;
   }
 
   return Sema::CXXInvalid;
index f35fdeda38c9d1dee5d332ba8fbf4228acfebf7f..04868cee5763e1d8cf6a64ed80b005f9cc622a7b 100644 (file)
@@ -1984,7 +1984,7 @@ BuildImplicitBaseInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
     BasePath.push_back(BaseSpec);
     CopyCtorArg = SemaRef.ImpCastExprToType(CopyCtorArg, ArgTy,
                                             CK_UncheckedDerivedToBase,
-                                            Moving ? VK_RValue : VK_LValue,
+                                            Moving ? VK_XValue : VK_LValue,
                                             &BasePath).take();
 
     InitializationKind InitKind
@@ -2055,7 +2055,7 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
     MemberLookup.addDecl(Indirect ? cast<ValueDecl>(Indirect)
                                   : cast<ValueDecl>(Field), AS_public);
     MemberLookup.resolveKind();
-    ExprResult CopyCtorArg 
+    ExprResult CtorArg 
       = SemaRef.BuildMemberReferenceExpr(MemberExprBase,
                                          ParamType, Loc,
                                          /*IsArrow=*/false,
@@ -2063,14 +2063,14 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
                                          /*FirstQualifierInScope=*/0,
                                          MemberLookup,
                                          /*TemplateArgs=*/0);    
-    if (CopyCtorArg.isInvalid())
+    if (CtorArg.isInvalid())
       return true;
 
     // C++11 [class.copy]p15:
     //   - if a member m has rvalue reference type T&&, it is direct-initialized
     //     with static_cast<T&&>(x.m);
-    if (RefersToRValueRef(CopyCtorArg.get())) {
-      CopyCtorArg = CastForMoving(SemaRef, CopyCtorArg.take());
+    if (RefersToRValueRef(CtorArg.get())) {
+      CtorArg = CastForMoving(SemaRef, CtorArg.take());
     }
 
     // When the field we are copying is an array, create index variables for 
@@ -2104,13 +2104,12 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
         = SemaRef.BuildDeclRefExpr(IterationVar, SizeType, VK_RValue, Loc);
       assert(!IterationVarRef.isInvalid() &&
              "Reference to invented variable cannot fail!");
-      
+
       // Subscript the array with this iteration variable.
-      CopyCtorArg = SemaRef.CreateBuiltinArraySubscriptExpr(CopyCtorArg.take(),
-                                                            Loc,
+      CtorArg = SemaRef.CreateBuiltinArraySubscriptExpr(CtorArg.take(), Loc,
                                                         IterationVarRef.take(),
-                                                            Loc);
-      if (CopyCtorArg.isInvalid())
+                                                        Loc);
+      if (CtorArg.isInvalid())
         return true;
 
       BaseType = Array->getElementType();
@@ -2118,7 +2117,7 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
 
     // The array subscript expression is an lvalue, which is wrong for moving.
     if (Moving && InitializingArray)
-      CopyCtorArg = CastForMoving(SemaRef, CopyCtorArg.take());
+      CtorArg = CastForMoving(SemaRef, CtorArg.take());
 
     // Construct the entity that we will be initializing. For an array, this
     // will be first element in the array, which may require several levels
@@ -2138,13 +2137,13 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
     InitializationKind InitKind =
       InitializationKind::CreateDirect(Loc, SourceLocation(), SourceLocation());
     
-    Expr *CopyCtorArgE = CopyCtorArg.takeAs<Expr>();
+    Expr *CtorArgE = CtorArg.takeAs<Expr>();
     InitializationSequence InitSeq(SemaRef, Entities.back(), InitKind,
-                                   &CopyCtorArgE, 1);
+                                   &CtorArgE, 1);
     
     ExprResult MemberInit
       = InitSeq.Perform(SemaRef, Entities.back(), InitKind, 
-                        MultiExprArg(&CopyCtorArgE, 1));
+                        MultiExprArg(&CtorArgE, 1));
     MemberInit = SemaRef.MaybeCreateExprWithCleanups(MemberInit);
     if (MemberInit.isInvalid())
       return true;
diff --git a/test/CXX/dcl.decl/dcl.meaning/dcl.fct/dcl.fct.def.default/p2.cpp b/test/CXX/dcl.decl/dcl.meaning/dcl.fct/dcl.fct.def.default/p2.cpp
new file mode 100644 (file)
index 0000000..6b964db
--- /dev/null
@@ -0,0 +1,62 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
+
+// FIXME: test with non-std qualifiers
+
+namespace move {
+  struct Const {
+    Const(const Const&&) = default; // expected-error {{the parameter for an explicitly-defaulted move constructor may not be const}}
+    Const& operator=(const Const&&) = default; // expected-error {{the parameter for an explicitly-defaulted move assignment operator may not be const}}
+  };
+
+  struct Volatile {
+    Volatile(volatile Volatile&&) = default; // expected-error {{the parameter for an explicitly-defaulted move constructor may not be volatile}}
+    Volatile& operator=(volatile Volatile&&) = default; // expected-error {{the parameter for an explicitly-defaulted move assignment operator may not be volatile}}
+  };
+
+  struct AssignmentRet1 {
+    AssignmentRet1&& operator=(AssignmentRet1&&) = default; // expected-error {{an explicitly-defaulted move assignment operator must return an unqualified lvalue reference to its class type}}
+  };
+
+  struct AssignmentRet2 {
+    const AssignmentRet2& operator=(AssignmentRet2&&) = default; // expected-error {{an explicitly-defaulted move assignment operator must return an unqualified lvalue reference to its class type}}
+  };
+
+  struct ConstAssignment {
+    ConstAssignment& operator=(ConstAssignment&&) const = default; // expected-error {{an explicitly-defaulted move assignment operator may not have 'const' or 'volatile' qualifiers}}
+  };
+}
+
+namespace copy {
+  struct Volatile {
+    Volatile(const volatile Volatile&) = default; // expected-error {{the parameter for an explicitly-defaulted copy constructor may not be volatile}}
+    Volatile& operator=(const volatile Volatile&) = default; // expected-error {{the parameter for an explicitly-defaulted copy assignment operator may not be volatile}}
+  };
+
+  struct Const {
+    Const(const Const&) = default;
+    Const& operator=(const Const&) = default;
+  };
+
+  struct NonConst {
+    NonConst(NonConst&) = default;
+    NonConst& operator=(NonConst&) = default;
+  };
+
+  struct BadConst {
+    NonConst nc; // makes implicit copy non-const
+    BadConst(const BadConst&) = default; // expected-error {{is const, but}}
+    BadConst& operator=(const BadConst&) = default; // expected-error {{is const, but}}
+  };
+
+  struct AssignmentRet1 {
+    AssignmentRet1&& operator=(const AssignmentRet1&) = default; // expected-error {{an explicitly-defaulted copy assignment operator must return an unqualified lvalue reference to its class type}}
+  };
+
+  struct AssignmentRet2 {
+    const AssignmentRet2& operator=(const AssignmentRet2&) = default; // expected-error {{an explicitly-defaulted copy assignment operator must return an unqualified lvalue reference to its class type}}
+  };
+
+  struct ConstAssignment {
+    ConstAssignment& operator=(const ConstAssignment&) const = default; // expected-error {{an explicitly-defaulted copy assignment operator may not have 'const' or 'volatile' qualifiers}}
+  };
+}
index ca5f868d9b056f1699b31b82511e1e8b8e78e4d7..762543038483edcdf19fa7bb1b13bd6350c9bbb0 100644 (file)
@@ -164,3 +164,12 @@ int no_alias_templates();
 
 // CHECK-0X: has_alias_templates
 // CHECK-NO-0X: no_alias_templates
+
+#if __has_feature(cxx_implicit_moves)
+int has_implicit_moves();
+#else
+int no_implicit_moves();
+#endif
+
+// CHECK-0X: has_implicit_moves
+// CHECK-NO-0X: no_implicit_moves