]> granicus.if.org Git - clang/commitdiff
When we notice that a member function is defined with "= delete" or "=
authorDouglas Gregor <dgregor@apple.com>
Mon, 7 Nov 2011 20:56:01 +0000 (20:56 +0000)
committerDouglas Gregor <dgregor@apple.com>
Mon, 7 Nov 2011 20:56:01 +0000 (20:56 +0000)
default", make a note of which is used when creating the
initial declaration. Previously, we would wait until later to handle
default/delete as a definition, but this is too late: when adding the
declaration, we already treated the declaration as "user-provided"
when in fact it was merely "user-declared".

Fixes PR10861 and PR10442, along with a bunch of FIXMEs.

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

13 files changed:
include/clang/Parse/Parser.h
include/clang/Sema/DeclSpec.h
lib/AST/DeclCXX.cpp
lib/Parse/ParseCXXInlineMethods.cpp
lib/Parse/ParseDeclCXX.cpp
lib/Parse/Parser.cpp
lib/Sema/SemaDecl.cpp
lib/Sema/SemaTemplate.cpp
test/CXX/basic/basic.types/p10.cpp
test/CXX/class/p6-0x.cpp
test/CXX/dcl.decl/dcl.init/dcl.init.aggr/p1-0x.cpp
test/CXX/special/class.ctor/p5-0x.cpp
test/CXX/special/class.temporary/p1.cpp

index dba7ffb4788005febe360e513a391ba0d732138b..1b369d0ed38c22356b382bbc402561bc612e90ac 100644 (file)
@@ -1134,7 +1134,9 @@ private:
   Decl *ParseCXXInlineMethodDef(AccessSpecifier AS, AttributeList *AccessAttrs,
                                 ParsingDeclarator &D,
                                 const ParsedTemplateInfo &TemplateInfo,
-                                const VirtSpecifiers& VS, ExprResult& Init);
+                                const VirtSpecifiers& VS, 
+                                FunctionDefinitionKind DefinitionKind,
+                                ExprResult& Init);
   void ParseCXXNonStaticMemberInitializer(Decl *VarD);
   void ParseLexedAttributes(ParsingClass &Class);
   void ParseLexedAttribute(LateParsedAttribute &LA);
index 4d40a3d2912b16fee09477b1e146fa6952248693..7dc8f29455c3dcc3ed0ebf39b230fa3d3aed1512 100644 (file)
@@ -1379,6 +1379,15 @@ struct DeclaratorChunk {
 
 };
 
+/// \brief Described the kind of function definition (if any) provided for
+/// a function.
+enum FunctionDefinitionKind {
+  FDK_Declaration,
+  FDK_Definition,
+  FDK_Defaulted,
+  FDK_Deleted
+};
+  
 /// Declarator - Information about one declarator, including the parsed type
 /// information and the identifier.  When the declarator is fully formed, this
 /// is turned into the appropriate Decl object.
@@ -1434,8 +1443,11 @@ private:
   /// GroupingParens - Set by Parser::ParseParenDeclarator().
   bool GroupingParens : 1;
 
-  /// FunctionDefinition - Is this Declarator for a function or member defintion
-  bool FunctionDefinition : 1;
+  /// FunctionDefinition - Is this Declarator for a function or member 
+  /// definition and, if so, what kind?
+  ///
+  /// Actually a FunctionDefinitionKind.
+  unsigned FunctionDefinition : 2;
 
   // Redeclaration - Is this Declarator is a redeclaration.
   bool Redeclaration : 1;
@@ -1465,7 +1477,8 @@ public:
   Declarator(const DeclSpec &ds, TheContext C)
     : DS(ds), Range(ds.getSourceRange()), Context(C),
       InvalidType(DS.getTypeSpecType() == DeclSpec::TST_error),
-      GroupingParens(false), FunctionDefinition(false), Redeclaration(false),
+      GroupingParens(false), FunctionDefinition(FDK_Declaration), 
+      Redeclaration(false),
       Attrs(ds.getAttributePool().getFactory()), AsmLabel(0),
       InlineParamsUsed(false), Extension(false) {
   }
@@ -1827,8 +1840,17 @@ public:
   SourceLocation getEllipsisLoc() const { return EllipsisLoc; }
   void setEllipsisLoc(SourceLocation EL) { EllipsisLoc = EL; }
 
