]> granicus.if.org Git - clang/commitdiff
Do defaulted constructors properly.
authorSean Hunt <scshunt@csclub.uwaterloo.ca>
Fri, 6 May 2011 01:42:00 +0000 (01:42 +0000)
committerSean Hunt <scshunt@csclub.uwaterloo.ca>
Fri, 6 May 2011 01:42:00 +0000 (01:42 +0000)
Explictly defaultedness is correctly reflected on the AST, but there are
no changes to how that affects the definition of functions or much else
really.

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

include/clang/AST/Decl.h
include/clang/AST/DeclCXX.h
include/clang/Basic/DiagnosticCommonKinds.td
include/clang/Basic/DiagnosticParseKinds.td
include/clang/Sema/Sema.h
lib/Parse/ParseDecl.cpp
lib/Parse/ParseDeclCXX.cpp
lib/Sema/SemaDecl.cpp
lib/Sema/SemaDeclCXX.cpp

index ef49205203919e8a01bf6331fb9efb46c3bef683..2cf26184913cf305ec097da3f874d049702b5e3d 100644 (file)
@@ -1365,6 +1365,8 @@ private:
   bool HasWrittenPrototype : 1;
   bool IsDeleted : 1;
   bool IsTrivial : 1; // sunk from CXXMethodDecl
+  bool IsDefaulted : 1; // sunk from CXXMethoDecl
+  bool IsExplicitlyDefaulted : 1; //sunk from CXXMethodDecl
   bool HasImplicitReturnZero : 1;
   bool IsLateTemplateParsed : 1;
 
@@ -1566,6 +1568,16 @@ public:
   bool isTrivial() const { return IsTrivial; }
   void setTrivial(bool IT) { IsTrivial = IT; }
 
+  /// Whether this function is defaulted per C++0x. Only valid for
+  /// special member functions. 
+  bool isDefaulted() const { return IsDefaulted; }
+  void setDefaulted(bool D = true) { IsDefaulted = D; }
+
+  /// Whether this function is explicitly defaulted per C++0x. Only valid
+  /// for special member functions.
+  bool isExplicitlyDefaulted() const { return IsExplicitlyDefaulted; }
+  void setExplicitlyDefaulted(bool ED = true) { IsExplicitlyDefaulted = ED; }
+
   /// Whether falling off this function implicitly returns null/zero.
   /// If a more specific implicit return value is required, front-ends
   /// should synthesize the appropriate return statements.
index 88f473eb48b2207b4034dd53b751ab310d34dc39..25a75b9ea0c8a3114a72d2134a4f9f0d1ae7ffd3 100644 (file)
@@ -1189,6 +1189,12 @@ public:
   CXXMethodDecl *getCanonicalDecl() {
     return cast<CXXMethodDecl>(FunctionDecl::getCanonicalDecl());
   }
+
+  /// isUserProvided - True if it is either an implicit constructor or
+  /// if it was defaulted or deleted on first declaration.
+  bool isUserProvided() const {
+    return getCanonicalDecl()->isDeleted() || getCanonicalDecl()->isDefaulted();
+  }
   
   ///
   void addOverriddenMethod(const CXXMethodDecl *MD);
index 0b0bca0395cb685fd8710cdb691605686fb953d8..166f81a5ffe111d9482165a16022d04078c78ccd 100644 (file)
@@ -52,6 +52,10 @@ def err_invalid_storage_class_in_func_decl : Error<
 def err_expected_namespace_name : Error<"expected namespace name">;
 def ext_variadic_templates : ExtWarn<
   "variadic templates are a C++0x extension">, InGroup<CXX0x>;
+def err_default_special_members : Error<
+  "Only special member functions may be defaulted">;
+def err_friends_define_only_namespace_scope : Error<
+  "Cannot define a function with non-namespace scope in a friend declaration">;
 
 // Sema && Lex
 def ext_longlong : Extension<
index e2d7f4ce9a73fca1cd69f4392a0706b4aa071946..3a8a708afa0bc3b5ac993f8488351abc9a088c0c 100644 (file)
@@ -434,6 +434,9 @@ def err_missing_whitespace_digraph : Error<
 
 def warn_deleted_function_accepted_as_extension: ExtWarn<
   "deleted function definition accepted as a C++0x extension">, InGroup<CXX0x>;
