diff options
-rw-r--r-- | include/clang/AST/DeclCXX.h | 83 | ||||
-rw-r--r-- | include/clang/Basic/DiagnosticSemaKinds.td | 3 | ||||
-rw-r--r-- | lib/AST/DeclCXX.cpp | 118 | ||||
-rw-r--r-- | lib/AST/ExprConstant.cpp | 45 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 156 | ||||
-rw-r--r-- | test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp | 9 | ||||
-rw-r--r-- | test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp | 2 | ||||
-rw-r--r-- | test/CXX/dcl.decl/dcl.fct.def/dcl.fct.def.default/p2.cpp | 55 | ||||
-rw-r--r-- | test/CXX/special/class.copy/p13-0x.cpp | 55 | ||||
-rw-r--r-- | test/CXX/special/class.ctor/p6-0x.cpp | 49 | ||||
-rw-r--r-- | test/SemaCXX/constant-expression-cxx11.cpp | 9 | ||||
-rw-r--r-- | test/SemaCXX/enum-bitfield.cpp | 4 |
12 files changed, 511 insertions, 77 deletions
diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h index 7c040e7d2e..edbeabd3d9 100644 --- a/include/clang/AST/DeclCXX.h +++ b/include/clang/AST/DeclCXX.h @@ -366,10 +366,34 @@ class CXXRecordDecl : public RecordDecl { bool HasTrivialDefaultConstructor : 1; /// HasConstexprNonCopyMoveConstructor - True when this class has at least - /// one constexpr constructor which is neither the copy nor move - /// constructor. + /// one user-declared constexpr constructor which is neither the copy nor + /// move constructor. bool HasConstexprNonCopyMoveConstructor : 1; + /// DefaultedDefaultConstructorIsConstexpr - True if a defaulted default + /// constructor for this class would be constexpr. + bool DefaultedDefaultConstructorIsConstexpr : 1; + + /// DefaultedCopyConstructorIsConstexpr - True if a defaulted copy + /// constructor for this class would be constexpr. + bool DefaultedCopyConstructorIsConstexpr : 1; + + /// DefaultedMoveConstructorIsConstexpr - True if a defaulted move + /// constructor for this class would be constexpr. + bool DefaultedMoveConstructorIsConstexpr : 1; + + /// HasConstexprDefaultConstructor - True if this class has a constexpr + /// default constructor (either user-declared or implicitly declared). + bool HasConstexprDefaultConstructor : 1; + + /// HasConstexprCopyConstructor - True if this class has a constexpr copy + /// constructor (either user-declared or implicitly declared). + bool HasConstexprCopyConstructor : 1; + + /// HasConstexprMoveConstructor - True if this class has a constexpr move + /// constructor (either user-declared or implicitly declared). + bool HasConstexprMoveConstructor : 1; + /// HasTrivialCopyConstructor - True when this class has a trivial copy /// constructor. /// @@ -946,19 +970,62 @@ public: /// mutable field. bool hasMutableFields() const { return data().HasMutableFields; } - // hasTrivialDefaultConstructor - Whether this class has a trivial default - // constructor - // (C++0x [class.ctor]p5) + /// hasTrivialDefaultConstructor - Whether this class has a trivial default + /// constructor (C++11 [class.ctor]p5). bool hasTrivialDefaultConstructor() const { return data().HasTrivialDefaultConstructor && (!data().UserDeclaredConstructor || data().DeclaredDefaultConstructor); } - // hasConstexprNonCopyMoveConstructor - Whether this class has at least one - // constexpr constructor other than the copy or move constructors. + /// hasConstexprNonCopyMoveConstructor - Whether this class has at least one + /// constexpr constructor other than the copy or move constructors. bool hasConstexprNonCopyMoveConstructor() const { - return data().HasConstexprNonCopyMoveConstructor; + return data().HasConstexprNonCopyMoveConstructor || + (!hasUserDeclaredConstructor() && + defaultedDefaultConstructorIsConstexpr()); + } + + /// defaultedDefaultConstructorIsConstexpr - Whether a defaulted default + /// constructor for this class would be constexpr. + bool defaultedDefaultConstructorIsConstexpr() const { + return data().DefaultedDefaultConstructorIsConstexpr; + } + + /// defaultedCopyConstructorIsConstexpr - Whether a defaulted copy + /// constructor for this class would be constexpr. + bool defaultedCopyConstructorIsConstexpr() const { + return data().DefaultedCopyConstructorIsConstexpr; + } + + /// defaultedMoveConstructorIsConstexpr - Whether a defaulted move + /// constructor for this class would be constexpr. + bool defaultedMoveConstructorIsConstexpr() const { + return data().DefaultedMoveConstructorIsConstexpr; + } + + /// hasConstexprDefaultConstructor - Whether this class has a constexpr + /// default constructor. + bool hasConstexprDefaultConstructor() const { + return data().HasConstexprDefaultConstructor || + (!data().UserDeclaredConstructor && + data().DefaultedDefaultConstructorIsConstexpr && isLiteral()); + } + + /// hasConstexprCopyConstructor - Whether this class has a constexpr copy + /// constructor. + bool hasConstexprCopyConstructor() const { + return data().HasConstexprCopyConstructor || + (!data().DeclaredCopyConstructor && + data().DefaultedCopyConstructorIsConstexpr && isLiteral()); + } + + /// hasConstexprMoveConstructor - Whether this class has a constexpr move + /// constructor. + bool hasConstexprMoveConstructor() const { + return data().HasConstexprMoveConstructor || + (needsImplicitMoveConstructor() && + data().DefaultedMoveConstructorIsConstexpr && isLiteral()); } // hasTrivialCopyConstructor - Whether this class has a trivial copy diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 83ba22feff..df10a2df5d 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -4685,6 +4685,9 @@ def err_incorrect_defaulted_exception_spec : Error< "copy constructor|move constructor|copy assignment operator|move assignment " "operator|destructor}0 does not match the " "calculated one">; +def err_incorrect_defaulted_constexpr : Error< + "defaulted definition of %select{default constructor|copy constructor|" + "move constructor}0 is not constexpr">; def err_out_of_line_default_deletes : Error< "defaulting this %select{default constructor|copy constructor|move " "constructor|copy assignment operator|move assignment operator|destructor}0 " diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index ddb61e5950..c1aa35f305 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -38,7 +38,12 @@ CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D) Abstract(false), IsStandardLayout(true), HasNoNonEmptyBases(true), HasPrivateFields(false), HasProtectedFields(false), HasPublicFields(false), HasMutableFields(false), HasTrivialDefaultConstructor(true), - HasConstexprNonCopyMoveConstructor(false), HasTrivialCopyConstructor(true), + HasConstexprNonCopyMoveConstructor(false), + DefaultedDefaultConstructorIsConstexpr(true), + DefaultedCopyConstructorIsConstexpr(true), + DefaultedMoveConstructorIsConstexpr(true), + HasConstexprDefaultConstructor(false), HasConstexprCopyConstructor(false), + HasConstexprMoveConstructor(false), HasTrivialCopyConstructor(true), HasTrivialMoveConstructor(true), HasTrivialCopyAssignment(true), HasTrivialMoveAssignment(true), HasTrivialDestructor(true), HasNonLiteralTypeFieldsOrBases(false), ComputedVisibleConversions(false), @@ -190,6 +195,13 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases, // A standard-layout class is a class that: [...] // -- has [...] no virtual base classes data().IsStandardLayout = false; + + // C++11 [dcl.constexpr]p4: + // In the definition of a constexpr constructor [...] + // -- the class shall not have any virtual base classes + data().DefaultedDefaultConstructorIsConstexpr = false; + data().DefaultedCopyConstructorIsConstexpr = false; + data().DefaultedMoveConstructorIsConstexpr = false; } else { // C++ [class.ctor]p5: // A default constructor is trivial [...] if: @@ -221,6 +233,32 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases, data().HasTrivialCopyAssignment = false; if (!BaseClassDecl->hasTrivialMoveAssignment()) data().HasTrivialMoveAssignment = false; + + // C++11 [class.ctor]p6: + // If that user-written default cosntructor would satisfy the + // requirements of a constexpr constructor, the implicitly-defined + // default constructor is constexpr. + if (!BaseClassDecl->hasConstexprDefaultConstructor()) + data().DefaultedDefaultConstructorIsConstexpr = false; + + // C++11 [class.copy]p13: + // If the implicitly-defined constructor would satisfy the requirements + // of a constexpr constructor, the implicitly-defined constructor is + // constexpr. + // C++11 [dcl.constexpr]p4: + // -- every constructor involved in initializing [...] base class + // sub-objects shall be a constexpr constructor + if (!BaseClassDecl->hasConstexprCopyConstructor()) + data().DefaultedCopyConstructorIsConstexpr = false; + if (BaseClassDecl->hasDeclaredMoveConstructor() || + BaseClassDecl->needsImplicitMoveConstructor()) + // FIXME: If the implicit move constructor generated for the base class + // would be ill-formed, the implicit move constructor generated for the + // derived class calls the base class' copy constructor. + data().DefaultedMoveConstructorIsConstexpr &= + !BaseClassDecl->hasConstexprMoveConstructor(); + else if (!BaseClassDecl->hasConstexprCopyConstructor()) + data().DefaultedMoveConstructorIsConstexpr = false; } // C++ [class.ctor]p3: @@ -471,13 +509,21 @@ void CXXRecordDecl::addedMember(Decl *D) { // If this is a special member function, note that it was added and then // return early. if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) { - if (Constructor->isDefaultConstructor()) + if (Constructor->isDefaultConstructor()) { data().DeclaredDefaultConstructor = true; - else if (Constructor->isCopyConstructor()) + if (Constructor->isConstexpr()) { + data().HasConstexprDefaultConstructor = true; + data().HasConstexprNonCopyMoveConstructor = true; + } + } else if (Constructor->isCopyConstructor()) { data().DeclaredCopyConstructor = true; - else if (Constructor->isMoveConstructor()) + if (Constructor->isConstexpr()) + data().HasConstexprCopyConstructor = true; + } else if (Constructor->isMoveConstructor()) { data().DeclaredMoveConstructor = true; - else + if (Constructor->isConstexpr()) + data().HasConstexprMoveConstructor = true; + } else goto NotASpecialMember; return; } else if (isa<CXXDestructorDecl>(D)) { @@ -507,14 +553,18 @@ NotASpecialMember:; // to all functions. bool UserProvided = Constructor->isUserProvided(); - // C++0x [class.ctor]p5: - // A default constructor is trivial if it is not user-provided [...] if (Constructor->isDefaultConstructor()) { data().DeclaredDefaultConstructor = true; if (UserProvided) { + // C++0x [class.ctor]p5: + // A default constructor is trivial if it is not user-provided [...] data().HasTrivialDefaultConstructor = false; data().UserProvidedDefaultConstructor = true; } + if (Constructor->isConstexpr()) { + data().HasConstexprDefaultConstructor = true; + data().HasConstexprNonCopyMoveConstructor = true; + } } // Note when we have a user-declared copy or move constructor, which will @@ -529,6 +579,9 @@ NotASpecialMember:; // user-provided [...] if (UserProvided) data().HasTrivialCopyConstructor = false; + + if (Constructor->isConstexpr()) + data().HasConstexprCopyConstructor = true; } else if (Constructor->isMoveConstructor()) { data().UserDeclaredMoveConstructor = true; data().DeclaredMoveConstructor = true; @@ -538,6 +591,9 @@ NotASpecialMember:; // user-provided [...] if (UserProvided) data().HasTrivialMoveConstructor = false; + + if (Constructor->isConstexpr()) + data().HasConstexprMoveConstructor = true; } } if (Constructor->isConstexpr() && !Constructor->isCopyOrMoveConstructor()) { @@ -578,8 +634,18 @@ NotASpecialMember:; // 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()) + if (DD->isUserProvided() || DD->isVirtual()) { data().HasTrivialDestructor = false; + // C++11 [dcl.constexpr]p1: + // The constexpr specifier shall be applied only to [...] the + // declaration of a static data member of a literal type. + // C++11 [basic.types]p10: + // A type is a literal type if it is [...] a class type that [...] has + // a trivial destructor. + data().DefaultedDefaultConstructorIsConstexpr = false; + data().DefaultedCopyConstructorIsConstexpr = false; + data().DefaultedMoveConstructorIsConstexpr = false; + } return; } @@ -746,7 +812,7 @@ NotASpecialMember:; CXXRecordDecl* FieldRec = cast<CXXRecordDecl>(RecordTy->getDecl()); if (FieldRec->getDefinition()) { // C++0x [class.ctor]p5: - // A defulat constructor is trivial [...] if: + // A default constructor is trivial [...] if: // -- for all the non-static data members of its class that are of // class type (or array thereof), each such class has a trivial // default constructor. @@ -818,7 +884,41 @@ NotASpecialMember:; // Keep track of the presence of mutable fields. if (FieldRec->hasMutableFields()) data().HasMutableFields = true; + + // C++11 [class.copy]p13: + // If the implicitly-defined constructor would satisfy the + // requirements of a constexpr constructor, the implicitly-defined + // constructor is constexpr. + // C++11 [dcl.constexpr]p4: + // -- every constructor involved in initializing non-static data + // members [...] shall be a constexpr constructor + if (!Field->hasInClassInitializer() && + !FieldRec->hasConstexprDefaultConstructor()) + // The standard requires any in-class initializer to be a constant + // expression. We consider this to be a defect. + data().DefaultedDefaultConstructorIsConstexpr = false; + + if (!FieldRec->hasConstexprCopyConstructor()) + data().DefaultedCopyConstructorIsConstexpr = false; + + if (FieldRec->hasDeclaredMoveConstructor() || + FieldRec->needsImplicitMoveConstructor()) + // FIXME: If the implicit move constructor generated for the member's + // class would be ill-formed, the implicit move constructor generated + // for this class calls the member's copy constructor. + data().DefaultedMoveConstructorIsConstexpr &= + FieldRec->hasConstexprMoveConstructor(); + else if (!FieldRec->hasConstexprCopyConstructor()) + data().DefaultedMoveConstructorIsConstexpr = false; } + } else { + // Base element type of field is a non-class type. + if (!T->isLiteralType()) { + data().DefaultedDefaultConstructorIsConstexpr = false; + data().DefaultedCopyConstructorIsConstexpr = false; + data().DefaultedMoveConstructorIsConstexpr = false; + } else if (!Field->hasInClassInitializer()) + data().DefaultedDefaultConstructorIsConstexpr = false; } // C++0x [class]p7: diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index 8e6682bcde..c58a568876 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -1591,6 +1591,29 @@ static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info, } } +/// CheckTrivialDefaultConstructor - Check whether a constructor is a trivial +/// default constructor. If so, we'll fold it whether or not it's marked as +/// constexpr. If it is marked as constexpr, we will never implicitly define it, +/// so we need special handling. +static bool CheckTrivialDefaultConstructor(EvalInfo &Info, SourceLocation Loc, + const CXXConstructorDecl *CD) { + if (!CD->isTrivial() || !CD->isDefaultConstructor()) + return false; + + if (!CD->isConstexpr()) { + if (Info.getLangOpts().CPlusPlus0x) { + // FIXME: If DiagDecl is an implicitly-declared special member function, + // we should be much more explicit about why it's not constexpr. + Info.CCEDiag(Loc, diag::note_constexpr_invalid_function, 1) + << /*IsConstexpr*/0 << /*IsConstructor*/1 << CD; + Info.Note(CD->getLocation(), diag::note_declared_at); + } else { + Info.CCEDiag(Loc, diag::note_invalid_subexpr_in_const_expr); + } + } + return true; +} + /// CheckConstexprFunction - Check that a function can be called in a constant /// expression. static bool CheckConstexprFunction(EvalInfo &Info, SourceLocation CallLoc, @@ -2790,6 +2813,16 @@ bool RecordExprEvaluator::VisitInitListExpr(const InitListExpr *E) { bool RecordExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E) { const CXXConstructorDecl *FD = E->getConstructor(); + if (CheckTrivialDefaultConstructor(Info, E->getExprLoc(), FD)) { + const CXXRecordDecl *RD = FD->getParent(); + if (RD->isUnion()) + Result = APValue((FieldDecl*)0); + else + Result = APValue(APValue::UninitStruct(), RD->getNumBases(), + std::distance(RD->field_begin(), RD->field_end())); + return true; + } + const FunctionDecl *Definition = 0; FD->getBody(Definition); @@ -3144,6 +3177,18 @@ bool ArrayExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E) { return true; const CXXConstructorDecl *FD = E->getConstructor(); + + if (CheckTrivialDefaultConstructor(Info, E->getExprLoc(), FD)) { + const CXXRecordDecl *RD = FD->getParent(); + if (RD->isUnion()) + Result.getArrayFiller() = APValue((FieldDecl*)0); + else + Result.getArrayFiller() = + APValue(APValue::UninitStruct(), RD->getNumBases(), + std::distance(RD->field_begin(), RD->field_end())); + return true; + } + const FunctionDecl *Definition = 0; FD->getBody(Definition); diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index f8c02ba741..7f743f50f3 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -3756,6 +3756,18 @@ void Sema::CheckExplicitlyDefaultedDefaultConstructor(CXXConstructorDecl *CD) { *ExceptionType = Context.getFunctionType( Context.VoidTy, 0, 0, EPI)->getAs<FunctionProtoType>(); + // C++11 [dcl.fct.def.default]p2: + // An explicitly-defaulted function may be declared constexpr only if it + // would have been implicitly declared as constexpr, + if (CD->isConstexpr()) { + if (!CD->getParent()->defaultedDefaultConstructorIsConstexpr()) { + Diag(CD->getLocStart(), diag::err_incorrect_defaulted_constexpr) + << CXXDefaultConstructor; + HadError = true; + } + } + // and may have an explicit exception-specification only if it is compatible + // with the exception-specification on the implicit declaration. if (CtorType->hasExceptionSpec()) { if (CheckEquivalentExceptionSpec( PDiag(diag::err_incorrect_defaulted_exception_spec) @@ -3765,11 +3777,20 @@ void Sema::CheckExplicitlyDefaultedDefaultConstructor(CXXConstructorDecl *CD) { CtorType, CD->getLocation())) { HadError = true; } - } else if (First) { - // We set the declaration to have the computed exception spec here. - // We know there are no parameters. + } + + // If a function is explicitly defaulted on its first declaration, + if (First) { + // -- it is implicitly considered to be constexpr if the implicit + // definition would be, + CD->setConstexpr(CD->getParent()->defaultedDefaultConstructorIsConstexpr()); + + // -- it is implicitly considered to have the same + // exception-specification as if it had been implicitly declared + // + // FIXME: a compatible, but different, explicit exception specification + // will be silently overridden. We should issue a warning if this happens. EPI.ExtInfo = CtorType->getExtInfo(); - CD->setType(Context.getFunctionType(Context.VoidTy, 0, 0, EPI)); } if (HadError) { @@ -3823,6 +3844,18 @@ void Sema::CheckExplicitlyDefaultedCopyConstructor(CXXConstructorDecl *CD) { HadError = true; } + // C++11 [dcl.fct.def.default]p2: + // An explicitly-defaulted function may be declared constexpr only if it + // would have been implicitly declared as constexpr, + if (CD->isConstexpr()) { + if (!CD->getParent()->defaultedCopyConstructorIsConstexpr()) { + Diag(CD->getLocStart(), diag::err_incorrect_defaulted_constexpr) + << CXXCopyConstructor; + HadError = true; + } + } + // and may have an explicit exception-specification only if it is compatible + // with the exception-specification on the implicit declaration. if (CtorType->hasExceptionSpec()) { if (CheckEquivalentExceptionSpec( PDiag(diag::err_incorrect_defaulted_exception_spec) @@ -3832,10 +3865,23 @@ void Sema::CheckExplicitlyDefaultedCopyConstructor(CXXConstructorDecl *CD) { CtorType, CD->getLocation())) { HadError = true; } - } else if (First) { - // We set the declaration to have the computed exception spec here. - // We duplicate the one parameter type. + } + + // If a function is explicitly defaulted on its first declaration, + if (First) { + // -- it is implicitly considered to be constexpr if the implicit + // definition would be, + CD->setConstexpr(CD->getParent()->defaultedCopyConstructorIsConstexpr()); + + // -- it is implicitly considered to have the same + // exception-specification as if it had been implicitly declared, and + // + // FIXME: a compatible, but different, explicit exception specification + // will be silently overridden. We should issue a warning if this happens. EPI.ExtInfo = CtorType->getExtInfo(); + + // -- [...] it shall have the same parameter type as if it had been + // implicitly declared. CD->setType(Context.getFunctionType(Context.VoidTy, &ArgType, 1, EPI)); } @@ -3917,7 +3963,8 @@ void Sema::CheckExplicitlyDefaultedCopyAssignment(CXXMethodDecl *MD) { OperType, MD->getLocation())) { HadError = true; } - } else if (First) { + } + if (First) { // We set the declaration to have the computed exception spec here. // We duplicate the one parameter type. EPI.RefQualifier = OperType->getRefQualifier(); @@ -3974,6 +4021,18 @@ void Sema::CheckExplicitlyDefaultedMoveConstructor(CXXConstructorDecl *CD) { HadError = true; } + // C++11 [dcl.fct.def.default]p2: + // An explicitly-defaulted function may be declared constexpr only if it + // would have been implicitly declared as constexpr, + if (CD->isConstexpr()) { + if (!CD->getParent()->defaultedMoveConstructorIsConstexpr()) { + Diag(CD->getLocStart(), diag::err_incorrect_defaulted_constexpr) + << CXXMoveConstructor; + HadError = true; + } + } + // and may have an explicit exception-specification only if it is compatible + // with the exception-specification on the implicit declaration. if (CtorType->hasExceptionSpec()) { if (CheckEquivalentExceptionSpec( PDiag(diag::err_incorrect_defaulted_exception_spec) @@ -3983,10 +4042,23 @@ void Sema::CheckExplicitlyDefaultedMoveConstructor(CXXConstructorDecl *CD) { CtorType, CD->getLocation())) { HadError = true; } - } else if (First) { - // We set the declaration to have the computed exception spec here. - // We duplicate the one parameter type. + } + + // If a function is explicitly defaulted on its first declaration, + if (First) { + // -- it is implicitly considered to be constexpr if the implicit + // definition would be, + CD->setConstexpr(CD->getParent()->defaultedMoveConstructorIsConstexpr()); + + // -- it is implicitly considered to have the same + // exception-specification as if it had been implicitly declared, and + // + // FIXME: a compatible, but different, explicit exception specification + // will be silently overridden. We should issue a warning if this happens. EPI.ExtInfo = CtorType->getExtInfo(); + + // -- [...] it shall have the same parameter type as if it had been + // implicitly declared. CD->setType(Context.getFunctionType(Context.VoidTy, &ArgType, 1, EPI)); } @@ -4066,7 +4138,8 @@ void Sema::CheckExplicitlyDefaultedMoveAssignment(CXXMethodDecl *MD) { OperType, MD->getLocation())) { HadError = true; } - } else if (First) { + } + if (First) { // We set the declaration to have the computed exception spec here. // We duplicate the one parameter type. EPI.RefQualifier = OperType->getRefQualifier(); @@ -4113,7 +4186,8 @@ void Sema::CheckExplicitlyDefaultedDestructor(CXXDestructorDecl *DD) { DD->setInvalidDecl(); return; } - } else if (First) { + } + if (First) { // We set the declaration to have the computed exception spec here. // There are no parameters. EPI.ExtInfo = DtorType->getExtInfo(); @@ -6792,16 +6866,12 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor( DeclarationName Name = Context.DeclarationNames.getCXXConstructorName(ClassType); DeclarationNameInfo NameInfo(Name, ClassLoc); - CXXConstructorDecl *DefaultCon - = CXXConstructorDecl::Create(Context, ClassDecl, ClassLoc, NameInfo, - Context.getFunctionType(Context.VoidTy, - 0, 0, EPI), - /*TInfo=*/0, - /*isExplicit=*/false, - /*isInline=*/true, - /*isImplicitlyDeclared=*/true, - // FIXME: apply the rules for definitions here - /*isConstexpr=*/false); + CXXConstructorDecl *DefaultCon = CXXConstructorDecl::Create( + Context, ClassDecl, ClassLoc, NameInfo, + Context.getFunctionType(Context.VoidTy, 0, 0, EPI), /*TInfo=*/0, + /*isExplicit=*/false, /*isInline=*/true, /*isImplicitlyDeclared=*/true, + /*isConstexpr=*/ClassDecl->defaultedDefaultConstructorIsConstexpr() && + getLangOptions().CPlusPlus0x); DefaultCon->setAccess(AS_public); DefaultCon->setDefaulted(); DefaultCon->setImplicit(); @@ -8476,21 +8546,17 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor( DeclarationNameInfo NameInfo(Name, ClassLoc); // An implicitly-declared copy constructor is an inline public - // member of its class. - CXXConstructorDecl *CopyConstructor - = CXXConstructorDecl::Create(Context, ClassDecl, ClassLoc, NameInfo, - Context.getFunctionType(Context.VoidTy, - &ArgType, 1, EPI), - /*TInfo=*/0, - /*isExplicit=*/false, - /*isInline=*/true, - /*isImplicitlyDeclared=*/true, - // FIXME: apply the rules for definitions here - /*isConstexpr=*/false); + // member of its class. + CXXConstructorDecl *CopyConstructor = CXXConstructorDecl::Create( + Context, ClassDecl, ClassLoc, NameInfo, + Context.getFunctionType(Context.VoidTy, &ArgType, 1, EPI), /*TInfo=*/0, + /*isExplicit=*/false, /*isInline=*/true, /*isImplicitlyDeclared=*/true, + /*isConstexpr=*/ClassDecl->defaultedCopyConstructorIsConstexpr() && + getLangOptions().CPlusPlus0x); CopyConstructor->setAccess(AS_public); CopyConstructor->setDefaulted(); CopyConstructor->setTrivial(ClassDecl->hasTrivialCopyConstructor()); - + // Note that we have declared this constructor. ++ASTContext::NumImplicitCopyConstructorsDeclared; @@ -8631,21 +8697,17 @@ CXXConstructorDecl *Sema::DeclareImplicitMoveConstructor( // C++0x [class.copy]p11: // An implicitly-declared copy/move constructor is an inline public - // member of its class. - CXXConstructorDecl *MoveConstructor - = CXXConstructorDecl::Create(Context, ClassDecl, ClassLoc, NameInfo, - Context.getFunctionType(Context.VoidTy, - &ArgType, 1, EPI), - /*TInfo=*/0, - /*isExplicit=*/false, - /*isInline=*/true, - /*isImplicitlyDeclared=*/true, - // FIXME: apply the rules for definitions here - /*isConstexpr=*/false); + // member of its class. + CXXConstructorDecl *MoveConstructor = CXXConstructorDecl::Create( + Context, ClassDecl, ClassLoc, NameInfo, + Context.getFunctionType(Context.VoidTy, &ArgType, 1, EPI), /*TInfo=*/0, + /*isExplicit=*/false, /*isInline=*/true, /*isImplicitlyDeclared=*/true, + /*isConstexpr=*/ClassDecl->defaultedMoveConstructorIsConstexpr() && + getLangOptions().CPlusPlus0x); MoveConstructor->setAccess(AS_public); MoveConstructor->setDefaulted(); MoveConstructor->setTrivial(ClassDecl->hasTrivialMoveConstructor()); - + // Add the parameter to the constructor. ParmVarDecl *FromParam = ParmVarDecl::Create(Context, MoveConstructor, ClassLoc, ClassLoc, diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp index 809a0cb176..f173748e96 100644 --- a/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp +++ b/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp @@ -42,13 +42,12 @@ class C2 {} constexpr; // expected-error {{class cannot be marked constexpr}} struct S2 {} constexpr; // expected-error {{struct cannot be marked constexpr}} union U2 {} constexpr; // expected-error {{union cannot be marked constexpr}} enum E2 {} constexpr; // expected-error {{enum cannot be marked constexpr}} -// FIXME: Mark default constructors as 'constexpr' when appropriate. -constexpr class C3 {} c3 = C3(); // unexpected-error {{must be initialized by a constant expression}} unexpected-note {{non-constexpr constructor}} unexpected-note {{here}} -constexpr struct S3 {} s3 = S3(); // unexpected-error {{must be initialized by a constant expression}} unexpected-note {{non-constexpr constructor}} unexpected-note {{here}} +constexpr class C3 {} c3 = C3(); +constexpr struct S3 {} s3 = S3(); constexpr union U3 {} u3 = {}; constexpr enum E3 { V3 } e3 = V3; -class C4 {} constexpr c4 = C4(); // unexpected-error {{must be initialized by a constant expression}} unexpected-note {{non-constexpr constructor}} unexpected-note {{here}} -struct S4 {} constexpr s4 = S4(); // unexpected-error {{must be initialized by a constant expression}} unexpected-note {{non-constexpr constructor}} unexpected-note {{here}} +class C4 {} constexpr c4 = C4(); +struct S4 {} constexpr s4 = S4(); union U4 {} constexpr u4 = {}; enum E4 { V4 } constexpr e4 = V4; constexpr int; // expected-error {{constexpr can only be used in variable and function declarations}} diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp index 03406dbf91..1b31d21f36 100644 --- a/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp +++ b/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp @@ -30,7 +30,7 @@ struct SS : S { // The definition of a constexpr function shall satisfy the following // constraints: -struct T : SS { // expected-note {{base class 'SS' of non-literal type}} +struct T : SS, NonLiteral { // expected-note {{base class 'NonLiteral' of non-literal type}} constexpr T(); // expected-error {{non-literal type 'T' cannot have constexpr members}} // - it shall not be virtual; diff --git a/test/CXX/dcl.decl/dcl.fct.def/dcl.fct.def.default/p2.cpp b/test/CXX/dcl.decl/dcl.fct.def/dcl.fct.def.default/p2.cpp new file mode 100644 index 0000000000..d401a97ca2 --- /dev/null +++ b/test/CXX/dcl.decl/dcl.fct.def/dcl.fct.def.default/p2.cpp @@ -0,0 +1,55 @@ +// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s + +// An explicitly-defaulted function may be declared constexpr only if it would +// have been implicitly declared as constexpr. +struct S1 { + constexpr S1() = default; // expected-error {{defaulted definition of default constructor is not constexpr}} + constexpr S1(const S1&) = default; + constexpr S1(S1&&) = default; + constexpr S1 &operator=(const S1&) = default; // expected-error {{explicitly-defaulted copy assignment operator may not have}} + constexpr S1 &operator=(S1&&) = default; // expected-error {{explicitly-defaulted move assignment operator may not have}} + constexpr ~S1() = default; // expected-error {{destructor cannot be marked constexpr}} + int n; +}; +struct NoCopyMove { + constexpr NoCopyMove() {} + NoCopyMove(const NoCopyMove&); + NoCopyMove(NoCopyMove&&); +}; +struct S2 { + constexpr S2() = default; + constexpr S2(const S2&) = default; // expected-error {{defaulted definition of copy constructor is not constexpr}} + constexpr S2(S2&&) = default; // expected-error {{defaulted definition of move constructor is not constexpr}} + NoCopyMove ncm; +}; + +// If a function is explicitly defaulted on its first declaration +// -- it is implicitly considered to be constexpr if the implicit declaration +// would be +struct S3 { + S3() = default; // expected-note {{here}} + S3(const S3&) = default; + S3(S3&&) = default; + constexpr S3(int n) : n(n) {} + int n; +}; +constexpr S3 s3a = S3(0); +constexpr S3 s3b = s3a; +constexpr S3 s3c = S3(); // expected-error {{constant expression}} expected-note {{non-constexpr constructor}} + +struct S4 { + S4() = default; + S4(const S4&) = default; // expected-note {{here}} + S4(S4&&) = default; // expected-note {{here}} + NoCopyMove ncm; +}; +constexpr S4 s4a; // ok +constexpr S4 s4b = S4(); // expected-error {{constant expression}} expected-note {{non-constexpr constructor}} +constexpr S4 s4c = s4a; // expected-error {{constant expression}} expected-note {{non-constexpr constructor}} + +struct S5 { + constexpr S5(); + int n = 1, m = n + 3; +}; +constexpr S5::S5() = default; +static_assert(S5().m == 4, ""); diff --git a/test/CXX/special/class.copy/p13-0x.cpp b/test/CXX/special/class.copy/p13-0x.cpp new file mode 100644 index 0000000000..30d8c6ebad --- /dev/null +++ b/test/CXX/special/class.copy/p13-0x.cpp @@ -0,0 +1,55 @@ +// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s + +// If the implicitly-defined constructor would satisfy the requirements of a +// constexpr constructor, the implicitly-defined constructor is constexpr. +struct Constexpr1 { + constexpr Constexpr1() : n(0) {} + int n; +}; +constexpr Constexpr1 c1a = Constexpr1(Constexpr1()); // ok +constexpr Constexpr1 c1b = Constexpr1(Constexpr1(c1a)); // ok + +struct Constexpr2 { + Constexpr1 ce1; + constexpr Constexpr2() = default; + constexpr Constexpr2(const Constexpr2 &o) : ce1(o.ce1) {} + // no move constructor +}; + +constexpr Constexpr2 c2a = Constexpr2(Constexpr2()); // ok +constexpr Constexpr2 c2b = Constexpr2(Constexpr2(c2a)); // ok + +struct Constexpr3 { + Constexpr2 ce2; + // all special constructors are constexpr, move ctor calls ce2's copy ctor +}; + +constexpr Constexpr3 c3a = Constexpr3(Constexpr3()); // ok +constexpr Constexpr3 c3b = Constexpr3(Constexpr3(c3a)); // ok + +struct NonConstexprCopy { + constexpr NonConstexprCopy() = default; + NonConstexprCopy(const NonConstexprCopy &); + constexpr NonConstexprCopy(NonConstexprCopy &&) = default; + + int n = 42; +}; + +NonConstexprCopy::NonConstexprCopy(const NonConstexprCopy &) = default; // expected-note {{here}} + +constexpr NonConstexprCopy ncc1 = NonConstexprCopy(NonConstexprCopy()); // ok +constexpr NonConstexprCopy ncc2 = ncc1; // expected-error {{constant expression}} expected-note {{non-constexpr constructor}} + +struct NonConstexprDefault { + NonConstexprDefault() = default; + constexpr NonConstexprDefa |