-  void setFunctionDefinition(bool Val) { FunctionDefinition = Val; }
-  bool isFunctionDefinition() const { return FunctionDefinition; }
+  void setFunctionDefinitionKind(FunctionDefinitionKind Val) { 
+    FunctionDefinition = Val; 
+  }
+  
+  bool isFunctionDefinition() const {
+    return getFunctionDefinitionKind() != FDK_Declaration;
+  }
+  
+  FunctionDefinitionKind getFunctionDefinitionKind() const { 
+    return (FunctionDefinitionKind)FunctionDefinition; 
+  }
 
   void setRedeclaration(bool Val) { Redeclaration = Val; }
   bool isRedeclaration() const { return Redeclaration; }
index b8c20e4b06db67ab0a54241a3b7ca74c42f27278..b86cf281188b7fab3191968ded52429e3c7d34fc 100644 (file)
@@ -451,8 +451,7 @@ void CXXRecordDecl::addedMember(Decl *D) {
       //    -- class X has no virtual functions [...]
       data().HasTrivialCopyAssignment = false;
       data().HasTrivialMoveAssignment = false;
-      // FIXME: Destructor?
-
+            
       // C++0x [class]p7:
       //   A standard-layout class is a class that: [...]
       //    -- has no virtual functions
@@ -574,9 +573,10 @@ NotASpecialMember:;
     // This bit is the C++03 POD bit, not the 0x one.
     data().PlainOldData = false;
     
-    // C++0x [class.dtor]p5: 
-    //   A destructor is trivial if it is not user-provided and [...]
-    if (DD->isUserProvided())
+    // C++11 [class.dtor]p5: 
+    //   A destructor is trivial if it is not user-provided and if
+    //    -- the destructor is not virtual.
+    if (DD->isUserProvided() || DD->isVirtual())
       data().HasTrivialDestructor = false;
     
     return;
index 04c05d0cc38446968a61119123d93c1604121000..65f7f56fe93d0566cc7f2d46177fe8ac1ccaaee5 100644 (file)
@@ -24,8 +24,10 @@ using namespace clang;
 Decl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS,
                                       AttributeList *AccessAttrs,
                                       ParsingDeclarator &D,
-                                const ParsedTemplateInfo &TemplateInfo,
-                                const VirtSpecifiers& VS, ExprResult& Init) {
+                                      const ParsedTemplateInfo &TemplateInfo,
+                                      const VirtSpecifiers& VS, 
+                                      FunctionDefinitionKind DefinitionKind,
+                                      ExprResult& Init) {
   assert(D.isFunctionDeclarator() && "This isn't a function declarator!");
   assert((Tok.is(tok::l_brace) || Tok.is(tok::colon) || Tok.is(tok::kw_try) ||
           Tok.is(tok::equal)) &&
@@ -36,7 +38,7 @@ Decl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS,
           TemplateInfo.TemplateParams ? TemplateInfo.TemplateParams->size() : 0);
 
   Decl *FnD;
-  D.setFunctionDefinition(true);
+  D.setFunctionDefinitionKind(DefinitionKind);
   if (D.getDeclSpec().isFriendSpecified())
     FnD = Actions.ActOnFriendFunctionDecl(getCurScope(), D,
                                           move(TemplateParams));
index 721d185f5392d8713c9e789f58dae0e3f09291c4..04c94a053d6be6c094e05e3241cce3fb78c33888 100644 (file)
@@ -1779,25 +1779,27 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
         HasInitializer = true;
     }
 
-    bool IsDefinition = false;
+    FunctionDefinitionKind DefinitionKind = FDK_Declaration;
     // function-definition:
     //
     // In C++11, a non-function declarator followed by an open brace is a
     // braced-init-list for an in-class member initialization, not an
     // erroneous function definition.
     if (Tok.is(tok::l_brace) && !getLang().CPlusPlus0x) {
-      IsDefinition = true;
+      DefinitionKind = FDK_Definition;
     } else if (DeclaratorInfo.isFunctionDeclarator()) {
       if (Tok.is(tok::l_brace) || Tok.is(tok::colon) || Tok.is(tok::kw_try)) {
-        IsDefinition = true;
+        DefinitionKind = FDK_Definition;
       } else if (Tok.is(tok::equal)) {
         const Token &KW = NextToken();
-        if (KW.is(tok::kw_default) || KW.is(tok::kw_delete))
-          IsDefinition = true;
+        if (KW.is(tok::kw_default))
+          DefinitionKind = FDK_Defaulted;
+        else if (KW.is(tok::kw_delete))
+          DefinitionKind = FDK_Deleted;
       }
     }
 