+def warn_defaulted_function_accepted_as_extension: ExtWarn<
+  "defaulted function definition accepted as a C++0x extension">,
+  InGroup<CXX0x>;
 
 // C++0x alias-declaration
 def ext_alias_declaration : ExtWarn<
index 69e14f3c0b90cc58107a029665501249f778d34d..1ce7f6af5b6e7204a2bc1cc534c9f8d5c6cf7f42 100644 (file)
@@ -935,7 +935,8 @@ public:
 
   Decl *HandleDeclarator(Scope *S, Declarator &D,
                          MultiTemplateParamsArg TemplateParameterLists,
-                         bool IsFunctionDefinition);
+                         bool IsFunctionDefinition,
+                         SourceLocation DefLoc = SourceLocation());
   void RegisterLocallyScopedExternCDecl(NamedDecl *ND,
                                         const LookupResult &Previous,
                                         Scope *S);
@@ -963,7 +964,8 @@ public:
                                      LookupResult &Previous,
                                      MultiTemplateParamsArg TemplateParamLists,
                                      bool IsFunctionDefinition,
-                                     bool &Redeclaration);
+                                     bool &Redeclaration,
+                                     SourceLocation DefLoc = SourceLocation());
   bool AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD);
   void DiagnoseHiddenVirtualMethods(CXXRecordDecl *DC, CXXMethodDecl *MD);
   void CheckFunctionDeclaration(Scope *S,
@@ -3063,7 +3065,8 @@ public:
                                  MultiTemplateParamsArg TemplateParameterLists,
                                  Expr *BitfieldWidth, const VirtSpecifiers &VS,
                                  Expr *Init, bool IsDefinition,
-                                 bool Deleted = false);
+                                 bool Deleted = false,
+                                 SourceLocation DefLoc = SourceLocation());
 
   MemInitResult ActOnMemInitializer(Decl *ConstructorD,
                                     Scope *S,
index a20e90bd0ea38f3d0d7e4e4f201e84afd1ff32de..a4c323979d44df92ea9f0ff56a01053a4b7a6275 100644 (file)
@@ -966,6 +966,10 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D,
         Diag(DelLoc, diag::warn_deleted_function_accepted_as_extension);
 
       Actions.SetDeclDeleted(ThisDecl, DelLoc);
+    } else if (Tok.is(tok::kw_default)) {
+      SourceLocation DefLoc = ConsumeToken();
+
+      Diag(DefLoc, diag::err_default_special_members);
     } else {
       if (getLang().CPlusPlus && D.getCXXScopeSpec().isSet()) {
         EnterScope(0);
index 7247c0724e4cf96073b70272d97f9faa2aef896f..d263f96e26898b4459c5f8087740699fc2088171 100644 (file)
@@ -1648,6 +1648,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
   ExprResult BitfieldSize;
   ExprResult Init;
   bool Deleted = false;
+  SourceLocation DefLoc;
 
   while (1) {
     // member-declarator:
@@ -1679,6 +1680,10 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
           Diag(Tok, diag::warn_deleted_function_accepted_as_extension);
         ConsumeToken();
         Deleted = true;
+      } else if (Tok.is(tok::kw_default)) {
+        if (!getLang().CPlusPlus0x)
+          Diag(Tok, diag::warn_defaulted_function_accepted_as_extension);
+        DefLoc = ConsumeToken();
       } else {
         Init = ParseInitializer();
         if (Init.isInvalid())
@@ -1706,6 +1711,9 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
 
     Decl *ThisDecl = 0;
     if (DS.isFriendSpecified()) {
+      if (DefLoc.isValid())
+        Diag(DefLoc, diag::err_default_special_members);
+
       // TODO: handle initializers, bitfields, 'delete'
       ThisDecl = Actions.ActOnFriendFunctionDecl(getCurScope(), DeclaratorInfo,
                                                  /*IsDefinition*/ false,
@@ -1717,7 +1725,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
                                                   BitfieldSize.release(),
                                                   VS, Init.release(),
                                                   /*IsDefinition*/Deleted,
-                                                  Deleted);
+                                                  Deleted, DefLoc);
     }
     if (ThisDecl)
       DeclsInGroup.push_back(ThisDecl);
@@ -1744,6 +1752,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
     BitfieldSize = 0;
     Init = 0;
     Deleted = false;
+    DefLoc = SourceLocation();
 
     // Attributes are only allowed on the second declarator.
     MaybeParseGNUAttributes(DeclaratorInfo);
index 2a63c9113587f3d302035d395097df757ef12645..0bf984d40a540778f1b372b8397dff9ca446a6b8 100644 (file)
@@ -2919,7 +2919,8 @@ bool Sema::DiagnoseClassNameShadow(DeclContext *DC,
   
 Decl *Sema::HandleDeclarator(Scope *S, Declarator &D,
                              MultiTemplateParamsArg TemplateParamLists,
-                             bool IsFunctionDefinition) {
+                             bool IsFunctionDefinition,
+                             SourceLocation DefLoc) {
   // TODO: consider using NameInfo for diagnostic.
   DeclarationNameInfo NameInfo = GetNameForDeclarator(D);
   DeclarationName Name = NameInfo.getName();
@@ -2962,7 +2963,6 @@ Decl *Sema::HandleDeclarator(Scope *S, Declarator &D,
         << D.getCXXScopeSpec().getRange();
       return 0;
     }
-
     bool IsDependentContext = DC->isDependentContext();
 
     if (!IsDependentContext && 
@@ -3121,6 +3121,9 @@ Decl *Sema::HandleDeclarator(Scope *S, Declarator &D,
 
   bool Redeclaration = false;
   if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef) {
+    if (DefLoc.isValid())
+      Diag(DefLoc, diag::err_default_special_members);
+
     if (TemplateParamLists.size()) {
       Diag(D.getIdentifierLoc(), diag::err_template_typedef);
       return 0;
@@ -3130,8 +3133,9 @@ Decl *Sema::HandleDeclarator(Scope *S, Declarator &D,
   } else if (R->isFunctionType()) {
     New = ActOnFunctionDeclarator(S, D, DC, R, TInfo, Previous,
                                   move(TemplateParamLists),
-                                  IsFunctionDefinition, Redeclaration);
+                                  IsFunctionDefinition, Redeclaration, DefLoc);
   } else {
+    assert(!DefLoc.isValid() && "We should have caught this in a caller");
     New = ActOnVariableDeclarator(S, D, DC, R, TInfo, Previous,
                                   move(TemplateParamLists),
                                   Redeclaration);
@@ -4003,7 +4007,8 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
                               QualType R, TypeSourceInfo *TInfo,
                               LookupResult &Previous,
                               MultiTemplateParamsArg TemplateParamLists,
-                              bool IsFunctionDefinition, bool &Redeclaration) {
+                              bool IsFunctionDefinition, bool &Redeclaration,
+                              SourceLocation DefLoc) {
   assert(R.getTypePtr()->isFunctionType());
 
   // TODO: consider using NameInfo for diagnostic.
@@ -4060,6 +4065,8 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
   bool isFunctionTemplateSpecialization = false;
 
   if (!getLangOptions().CPlusPlus) {
+    assert(!DefLoc.isValid() && "Defaulted functions are a C++ feature");
+
     // Determine whether the function was written with a
     // prototype. This true when:
     //   - there is a prototype in the declarator, or
@@ -4104,12 +4111,25 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
       R = CheckConstructorDeclarator(D, R, SC);
 
       // Create the new declaration
-      NewFD = CXXConstructorDecl::Create(Context,
+      CXXConstructorDecl *NewCD = CXXConstructorDecl::Create(
+                                         Context,
                                          cast<CXXRecordDecl>(DC),
                                          D.getSourceRange().getBegin(),
                                          NameInfo, R, TInfo,
                                          isExplicit, isInline,
                                          /*isImplicitlyDeclared=*/false);
+
+      NewFD = NewCD;
+
+      if (DefLoc.isValid()) {
+        if (NewCD->isDefaultConstructor() ||
+            NewCD->isCopyOrMoveConstructor()) {
+          NewFD->setDefaulted();
+          NewFD->setExplicitlyDefaulted();
+        } else {
+          Diag(DefLoc, diag::err_default_special_members);
+        }
+      }
     } else if (Name.getNameKind() == DeclarationName::CXXDestructorName) {
       // This is a C++ destructor declaration.
       if (DC->isRecord()) {
@@ -4122,6 +4142,11 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
                                           isInline,
                                           /*isImplicitlyDeclared=*/false);
         isVirtualOkay = true;
+
+        if (DefLoc.isValid()) {
+          NewFD->setDefaulted();
+          NewFD->setExplicitlyDefaulted();
+        }
       } else {
         Diag(D.getIdentifierLoc(), diag::err_destructor_not_member);
 
@@ -4140,6 +4165,9 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
         return 0;
       }
 
+      if (DefLoc.isValid())
+        Diag(DefLoc, diag::err_default_special_members);
+
       CheckConversionDeclarator(D, R, SC);
       NewFD = CXXConversionDecl::Create(Context, cast<CXXRecordDecl>(DC),
                                         D.getSourceRange().getBegin(),
@@ -4178,14 +4206,29 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
         isStatic = true;
 
       // This is a C++ method declaration.
-      NewFD = CXXMethodDecl::Create(Context, cast<CXXRecordDecl>(DC),
-                                    D.getSourceRange().getBegin(),
-                                    NameInfo, R, TInfo,
-                                    isStatic, SCAsWritten, isInline,
-                                    SourceLocation());
+      CXXMethodDecl *NewMD = CXXMethodDecl::Create(
+                                               Context, cast<CXXRecordDecl>(DC),
+                                               D.getSourceRange().getBegin(),
+                                               NameInfo, R, TInfo,
+                                               isStatic, SCAsWritten, isInline,
+                                               SourceLocation());
+      NewFD = NewMD;
 
       isVirtualOkay = !isStatic;
+
+      if (DefLoc.isValid()) {
+        if (NewMD->isCopyAssignmentOperator() /* ||
+            NewMD->isMoveAssignmentOperator() */) {
+          NewFD->setDefaulted();
+          NewFD->setExplicitlyDefaulted();
+        } else {
+          Diag(DefLoc, diag::err_default_special_members);
+        }
+      }
     } else {
+      if (DefLoc.isValid())
+        Diag(DefLoc, diag::err_default_special_members);
+
       // Determine whether the function was written with a
       // prototype. This true when:
       //   - we're in C++ (where every function has a prototype),
index 525cb81c8071ae6017575f14adf2e3792395019f..ca5fdd1fdd457dcfd14a6ae01c4321fe9c2683d8 100644 (file)
@@ -963,7 +963,7 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
                                MultiTemplateParamsArg TemplateParameterLists,
                                ExprTy *BW, const VirtSpecifiers &VS,
                                ExprTy *InitExpr, bool IsDefinition,
-                               bool Deleted) {
+                               bool Deleted, SourceLocation DefLoc) {
   const DeclSpec &DS = D.getDeclSpec();
   DeclarationNameInfo NameInfo = GetNameForDeclarator(D);
   DeclarationName Name = NameInfo.getName();
@@ -1028,6 +1028,8 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
   if (isInstField) {
     CXXScopeSpec &SS = D.getCXXScopeSpec();
     
+    if (DefLoc.isValid())
+      Diag(DefLoc, diag::err_default_special_members);
     
     if (SS.isSet() && !SS.isInvalid()) {
       // The user provided a superfluous scope specifier inside a class
@@ -1053,7 +1055,8 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
                          AS);
     assert(Member && "HandleField never returns null");
   } else {
-    Member = HandleDeclarator(S, D, move(TemplateParameterLists), IsDefinition);
+    Member = HandleDeclarator(S, D, move(TemplateParameterLists), IsDefinition,
+                              DefLoc);
     if (!Member) {
       return 0;
     }