-    if (IsDefinition) {
+    if (DefinitionKind) {
       if (!DeclaratorInfo.isFunctionDeclarator()) {
         Diag(Tok, diag::err_func_def_no_params);
         ConsumeBrace();
@@ -1825,7 +1827,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
 
       Decl *FunDecl =
         ParseCXXInlineMethodDef(AS, AccessAttrs, DeclaratorInfo, TemplateInfo,
-                                VS, Init);
+                                VS, DefinitionKind, Init);
 
       for (unsigned i = 0, ni = LateParsedAttrs.size(); i < ni; ++i) {
         LateParsedAttrs[i]->setDecl(FunDecl);
index 6e84e429684694f1aba57dc203f00e0dc61040c2..b4d41ef48233ee44d0d8d46aced897e6195e231a 100644 (file)
@@ -876,7 +876,7 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
     ParseScope BodyScope(this, Scope::FnScope|Scope::DeclScope);
     Scope *ParentScope = getCurScope()->getParent();
 
-    D.setFunctionDefinition(true);
+    D.setFunctionDefinitionKind(FDK_Definition);
     Decl *DP = Actions.HandleDeclarator(ParentScope, D,
                                         move(TemplateParameterLists));
     D.complete(DP);
index 05f48707aa2c98ef4cf2941e4d4cee8fc315f9c7..d71cd5f7d5441e5103fb87afdf8190b70f66334a 100644 (file)
@@ -3145,7 +3145,7 @@ static bool RebuildDeclaratorInCurrentInstantiation(Sema &S, Declarator &D,
 }
 
 Decl *Sema::ActOnDeclarator(Scope *S, Declarator &D) {
-  D.setFunctionDefinition(false);
+  D.setFunctionDefinitionKind(FDK_Declaration);
   return HandleDeclarator(S, D, MultiTemplateParamsArg(*this));
 }
 
@@ -4803,7 +4803,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
     // scope specifier, or is the object of a friend declaration, the
     // lexical context will be different from the semantic context.
     NewFD->setLexicalDeclContext(CurContext);
-    
+        
     // Match up the template parameter lists with the scope specifier, then
     // determine whether we have a template or a template specialization.
     bool Invalid = false;
@@ -4995,10 +4995,26 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
       NewFD->setAccess(AS_public);
     }
 
+    // If a function is defined as defaulted or deleted, mark it as such now.
+    switch (D.getFunctionDefinitionKind()) {
+      case FDK_Declaration:
+      case FDK_Definition:
+        break;
+        
+      case FDK_Defaulted:
+        NewFD->setDefaulted();
+        break;
+        
+      case FDK_Deleted:
+        NewFD->setDeletedAsWritten();
+        break;
+    }
+
     if (isa<CXXMethodDecl>(NewFD) && DC == CurContext &&
         D.isFunctionDefinition()) {
-      // A method is implicitly inline if it's defined in its class
-      // definition.
+      // C++ [class.mfct]p2:
+      //   A member function may be defined (8.4) in its class definition, in 
+      //   which case it is an inline member function (7.1.2)
       NewFD->setImplicitlyInline();
     }
 
@@ -6885,7 +6901,7 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope,
   assert(D.isFunctionDeclarator() && "Not a function declarator!");
   Scope *ParentScope = FnBodyScope->getParent();
 
-  D.setFunctionDefinition(true);
+  D.setFunctionDefinitionKind(FDK_Definition);
   Decl *DP = HandleDeclarator(ParentScope, D,
                               MultiTemplateParamsArg(*this));
   return ActOnStartOfFunctionDef(FnBodyScope, DP);
index 2d7e85094aa27de0037760f2f9785422c8f6a77a..8ec4c195f919428056753d4c235281b5ab1ea631 100644 (file)
@@ -5219,7 +5219,7 @@ Decl *Sema::ActOnStartOfFunctionTemplateDef(Scope *FnBodyScope,
 
   Scope *ParentScope = FnBodyScope->getParent();
 
-  D.setFunctionDefinition(true);
+  D.setFunctionDefinitionKind(FDK_Definition);
   Decl *DP = HandleDeclarator(ParentScope, D,
                               move(TemplateParameterLists));
   if (FunctionTemplateDecl *FunctionTemplate
index 3b438d15f28bfd46d22821c270e9da853624af71..1f66e5522df8da7f9d0c64cb14e5ec657cd10e21 100644 (file)
@@ -18,6 +18,7 @@ struct UserProvDtor {
   constexpr UserProvDtor(); // expected-error {{non-literal type 'UserProvDtor' cannot have constexpr members}}
   ~UserProvDtor(); // expected-note {{has a user-provided destructor}}
 };
+
 struct NonTrivDtor {
   constexpr NonTrivDtor(); // expected-error {{non-literal type 'NonTrivDtor' cannot have constexpr members}}
   virtual ~NonTrivDtor() = default; // expected-note {{has a non-trivial destructor}}
index 3384af09c7884985b1bd2eaef04e97def0bfb6bc..f2cf48282112f751c4c5115f6ce0fa124a747030 100644 (file)
@@ -13,3 +13,18 @@ static_assert(!__is_trivial(NonTrivial2), "NonTrivial2 is trivial");
 static_assert(!__is_trivial(NonTrivial3), "NonTrivial3 is trivial");
 static_assert(!__is_trivial(NonTrivial4), "NonTrivial4 is trivial");
 static_assert(!__is_trivial(NonTrivial5), "NonTrivial5 is trivial");
+
+struct Trivial2 {
+  Trivial2() = default;
+  Trivial2(const Trivial2 &) = default;
+  Trivial2(Trivial2 &&) = default;
+  Trivial2 &operator=(const Trivial2 &) = default;
+  Trivial2 &operator=(Trivial2 &) = default;
+  ~Trivial2() = default;
+};
+
+class NonTrivial6 { ~NonTrivial6(); };
+
+NonTrivial6::~NonTrivial6() = default;
+
+static_assert(!__is_trivial(NonTrivial6), "NonTrivial6 is trivial");
index 13b02c014e44e4280014f2440c2eb1e69a6d7683..ac8794f455e31efa62d7d35a67bca8a048fbeb22 100644 (file)
@@ -64,3 +64,15 @@ struct NonAggr6 {
   int n;
 };
 NonAggr6 na6 = { 42 }; // expected-error {{non-aggregate type 'NonAggr6'}}
+
+struct DefaultedAggr {
+  int n;
+
+  DefaultedAggr() = default;
+  DefaultedAggr(const DefaultedAggr &) = default;
+  DefaultedAggr(DefaultedAggr &&) = default;
+  DefaultedAggr &operator=(const DefaultedAggr &) = default;
+  DefaultedAggr &operator=(DefaultedAggr &) = default;
+  ~DefaultedAggr() = default;
+};
+DefaultedAggr da = { 42 } ;
index de2dea5be16b1e010c0133c13bbd28460d857580..c8d206ae37772c7f768ebf99e0b207a7ca445422 100644 (file)
@@ -48,10 +48,8 @@ class Deleted3a { const int a; }; // expected-note {{here}} \
 Deleted3a d3a; // expected-error {{deleted constructor}}
 class Deleted3b { const DefaultedDefCtor1 a[42]; }; // expected-note {{here}}
 Deleted3b d3b; // expected-error {{deleted constructor}}
-// FIXME: clang implements the pre-FDIS rule, under which DefaultedDefCtor2's
-// default constructor is user-provided.
-class Deleted3c { const DefaultedDefCtor2 a; }; // desired-note {{here}}
-Deleted3c d3c; // desired-error {{deleted constructor}}
+class Deleted3c { const DefaultedDefCtor2 a; }; // expected-note {{deleted}}
+Deleted3c d3c; // expected-error {{deleted constructor}}
 class NotDeleted3a { const int a = 0; };
 NotDeleted3a nd3a;
 class NotDeleted3b { const DefaultedDefCtor1 a[42] = {}; };
@@ -159,11 +157,7 @@ static_assert(!__has_trivial_constructor(NonTrivialDefCtor6), "NonTrivialDefCtor
 
 // Otherwise, the default constructor is non-trivial.
 class Trivial2 { Trivial2() = delete; };
-//static_assert(__has_trivial_constructor(Trivial2), "NonTrivialDefCtor2 is trivial");
-// FIXME: clang implements the pre-FDIS rule, under which this class is non-trivial.
-static_assert(!__has_trivial_constructor(Trivial2), "NonTrivialDefCtor2 is trivial");
+static_assert(__has_trivial_constructor(Trivial2), "NonTrivialDefCtor2 is trivial");
 
 class Trivial3 { Trivial3() = default; };
-//static_assert(__has_trivial_constructor(Trivial3), "NonTrivialDefCtor3 is trivial");
-// FIXME: clang implements the pre-FDIS rule, under which this class is non-trivial.
-static_assert(!__has_trivial_constructor(Trivial3), "NonTrivialDefCtor3 is trivial");
+static_assert(__has_trivial_constructor(Trivial3), "NonTrivialDefCtor3 is trivial");
index 384b1f89fda8d12719f3ef83bf38f2d0440fa799..4f6ac0a0029ed514addd35da8789ae1b3ce22c6b 100644 (file)
@@ -31,8 +31,7 @@ namespace test1 {
 
   void test() {
     A a;
-    // FIXME: this error about variadics is bogus
-    foo(a); // expected-error {{calling a private constructor of class 'test1::A'}} expected-error {{cannot pass object of non-trivial type 'test1::A' through variadic function}}
+    foo(a); // expected-error {{calling a private constructor of class 'test1::A'}}
   }
 }