diff options
24 files changed, 432 insertions, 332 deletions
diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index fbb3a582ca..bf30777922 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -2847,6 +2847,8 @@ public: } else if (EPI.ExceptionSpecType == EST_Uninstantiated) { EPI.ExceptionSpecDecl = getExceptionSpecDecl(); EPI.ExceptionSpecTemplate = getExceptionSpecTemplate(); + } else if (EPI.ExceptionSpecType == EST_Unevaluated) { + EPI.ExceptionSpecDecl = getExceptionSpecDecl(); } if (hasAnyConsumedArgs()) EPI.ConsumedArguments = getConsumedArgsBuffer(); @@ -2890,11 +2892,13 @@ public: // NoexceptExpr sits where the arguments end. return *reinterpret_cast<Expr *const *>(arg_type_end()); } - /// \brief If this function type has an uninstantiated exception - /// specification, this is the function whose exception specification - /// is represented by this type. + /// \brief If this function type has an exception specification which hasn't + /// been determined yet (either because it has not been evaluated or because + /// it has not been instantiated), this is the function whose exception + /// specification is represented by this type. FunctionDecl *getExceptionSpecDecl() const { - if (getExceptionSpecType() != EST_Uninstantiated) + if (getExceptionSpecType() != EST_Uninstantiated && + getExceptionSpecType() != EST_Unevaluated) return 0; return reinterpret_cast<FunctionDecl * const *>(arg_type_end())[0]; } @@ -2909,7 +2913,7 @@ public: } bool isNothrow(ASTContext &Ctx) const { ExceptionSpecificationType EST = getExceptionSpecType(); - assert(EST != EST_Delayed && EST != EST_Uninstantiated); + assert(EST != EST_Unevaluated && EST != EST_Uninstantiated); if (EST == EST_DynamicNone || EST == EST_BasicNoexcept) return true; if (EST != EST_ComputedNoexcept) diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 6a4e7d8c9b..eb8fcbba3e 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -870,8 +870,6 @@ def warn_missing_exception_specification : Warning< "%0 is missing exception specification '%1'">; def err_noexcept_needs_constant_expression : Error< "argument to noexcept specifier must be a constant expression">; -def err_exception_spec_unknown : Error< - "exception specification is not available until end of class definition">; // C++ access checking def err_class_redeclared_with_different_access : Error< @@ -5088,6 +5086,9 @@ def err_in_class_initializer_literal_type : Error< "'constexpr' specifier">; def err_in_class_initializer_non_constant : Error< "in-class initializer for static data member is not a constant expression">; +def err_in_class_initializer_references_def_ctor : Error< + "defaulted default constructor of %0 cannot be used by non-static data " + "member initializer which appears before end of class definition">; def ext_in_class_initializer_non_constant : Extension< "in-class initializer for static data member is not a constant expression; " diff --git a/include/clang/Basic/ExceptionSpecificationType.h b/include/clang/Basic/ExceptionSpecificationType.h index 6be5053b1b..edd89ec709 100644 --- a/include/clang/Basic/ExceptionSpecificationType.h +++ b/include/clang/Basic/ExceptionSpecificationType.h @@ -25,7 +25,7 @@ enum ExceptionSpecificationType { EST_MSAny, ///< Microsoft throw(...) extension EST_BasicNoexcept, ///< noexcept EST_ComputedNoexcept, ///< noexcept(expression) - EST_Delayed, ///< not known yet + EST_Unevaluated, ///< not evaluated yet, for special member function EST_Uninstantiated ///< not instantiated yet }; @@ -37,6 +37,10 @@ inline bool isNoexceptExceptionSpec(ExceptionSpecificationType ESpecType) { return ESpecType == EST_BasicNoexcept || ESpecType == EST_ComputedNoexcept; } +inline bool isUnresolvedExceptionSpec(ExceptionSpecificationType ESpecType) { + return ESpecType == EST_Unevaluated || ESpecType == EST_Uninstantiated; +} + /// \brief Possible results from evaluation of a noexcept expression. enum CanThrowResult { CT_Cannot, diff --git a/include/clang/Sema/DeclSpec.h b/include/clang/Sema/DeclSpec.h index 7999748b0f..00d42a814a 100644 --- a/include/clang/Sema/DeclSpec.h +++ b/include/clang/Sema/DeclSpec.h @@ -1152,8 +1152,7 @@ struct DeclaratorChunk { /// any. unsigned MutableLoc; - /// \brief When ExceptionSpecType isn't EST_None or EST_Delayed, the - /// location of the keyword introducing the spec. + /// \brief The location of the keyword introducing the spec, if any. unsigned ExceptionSpecLoc; /// ArgInfo - This is a pointer to a new[]'d array of ParamInfo objects that diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index e5b3b5a012..9675e08e4a 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -3335,17 +3335,6 @@ public: /// \brief Integrate an invoked expression into the collected data. void CalledExpr(Expr *E); - /// \brief Specify that the exception specification can't be detemined yet. - void SetDelayed() { - ClearExceptions(); - ComputedEST = EST_Delayed; - } - - /// \brief Have we been unable to compute this exception specification? - bool isDelayed() { - return ComputedEST == EST_Delayed; - } - /// \brief Overwrite an EPI's exception specification with this /// computed exception specification. void getEPI(FunctionProtoType::ExtProtoInfo &EPI) const { @@ -3363,34 +3352,39 @@ public: /// \brief Determine what sort of exception specification a defaulted /// copy constructor of a class will have. ImplicitExceptionSpecification - ComputeDefaultedDefaultCtorExceptionSpec(CXXRecordDecl *ClassDecl); + ComputeDefaultedDefaultCtorExceptionSpec(SourceLocation Loc, + CXXMethodDecl *MD); /// \brief Determine what sort of exception specification a defaulted /// default constructor of a class will have, and whether the parameter /// will be const. - std::pair<ImplicitExceptionSpecification, bool> - ComputeDefaultedCopyCtorExceptionSpecAndConst(CXXRecordDecl *ClassDecl); + ImplicitExceptionSpecification + ComputeDefaultedCopyCtorExceptionSpec(CXXMethodDecl *MD); /// \brief Determine what sort of exception specification a defautled /// copy assignment operator of a class will have, and whether the /// parameter will be const. - std::pair<ImplicitExceptionSpecification, bool> - ComputeDefaultedCopyAssignmentExceptionSpecAndConst(CXXRecordDecl *ClassDecl); + ImplicitExceptionSpecification + ComputeDefaultedCopyAssignmentExceptionSpec(CXXMethodDecl *MD); /// \brief Determine what sort of exception specification a defaulted move /// constructor of a class will have. ImplicitExceptionSpecification - ComputeDefaultedMoveCtorExceptionSpec(CXXRecordDecl *ClassDecl); + ComputeDefaultedMoveCtorExceptionSpec(CXXMethodDecl *MD); /// \brief Determine what sort of exception specification a defaulted move /// assignment operator of a class will have. ImplicitExceptionSpecification - ComputeDefaultedMoveAssignmentExceptionSpec(CXXRecordDecl *ClassDecl); + ComputeDefaultedMoveAssignmentExceptionSpec(CXXMethodDecl *MD); /// \brief Determine what sort of exception specification a defaulted /// destructor of a class will have. ImplicitExceptionSpecification - ComputeDefaultedDtorExceptionSpec(CXXRecordDecl *ClassDecl); + ComputeDefaultedDtorExceptionSpec(CXXMethodDecl *MD); + + /// \brief Evaluate the implicit exception specification for a defaulted + /// special member function. + void EvaluateImplicitExceptionSpec(SourceLocation Loc, CXXMethodDecl *MD); /// \brief Check the given exception-specification and update the /// extended prototype information with the results. @@ -3438,8 +3432,7 @@ public: /// C++11 says that user-defined destructors with no exception spec get one /// that looks as if the destructor was implicitly declared. void AdjustDestructorExceptionSpec(CXXRecordDecl *ClassDecl, - CXXDestructorDecl *Destructor, - bool WasDelayed = false); + CXXDestructorDecl *Destructor); /// \brief Declare all inherited constructors for the given class. /// @@ -4262,6 +4255,11 @@ public: void MarkVTableUsed(SourceLocation Loc, CXXRecordDecl *Class, bool DefinitionRequired = false); + /// \brief Mark the exception specifications of all virtual member functions + /// in the given class as needed. + void MarkVirtualMemberExceptionSpecsNeeded(SourceLocation Loc, + const CXXRecordDecl *RD); + /// MarkVirtualMembersReferenced - Will mark all members of the given /// CXXRecordDecl referenced. void MarkVirtualMembersReferenced(SourceLocation Loc, diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 2e13d0cc44..5b57ce4557 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -2367,15 +2367,18 @@ ASTContext::getFunctionType(QualType ResultTy, // - exception types // - consumed-arguments flags // Instead of the exception types, there could be a noexcept - // expression. + // expression, or information used to resolve the exception + // specification. size_t Size = sizeof(FunctionProtoType) + NumArgs * sizeof(QualType); - if (EPI.ExceptionSpecType == EST_Dynamic) + if (EPI.ExceptionSpecType == EST_Dynamic) { Size += EPI.NumExceptions * sizeof(QualType); - else if (EPI.ExceptionSpecType == EST_ComputedNoexcept) { + } else if (EPI.ExceptionSpecType == EST_ComputedNoexcept) { Size += sizeof(Expr*); } else if (EPI.ExceptionSpecType == EST_Uninstantiated) { Size += 2 * sizeof(FunctionDecl*); + } else if (EPI.ExceptionSpecType == EST_Unevaluated) { + Size += sizeof(FunctionDecl*); } if (EPI.ConsumedArguments) Size += NumArgs * sizeof(bool); diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index eacf505442..abefae44b2 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -1584,6 +1584,11 @@ FunctionProtoType::FunctionProtoType(QualType result, const QualType *args, slot[1] = epi.ExceptionSpecTemplate; // This exception specification doesn't make the type dependent, because // it's not instantiated as part of instantiating the type. + } else if (getExceptionSpecType() == EST_Unevaluated) { + // Store the function decl from which we will resolve our + // exception specification. + FunctionDecl **slot = reinterpret_cast<FunctionDecl**>(argSlot + numArgs); + slot[0] = epi.ExceptionSpecDecl; } if (epi.ConsumedArguments) { @@ -1667,7 +1672,8 @@ void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID, QualType Result, ID.AddPointer(epi.Exceptions[i].getAsOpaquePtr()); } else if (epi.ExceptionSpecType == EST_ComputedNoexcept && epi.NoexceptExpr){ epi.NoexceptExpr->Profile(ID, Context, false); - } else if (epi.ExceptionSpecType == EST_Uninstantiated) { + } else if (epi.ExceptionSpecType == EST_Uninstantiated || + epi.ExceptionSpecType == EST_Unevaluated) { ID.AddPointer(epi.ExceptionSpecDecl->getCanonicalDecl()); } if (epi.ConsumedArguments) { diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp index 1284527595..05c53850f5 100644 --- a/lib/Analysis/CFG.cpp +++ b/lib/Analysis/CFG.cpp @@ -1340,7 +1340,7 @@ static bool CanThrow(Expr *E, ASTContext &Ctx) { const FunctionType *FT = Ty->getAs<FunctionType>(); if (FT) { if (const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(FT)) - if (Proto->getExceptionSpecType() != EST_Uninstantiated && + if (!isUnresolvedExceptionSpec(Proto->getExceptionSpecType()) && Proto->isNothrow(Ctx)) return false; } diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 7233fc7c13..81b94a4ecd 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -4655,11 +4655,6 @@ static bool FindOverriddenMethod(const CXXBaseSpecifier *Specifier, return false; } -static bool hasDelayedExceptionSpec(CXXMethodDecl *Method) { - const FunctionProtoType *Proto =Method->getType()->getAs<FunctionProtoType>(); - return Proto && Proto->getExceptionSpecType() == EST_Delayed; -} - /// AddOverriddenMethods - See if a method overrides any in the base classes, /// and if so, check that it's a valid override and remember it. bool Sema::AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) { @@ -4675,8 +4670,7 @@ bool Sema::AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) { if (CXXMethodDecl *OldMD = dyn_cast<CXXMethodDecl>(*I)) { MD->addOverriddenMethod(OldMD->getCanonicalDecl()); if (!CheckOverridingFunctionReturnType(MD, OldMD) && - (hasDelayedExceptionSpec(MD) || - !CheckOverridingFunctionExceptionSpec(MD, OldMD)) && + !CheckOverridingFunctionExceptionSpec(MD, OldMD) && !CheckIfOverriddenFunctionIsMarkedFinal(MD, OldMD)) { AddedAny = true; } diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 1480c2ef98..9c4272de0c 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -128,8 +128,8 @@ namespace { void Sema::ImplicitExceptionSpecification::CalledDecl(SourceLocation CallLoc, CXXMethodDecl *Method) { - // If we have an MSAny or unknown spec already, don't bother. - if (!Method || ComputedEST == EST_MSAny || ComputedEST == EST_Delayed) + // If we have an MSAny spec already, don't bother. + if (!Method || ComputedEST == EST_MSAny) return; const FunctionProtoType *Proto @@ -141,7 +141,7 @@ void Sema::ImplicitExceptionSpecification::CalledDecl(SourceLocation CallLoc, ExceptionSpecificationType EST = Proto->getExceptionSpecType(); // If this function can throw any exceptions, make a note of that. - if (EST == EST_Delayed || EST == EST_MSAny || EST == EST_None) { + if (EST == EST_MSAny || EST == EST_None) { ClearExceptions(); ComputedEST = EST; return; @@ -198,7 +198,7 @@ void Sema::ImplicitExceptionSpecification::CalledDecl(SourceLocation CallLoc, } void Sema::ImplicitExceptionSpecification::CalledExpr(Expr *E) { - if (!E || ComputedEST == EST_MSAny || ComputedEST == EST_Delayed) + if (!E || ComputedEST == EST_MSAny) return; // FIXME: @@ -3881,9 +3881,6 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) { // instantiated (e.g. meta-functions). This doesn't apply to classes that // have inherited constructors. DeclareInheritedConstructors(Record); - - if (!Record->isDependentType()) - CheckExplicitlyDefaultedMethods(Record); } void Sema::CheckExplicitlyDefaultedMethods(CXXRecordDecl *Record) { @@ -3989,6 +3986,45 @@ static bool defaultedSpecialMemberIsConstexpr(Sema &S, CXXRecordDecl *ClassDecl, return true; } +static Sema::ImplicitExceptionSpecification +computeImplicitExceptionSpec(Sema &S, SourceLocation Loc, CXXMethodDecl *MD) { + switch (S.getSpecialMember(MD)) { + case Sema::CXXDefaultConstructor: + return S.ComputeDefaultedDefaultCtorExceptionSpec(Loc, MD); + case Sema::CXXCopyConstructor: + return S.ComputeDefaultedCopyCtorExceptionSpec(MD); + case Sema::CXXCopyAssignment: + return S.ComputeDefaultedCopyAssignmentExceptionSpec(MD); + case Sema::CXXMoveConstructor: + return S.ComputeDefaultedMoveCtorExceptionSpec(MD); + case Sema::CXXMoveAssignment: + return S.ComputeDefaultedMoveAssignmentExceptionSpec(MD); + case Sema::CXXDestructor: + return S.ComputeDefaultedDtorExceptionSpec(MD); + case Sema::CXXInvalid: + break; + } + llvm_unreachable("only special members have implicit exception specs"); +} + +void Sema::EvaluateImplicitExceptionSpec(SourceLocation Loc, CXXMethodDecl *MD) { + const FunctionProtoType *FPT = MD->getType()->castAs<FunctionProtoType>(); + if (FPT->getExceptionSpecType() != EST_Unevaluated) + return; + + // Evaluate the exception specification and update the type of the special + // member to use it. + FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo(); + computeImplicitExceptionSpec(*this, Loc, MD).getEPI(EPI); + const FunctionProtoType *NewFPT = cast<FunctionProtoType>( + Context.getFunctionType(FPT->getResultType(), FPT->arg_type_begin(), + FPT->getNumArgs(), EPI)); + MD->setType(QualType(NewFPT, 0)); +} + +static bool isImplicitCopyCtorArgConst(Sema &S, CXXRecordDecl *ClassDecl); +static bool isImplicitCopyAssignmentArgConst(Sema &S, CXXRecordDecl *ClassDecl); + void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) { CXXRecordDecl *RD = MD->getParent(); CXXSpecialMember CSM = getSpecialMember(MD); @@ -4023,40 +4059,28 @@ void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) { const FunctionProtoType *Type = MD->getType()->getAs<FunctionProtoType>(); - // Compute implicit exception specification, argument constness, constexpr - // and triviality. - ImplicitExceptionSpecification Spec(*this); + // Compute argument constness, constexpr, and triviality. bool CanHaveConstParam = false; bool Trivial; switch (CSM) { case CXXDefaultConstructor: - Spec = ComputeDefaultedDefaultCtorExceptionSpec(RD); - if (Spec.isDelayed()) - // Exception specification depends on some deferred part of the class. - // We'll try again when the class's definition has been fully processed. - return; Trivial = RD->hasTrivialDefaultConstructor(); break; case CXXCopyConstructor: - llvm::tie(Spec, CanHaveConstParam) = - ComputeDefaultedCopyCtorExceptionSpecAndConst(RD); + CanHaveConstParam = isImplicitCopyCtorArgConst(*this, RD); Trivial = RD->hasTrivialCopyConstructor(); break; case CXXCopyAssignment: - llvm::tie(Spec, CanHaveConstParam) = - ComputeDefaultedCopyAssignmentExceptionSpecAndConst(RD); + CanHaveConstParam = isImplicitCopyAssignmentArgConst(*this, RD); Trivial = RD->hasTrivialCopyAssignment(); break; case CXXMoveConstructor: - Spec = ComputeDefaultedMoveCtorExceptionSpec(RD); Trivial = RD->hasTrivialMoveConstructor(); break; case CXXMoveAssignment: - Spec = ComputeDefaultedMoveAssignmentExceptionSpec(RD); Trivial = RD->hasTrivialMoveAssignment(); break; case CXXDestructor: - Spec = ComputeDefaultedDtorExceptionSpec(RD); Trivial = RD->hasTrivialDestructor(); break; case CXXInvalid: @@ -4126,11 +4150,15 @@ void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) { HadError = true; } - // Rebuild the type with the implicit exception specification added. - FunctionProtoType::ExtProtoInfo EPI = Type->getExtProtoInfo(); - Spec.getEPI(EPI); - const FunctionProtoType *ImplicitType = cast<FunctionProtoType>( - Context.getFunctionType(ReturnType, &ArgType, ExpectedParams, EPI)); + // Rebuild the type with the implicit exception specification added, if we + // are going to need it. + const FunctionProtoType *ImplicitType = 0; + if (First || Type->hasExceptionSpec()) { + FunctionProtoType::ExtProtoInfo EPI = Type->getExtProtoInfo(); + computeImplicitExceptionSpec(*this, MD->getLocation(), MD).getEPI(EPI); + ImplicitType = cast<FunctionProtoType>( + Context.getFunctionType(ReturnType, &ArgType, ExpectedParams, EPI)); + } // C++11 [dcl.fct.def.default]p2: // An explicitly-defaulted function may be declared constexpr only if it @@ -6685,7 +6713,10 @@ namespace { } Sema::ImplicitExceptionSpecification -Sema::ComputeDefaultedDefaultCtorExceptionSpec(CXXRecordDecl *ClassDecl) { +Sema::ComputeDefaultedDefaultCtorExceptionSpec(SourceLocation Loc, + CXXMethodDecl *MD) { + CXXRecordDecl *ClassDecl = MD->getParent(); + // C++ [except.spec]p14: // An implicitly declared special member function (Clause 12) shall have an // exception-specification. [...] @@ -6732,7 +6763,21 @@ Sema::ComputeDefaultedDefaultCtorExceptionSpec(CXXRecordDecl *ClassDecl) { if (Expr *E = F->getInClassInitializer()) ExceptSpec.CalledExpr(E); else if (!F->isInvalidDecl()) - ExceptSpec.SetDelayed(); + // DR1351: + // If the brace-or-equal-initializer of a non-static data member + // invokes a defaulted default constructor of its class or of an + // enclosing class in a potentially evaluated subexpression, the + // program is ill-formed. + // + // This resolution is unworkable: the exception specification of the + // default constructor can be needed in an unevaluated context, in + // particular, in the operand of a noexcept-expression, and we can be + // unable to compute an exception specification for an enclosed class. + // + // We do not allow an in-class initializer to require the evaluation + // of the exception specification for any in-class initializer whose + // definition is not lexically complete. + Diag(Loc, diag::err_in_class_initializer_references_def_ctor) << MD; } else if (const RecordType *RecordTy = Context.getBaseElementType(F->getType())->getAs<RecordType>()) { CXXRecordDecl *FieldRecDecl = cast<CXXRecordDecl>(RecordTy->getDecl()); @@ -6761,10 +6806,6 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor( assert(!ClassDecl->hasUserDeclaredConstructor() && "Should not build implicit default constructor!"); - ImplicitExceptionSpecification Spec = - ComputeDefaultedDefaultCtorExceptionSpec(ClassDecl); - FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI(); - bool Constexpr = defaultedSpecialMemberIsConstexpr(*this, ClassDecl, CXXDefaultConstructor, false); @@ -6777,15 +6818,20 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor( = 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, + Context, ClassDecl, ClassLoc, NameInfo, /*Type*/QualType(), /*TInfo=*/0, /*isExplicit=*/false, /*isInline=*/true, /*isImplicitlyDeclared=*/true, Constexpr); DefaultCon->setAccess(AS_public); DefaultCon->setDefaulted(); DefaultCon->setImplicit(); DefaultCon->setTrivial(ClassDecl->hasTrivialDefaultConstructor()); - + + // Build an exception specification pointing back at this constructor. + FunctionProtoType::ExtProtoInfo EPI; + EPI.ExceptionSpecType = EST_Unevaluated; + EPI.ExceptionSpecDecl = DefaultCon; + DefaultCon->setType(Context.getFunctionType(Context.VoidTy, 0, 0, EPI)); + // Note that we have declared this constructor. ++ASTContext::NumImplicitDefaultConstructorsDeclared; @@ -6830,58 +6876,14 @@ void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation, } } -/// Get any existing defaulted default constructor for the given class. Do not -/// implicitly define one if it does not exist. -static CXXConstructorDecl *getDefaultedDefaultConstructorUnsafe(Sema &Self, - CXXRecordDecl *D) { - ASTContext &Context = Self.Context; - QualType ClassType = Context.getTypeDeclType(D); - DeclarationName ConstructorName - = Context.DeclarationNames.getCXXConstructorName( - Context.getCanonicalType(ClassType.getUnqualifiedType())); - - DeclContext::lookup_const_iterator Con, ConEnd; - for (llvm::tie(Con, ConEnd) = D->lookup(ConstructorName); - Con != ConEnd; ++Con) { - // A function template cannot be defaulted. - if (isa<FunctionTemplateDecl>(*Con)) - continue; - - CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(*Con); - if (Constructor->isDefaultConstructor()) - return Constructor->isDefaulted() ? Constructor : 0; - } - return 0; -} - void Sema::ActOnFinishDelayedMemberInitializers(Decl *D) { if (!D) return; AdjustDeclIfTemplate(D); CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(D); - CXXConstructorDecl *CtorDecl - = getDefaultedDefaultConstructorUnsafe(*this, ClassDecl); - - if (!CtorDecl) return; - - // Compute the exception specification for the default constructor. - const FunctionProtoType *CtorTy = - CtorDecl->getType()->castAs<FunctionProtoType>(); - if (CtorTy->getExceptionSpecType() == EST_Delayed) { - // FIXME: Don't do this unless the exception spec is needed. - ImplicitExceptionSpecification Spec = - ComputeDefaultedDefaultCtorExceptionSpec(ClassDecl); - FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI(); - assert(EPI.ExceptionSpecType != EST_Delayed); - CtorDecl->setType(Context.getFunctionType(Context.VoidTy, 0, 0, EPI)); - } - - // If the default constructor is explicitly defaulted, checking the exception - // specification is deferred until now. - if (!CtorDecl->isInvalidDecl() && CtorDecl->isExplicitlyDefaulted() && - !ClassDecl->isDependentType()) - CheckExplicitlyDefaultedSpecialMember(CtorDecl); + if (!ClassDecl->isDependentType()) + CheckExplicitlyDefaultedMethods(ClassDecl); } void Sema::DeclareInheritedConstructors(CXXRecordDecl *ClassDecl) { @@ -7065,7 +7067,9 @@ void Sema::DeclareInheritedConstructors(CXXRecordDecl *ClassDecl) { } Sema::ImplicitExceptionSpecification -Sema::ComputeDefaultedDtorExceptionSpec(CXXRecordDecl *ClassDecl) { +Sema::ComputeDefaultedDtorExceptionSpec(CXXMethodDecl *MD) { + CXXRecordDecl *ClassDecl = MD->getParent(); + // C++ [except.spec]p14: // An implicitly declared special member function (Clause 12) shall have // an exception-specification. @@ -7112,14 +7116,8 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) { // If a class has no user-declared destructor, a destructor is // declared implicitly. An implicitly-declared destructor is an // inline public member of its class. - - ImplicitExceptionSpecification Spec = - ComputeDefaultedDtorExceptionSpec(ClassDecl); - FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI(); // Create the actual destructor declaration. - QualType Ty = Context.getFunctionType(Context.VoidTy, 0, 0, EPI); - CanQualType ClassType = Context.getCanonicalType(Context.getTypeDeclType(ClassDecl)); SourceLocation ClassLoc = ClassDecl->getLocation(); @@ -7127,24 +7125,27 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) { = Context.DeclarationNames.getCXXDestructorName(ClassType); DeclarationNameInfo NameInfo(Name, ClassLoc); CXXDestructorDecl *Destructor - = CXXDestructorDecl::Create(Context, ClassDecl, ClassLoc, NameInfo, Ty, 0, - /*isInline=*/true, + = CXXDestructorDecl::Create(Context, ClassDecl, ClassLoc, NameInfo, + QualType(), 0, /*isInline=*/true, /*isImplicitlyDeclared=*/true); Destructor->setAccess(AS_public); Destructor->setDefaulted(); Destructor->setImplicit(); Destructor->setTrivial(ClassDecl->hasTrivialDestructor()); - + + // Build an exception specification pointing back at this destructor. + FunctionProtoType::ExtProtoInfo EPI; + EPI.ExceptionSpecType = EST_Unevaluated; + EPI.ExceptionSpecDecl = Destructor; + Destructor->setType(Context.getFunctionType(Context.VoidTy, 0, 0, EPI)); + // Note that we have declared this destructor. ++ASTContext::NumImplicitDestructorsDeclared; - + // Introduce this destructor into its scope. if (Scope *S = getScopeForContext(ClassDecl)) PushOnScopeChains(Destructor, S, false); ClassDecl->addDecl(Destructor); - - // This could be uniqued if it ever proves significant. - Destructor->setTypeSourceInfo(Context.getTrivialTypeSourceInfo(Ty)); AddOverriddenMethods(ClassDecl, Destructor); @@ -7194,15 +7195,6 @@ void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation, /// \brief Perform any semantic analysis which needs to be delayed until all /// pending class member declarations have been parsed. void Sema::ActOnFinishCXXMemberDecls() { - // Now we have parsed all exception specifications, determine the implicit - // exception specifications for destructors. - for (unsigned i = 0, e = DelayedDestructorExceptionSpecs.size(); - i != e; ++i) { - CXXDestructorDecl *Dtor = DelayedDestructorExceptionSpecs[i]; - AdjustDestructorExceptionSpec(Dtor->getParent(), Dtor, true); - } - DelayedDestructorExceptionSpecs.clear(); - // Perform any deferred checking of exception specifications for virtual // destructors. for (unsigned i = 0, e = DelayedDestructorExceptionSpecChecks.size(); @@ -7217,44 +7209,33 @@ void Sema::ActOnFinishCXXMemberDecls() { DelayedDestructorExceptionSpecChecks.clear(); } -void Sema::AdjustDestructorExceptionSpec(CXXRecordDecl *classDecl, - CXXDestructorDecl *destructor, - bool WasDelayed) { +void Sema::AdjustDestructorExceptionSpec(CXXRecordDecl *ClassDecl, + CXXDestructorDecl *Destructor) { + assert(getLangOpts().CPlusPlus0x && + "adjusting dtor exception specs was introduced in c++11"); + // C++11 [class.dtor]p3: // A declaration of a destructor that does not have an exception- // specification is implicitly considered to have the same exception- // specification as an implicit declaration. - const FunctionProtoType *dtorType = destructor->getType()-> + const FunctionProtoType *DtorType = Destructor->getType()-> getAs<FunctionProtoType>(); - if (!WasDelayed && dtorType->hasExceptionSpec()) + if (DtorType->hasExceptionSpec()) return; - ImplicitExceptionSpecification exceptSpec = - ComputeDefaultedDtorExceptionSpec(classDecl); - // Replace the destructor's type, building off the existing one. Fortunately, // the only thing of interest in the destructor type is its extended info. // The return and arguments are fixed. - FunctionProtoType::ExtProtoInfo epi = dtorType->getExtProtoInfo(); - epi.ExceptionSpecType = exceptSpec.getExceptionSpecType(); - epi.NumExceptions = exceptSpec.size(); - epi.Exceptions = exceptSpec.data(); - QualType ty = Context.getFunctionType(Context.VoidTy, 0, 0, epi); - - destructor->setType(ty); - - // If we can't compute the exception specification for this destructor yet - // (because it depends on an exception specification which we have not parsed - // yet), make a note that we need to try again when the class is complete. - if (epi.ExceptionSpecType == EST_Delayed) { - assert(!WasDelayed && "couldn't compute destructor exception spec"); - DelayedDestructorExceptionSpecs.push_back(destructor); - } + FunctionProtoType::ExtProtoInfo EPI = DtorType->getExtProtoInfo(); + EPI.ExceptionSpecType = EST_Unevaluated; + EPI.ExceptionSpecDecl = Destructor; + Destructor->setType(Context.getFunctionType(Context.VoidTy, 0, 0, EPI)); // FIXME: If the destructor has a body that could throw, and the newly created // spec doesn't allow exceptions, we should emit a warning, because this // change in behavior can break conforming C++03 programs at runtime. - // However, we don't have a body yet, so it needs to be done somewhere else. + // However, we don't have a body or an exception specification yet, so it + // needs to be done somewhere else. } /// \brief Builds a statement that copies/moves the given entity from \p From to @@ -7456,11 +7437,13 @@ BuildSingleCopyAssign(Sema &S, SourceLocation Loc, QualType T, Loc, Copy.take()); } -std::pair<Sema::ImplicitExceptionSpecification, bool> -Sema::ComputeDefaultedCopyAssignmentExceptionSpecAndConst( - CXXRecordDecl *ClassDecl) { +/// Determine whether an implicit copy assignment operator for ClassDecl has a +/// const argument. +/// FIXME: It ought to be possible to store this on the record. +static bool isImplicitCopyAssignmentArgConst(Sema &S, + CXXRecordDecl *ClassDecl) { if (ClassDecl->isInvalidDecl()) - return std::make_pair(ImplicitExceptionSpecification(*this), true); + return true; // C++ [class.copy]p10: // If the class definition does not explicitly declare a copy @@ -7471,37 +7454,34 @@ Sema::ComputeDefaultedCopyAssignmentExceptionSpecAndConst( // X& X::operator=(const X&) // // if - bool HasConstCopyAssignment = true; - // -- each direct base class B of X has a copy assignment operator // whose parameter is of type const B&, const volatile B& or B, // and for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(), BaseEnd = ClassDecl->bases_end(); - HasConstCopyAssignment && Base != BaseEnd; ++Base) { + Base != BaseEnd; ++Base) { // We'll handle this below - if (LangOpts.CPlusPlus0x && Base->isVirtual()) + if (S.getLangOpts().CPlusPlus0x && Base->isVirtual()) continue; assert(!Base->getType()->isDependentType() && "Cannot generate implicit members for class with dependent bases."); CXXRecordDecl *BaseClassDecl = Base->getType()->getAsCXXRecordDecl(); - HasConstCopyAssignment &= - (bool)LookupCopyingAssignment(BaseClassDecl, Qualifiers::Const, - false, 0); + if (!S.LookupCopyingAssignment(BaseClassDecl, Qualifiers::Const, false, 0)) + return false; } // In C++11, the above citation has "or virtual" added - if (LangOpts.CPlusPlus0x) { + if (S.getLangOpts().CPlusPlus0x) { for (CXXRecordDecl::base_class_iterator Base = ClassDecl->vbases_begin(), BaseEnd = ClassDecl->vbases_end(); - HasConstCopyAssignment && Base != BaseEnd; ++Base) { + Base != BaseEnd; ++Base) { assert(!Base->getType()->isDependentType() && "Cannot generate implicit members for class with dependent bases."); CXXRecordDecl *BaseClassDecl = Base->getType()->getAsCXXRecordDecl(); - HasConstCopyAssignment &= - (bool)LookupCopyingAssignment(BaseClassDecl, Qualifiers::Const, - false, 0); + if (!S.LookupCopyingAssignment(BaseClassDecl, Qualifiers::Const, + false, 0)) + return false; } } @@ -7511,23 +7491,36 @@ Sema::ComputeDefaultedCopyAssignmentExceptionSpecAndConst( // const volatile M& or M. for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), FieldEnd = ClassDecl->field_end(); - HasConstCopyAssignment && Field != FieldEnd; - ++Field) { - QualType FieldType = Context.getBaseElementType(Field->getType()); - if (CXXRecordDecl *FieldClassDecl = FieldType->getAsCXXRecordDecl()) { - HasConstCopyAssignment &= - (bool)LookupCopyingAssignment(FieldClassDecl, Qualifiers::Const, - false, 0); - } + Field != FieldEnd; ++Field) { + QualType FieldType = S.Context.getBaseElementType(Field->getType()); + if (CXXRecordDecl *FieldClassDecl = FieldType->getAsCXXRecordDecl()) + if (!S.LookupCopyingAssignment(FieldClassDecl, Qualifiers::Const, + false, 0)) + return false; } // Otherwise, the implicitly declared copy assignment operator will // have the form // // X& X::operator=(X&) - + + return true; +} + +Sema::ImplicitExceptionSpecification +Sema::ComputeDefaultedCopyAssignmentExceptionSpec(CXXMethodDecl *MD) { + CXXRecordDecl *ClassDecl = MD->getParent(); + + ImplicitExceptionSpecification ExceptSpec(*this); + if (ClassDecl->isInvalidDecl()) + return ExceptSpec; + + const FunctionProtoType *T = MD->getType()->castAs<FunctionProtoType>(); + assert(T->getNumArgs() == 1 && "not a copy assignment op"); + unsigned ArgQuals = T->getArgType(0).getNonReferenceType().getCVRQualifiers(); + // C++ [except.spec]p14: - // An implicitly declared special member function (Clause 12) shall have an + // An implicitly declared special member function (Clause 12) shall have an // exception-specification. [...] // It is unspecified whether or not an implicit copy assignment operator @@ -7536,8 +7529,6 @@ Sema::ComputeDefaultedCopyAssignmentExceptionSpecAndConst( // Based on a similar decision made for constness in C++0x, we're erring on // the side of assuming such calls to be made regardless of whether they // actually happen. - ImplicitExceptionSpecification ExceptSpec(*this); - unsigned ArgQuals = HasConstCopyAssignment ? Qualifiers::Const : 0; for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(), BaseEnd = ClassDecl->bases_end(); Base != BaseEnd; ++Base) { @@ -7575,7 +7566,7 @@ Sema::ComputeDefaultedCopyAssignmentExceptionSpecAndConst( } } - return std::make_pair(ExceptSpec, HasConstCopyAssignment); + return ExceptSpec; } CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) { @@ -7584,26 +7575,19 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) { // for determining the argument type of the operator. Note also that // operators taking an object instead of a reference are allowed. - ImplicitExceptionSpecification Spec(*this); - bool Const; - llvm::tie(Spec, Const) = - ComputeDefaultedCopyAssignmentExceptionSpecAndConst(ClassDecl); - QualType ArgType = Context.getTypeDeclType(ClassDecl); QualType RetType = Context.getLValueReferenceType(ArgType); - if (Const) + if (isImplicitCopyAssignmentArgConst(*this, ClassDecl)) ArgType = ArgType.withConst(); ArgType = Context.getLValueReferenceType(ArgType); // An implicitly-declared copy assignment operator is an inline public // member of its class. - FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI(); DeclarationName Name = Context.DeclarationNames.getCXXOperatorName(OO_Equal); SourceLocation ClassLoc = ClassDecl->getLocation(); DeclarationNameInfo NameInfo(Name, ClassLoc); CXXMethodDecl *CopyAssignment - = CXXMethodDecl::Create(Context, ClassDecl, ClassLoc, NameInfo, - Context.getFunctionType(RetType, &ArgType, 1, EPI), + = CXXMethodDecl::Create(Context, ClassDecl, ClassLoc, NameInfo, QualType(), /*TInfo=*/0, /*isStatic=*/false, /*StorageClassAsWritten=*/SC_None, /*isInline=*/true, /*isConstexpr=*/false, @@ -7612,7 +7596,13 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) { CopyAssignment->setDefaulted(); CopyAssignment->setImplicit(); CopyAssignment->setTrivial(ClassDecl->hasTrivialCopyAssignment()); - + + // Build an exception specification pointing back at this member. + FunctionProtoType::ExtProtoInfo EPI; + EPI.ExceptionSpecType = EST_Unevaluated; + EPI.ExceptionSpecDecl = CopyAssignment; + CopyAssignment->setType(Context.getFunctionType(RetType, &ArgType, 1, EPI)); + // Add the parameter to the operator. ParmVarDecl *FromParam = ParmVarDecl::Create(Context, CopyAssignment, ClassLoc, ClassLoc, /*Id=*/0, @@ -7950,9 +7940,10 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, } Sema::ImplicitExceptionSpecification -Sema::ComputeDefaultedMoveAssignmentExceptionSpec(CXXRecordDecl *ClassDecl) { - ImplicitExceptionSpecification ExceptSpec(*this); +Sema::ComputeDefaultedMoveAssignmentExceptionSpec(CXXMethodDecl *MD) { + CXXRecordDecl *ClassDecl = MD->getParent(); + ImplicitExceptionSpecification ExceptSpec(*this); if (ClassDecl->isInvalidDecl()) return ExceptSpec; @@ -8120,22 +8111,17 @@ CXXMethodDecl *Sema::DeclareImplicitMoveAssignment(CXXRecordDecl *ClassDecl) { // Note: The following rules are largely analoguous to the move // constructor rules. - ImplicitExceptionSpecification Spec( - ComputeDefaultedMoveAssignmentExceptionSpec(ClassDecl)); - QualType ArgType = Context.getTypeDeclType(ClassDecl); QualType RetType = Context.getLValueReferenceType(ArgType); ArgType = Context.getRValueReferenceType(ArgType); // An implicitly-declared move assignment operator is an inline public // member of its class. - FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI(); DeclarationName Name = Context.DeclarationNames.getCXXOperatorName(OO_Equal); SourceLocation ClassLoc = ClassDecl->getLocation(); DeclarationNameInfo NameInfo(Name, ClassLoc); CXXMethodDecl *MoveAssignment - = CXXMethodDecl::Create(Context, ClassDecl, ClassLoc, NameInfo, - Context.getFunctionType(RetType, &ArgType, 1, EPI), + = CXXMethodDecl::Create(Context, ClassDecl, ClassLoc, NameInfo, QualType(), /*TInfo=*/0, /*isStatic=*/false, /*StorageClassAsWritten=*/SC_None, /*isInline=*/true, @@ -8146,6 +8132,12 @@ CXXMethodDecl *Sema::DeclareImplicitMoveAssignment(CXXRecordDecl *ClassDecl) { MoveAssignment->setImplicit(); MoveAssignment->setTrivial(ClassDecl->hasTrivialMoveAssignment()); + // Build an exception specification pointing back at this member. + FunctionProtoType::ExtProtoInfo EPI; + EPI.ExceptionSpecType = EST_Unevaluated; + EPI.ExceptionSpecDecl = MoveAssignment; + MoveAssignment->setType(Context.getFunctionType(RetType, &ArgType, 1, EPI)); + // Add the parameter to the operator. ParmVarDecl *FromParam = ParmVarDecl::Create(Context, MoveAssignment, ClassLoc, ClassLoc, /*Id=*/0, @@ -8496,10 +8488,12 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation, } } -std::pair<Sema::ImplicitExceptionSpecification, bool> -Sema::ComputeDefaultedCopyCtorExceptionSpecAndConst(CXXRecordDecl *ClassDecl) { +/// Determine whether an implicit copy constructor for ClassDecl has a const +/// argument. +/// FIXME: It ought to be possible to store this on the record. +static bool isImplicitCopyCtorArgConst(Sema &S, CXXRecordDecl *ClassDecl) { if (ClassDecl->isInvalidDecl()) - return std::make_pair(ImplicitExceptionSpecification(*this), true); + return true; // C++ [class.copy]p5: // The implicitly-declared copy constructor for a class X will @@ -8508,60 +8502,71 @@ Sema::ComputeDefaultedCopyCtorExceptionSpecAndConst(CXXRecordDecl *ClassDecl) { // X::X(const X&) // // if - // FIXME: It ought to be possible to store this on the record. - bool HasConstCopyConstructor = true; - // -- each direct or virtual base class B of X has a copy // constructor whose first parameter is of type const B& or // const volatile B&, and for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(), BaseEnd = ClassDecl->bases_end(); - HasConstCopyConstructor && Base != BaseEnd; - ++Base) { + Base != BaseEnd; ++Base) { // Virtual bases are handled below. if (Base->isVirtual()) continue; - + CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); - HasConstCopyConstructor &= - (bool)LookupCopyingConstructor(BaseClassDecl, Qualifiers::Const); + // FIXME: This lookup is wrong. If the copy ctor for a member or base is + // ambiguous, we should still produce a constructor with a const-qualified + // parameter. + if (!S.LookupCopyingConstructor(BaseClassDecl, Qualifiers::Const)) + return false; } for (CXXRecordDecl::base_class_iterator Base = ClassDecl->vbases_begin(), BaseEnd = ClassDecl->vbases_end(); - HasConstCopyConstructor && Base != BaseEnd; - ++Base) { + Base != BaseEnd; ++Base) { CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); - HasConstCopyConstructor &= - (bool)LookupCopyingConstructor(BaseClassDecl, Qualifiers::Const); + if (!S.LookupCopyingConstructor(BaseClassDecl, Qualifiers::Const)) + return false; } - + // -- for all the nonstatic data members of X that are of a // class type M (or array thereof), each such class type // has a copy constructor whose first parameter is of type // const M& or const volatile M&. for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), FieldEnd = ClassDecl->field_end(); - HasConstCopyConstructor && Field != FieldEnd; - ++Field) { - QualType FieldType = Context.getBaseElementType(Field->getType()); + Field != FieldEnd; ++Field) { + QualType FieldType = S.Context.getBaseElementType(Field->getType()); if (CXXRecordDecl *FieldClassDecl = FieldType->getAsCXXRecordDecl()) { - HasConstCopyConstructor &= - (bool)LookupCopyingConstructor(FieldClassDecl, Qualifiers::Const); + if (!S.LookupCopyingConstructor(FieldClassDecl, Qualifiers::Const)) + return false; } } + // Otherwise, the implicitly declared copy constructor will have // the form // // X::X(X&) - + + return true; +} + +Sema::ImplicitExceptionSpecification +Sema::ComputeDefaultedCopyCtorExceptionSpec(CXXMethodDecl *MD) { + CXXRecordDecl *ClassDecl = MD->getParent(); + + ImplicitExceptionSpecification ExceptSpec(*this); + if (ClassDecl->isInvalidDecl()) + return ExceptSpec; + + const FunctionProtoType *T = MD->getType()->castAs<FunctionProtoType>(); + assert(T->getNumArgs() >= 1 && "not a copy ctor"); + unsigned Quals = T->getArgType(0).getNonReferenceType().getCVRQualifiers(); + // C++ [except.spec]p14: // An implicitly declared special member function (Clause 12) shall have an // exception-specification. [...] - ImplicitExceptionSpecification ExceptSpec(*this); - unsigned Quals = HasConstCopyConstructor? Qualifiers::Const : 0; for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(), BaseEnd = ClassDecl->bases_end(); Base != BaseEnd; @@ -8599,7 +8604,7 @@ Sema::ComputeDefaultedCopyCtorExceptionSpecAndConst(CXXRecordDecl *ClassDecl) { } } - return std::make_pair(ExceptSpec, HasConstCopyConstructor); + return ExceptSpec; } CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor( @@ -8608,18 +8613,12 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor( // If the class definition does not explicitly declare a copy // constructor, one is declared implicitly. - ImplicitExceptionSpecification Spec(*this); - bool Const; - llvm::tie(Spec, Const) = - ComputeDefaultedCopyCtorExceptionSpecAndConst(ClassDecl); - QualType ClassType = Context.getTypeDeclType(ClassDecl); QualType ArgType = ClassType; + bool Const = isImplicitCopyCtorArgConst(*this, ClassDecl); if (Const) ArgType = ArgType.withConst(); ArgType = Context.getLValueReferenceType(ArgType); - - FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI(); bool Constexpr = defaultedSpecialMemberIsConstexpr(*this, ClassDecl, CXXCopyConstructor, @@ -8634,14 +8633,20 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor( // 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, + Context, ClassDecl, ClassLoc, NameInfo, QualType(), /*TInfo=*/0, /*isExplicit=*/false, /*isInline=*/true, /*isImplicitlyDeclared=*/true, Constexpr); CopyConstructor->setAccess(AS_public); CopyConstructor->setDefaulted(); CopyConstructor->setTrivial(ClassDecl->hasTrivialCopyConstructor()); + // Build an exception specification pointing back at this member. + FunctionProtoType::ExtProtoInfo EPI; + EPI.ExceptionSpecType = EST_Unevaluated; + EPI.ExceptionSpecDecl = CopyConstructor; + CopyConstructor->setType( + Context.getFunctionType(Context.VoidTy, &ArgType, 1, EPI)); + // Note that we have declared this constructor. ++ASTContext::NumImplicitCopyConstructorsDeclared; @@ -8705,7 +8710,9 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation, } Sema::ImplicitExceptionSpecification -Sema::ComputeDefaultedMoveCtorExceptionSpec(CXXRecordDecl *ClassDecl) { +Sema::ComputeDefaultedMoveCtorExceptionSpec(CXXMethodDecl *MD) { + CXXRecordDecl *ClassDecl = MD->getParent(); + // C++ [except.spec]p14: // An implicitly declared special member function (Clause 12) shall have an // exception-specification. [...] @@ -8788,13 +8795,8 @@ CXXConstructorDecl *Sema::DeclareImplicitMoveConstructor( return 0; } - ImplicitExceptionSpecification Spec( - ComputeDefaultedMoveCtorExceptionSpec(ClassDecl)); - QualType ClassType = Context.getTypeDeclType(ClassDecl); QualType ArgType = Context.getRValueReferenceType(ClassType); - - FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI(); bool Constexpr = defaultedSpecialMemberIsConstexpr(*this, ClassDecl, CXXMoveConstructor, @@ -8810,14 +8812,20 @@ CXXConstructorDecl *Sema::DeclareImplicitMoveConstructor( // 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, + Context, ClassDecl, ClassLoc, NameInfo, QualType(), /*TInfo=*/0, /*isExplicit=*/false, /*isInline=*/true, /*isImplicitlyDeclared=*/true, Constexpr); MoveConstructor->setAccess(AS_public); MoveConstructor->setDefaulted(); MoveConstructor->setTrivial(ClassDecl->hasTrivialMoveConstructor()); + // Build an exception specification pointing back at this member. + FunctionProtoType::ExtProtoInfo EPI; + EPI.ExceptionSpecType = EST_Unevaluated; + EPI.ExceptionSpecDecl = MoveConstructor; + MoveConstructor->setType( + Context.getFunctionType(Context.VoidTy, &ArgType, 1, EPI)); + // Add the parameter to the constructor. ParmVarDecl *FromParam = ParmVarDecl::Create(Context, MoveConstructor, ClassLoc, ClassLoc, @@ -10427,10 +10435,11 @@ void Sema::SetDeclDefaulted(Decl *Dcl, SourceLocation DefaultLoc) { if (Primary == Primary->getCanonicalDecl()) return; + CheckExplicitlyDefaultedSpecialMember(MD); + switch (Member) { case CXXDefaultConstructor: { CXXConstructorDecl *CD = cast<CXXConstructorDecl>(MD); - CheckExplicitlyDefaultedSpecialMember(CD); if (!CD->isInvalidDecl()) DefineImplicitDefaultConstructor(DefaultLoc, CD); break; @@ -10438,14 +10447,12 @@ void Sema::SetDeclDefaulted(Decl *Dcl, SourceLocation DefaultLoc) { case CXXCopyConstructor: { CXXConstructorDecl *CD = cast<CXXConstructorDecl>(MD); - CheckExplicitlyDefaultedSpecialMember(CD); if (!CD->isInvalidDecl()) DefineImplicitCopyConstructor(DefaultLoc, CD); break; } case CXXCopyAssignment: { - CheckExplicitlyDefaultedSpecialMember(MD); if (!MD->isInvalidDecl()) DefineImplicitCopyAssignment(DefaultLoc, MD); break; @@ -10453,7 +10460,6 @@ void Sema::SetDeclDefaulted(Decl *Dcl, SourceLocation DefaultLoc) { case CXXDestructor: { CXXDestructorDecl *DD = cast<CXXDestructorDecl>(MD); - CheckExplicitlyDefaultedSpecialMember(DD); if (!DD->isInvalidDecl()) DefineImplicitDestructor(DefaultLoc, DD); break; @@ -10461,14 +10467,12 @@ void Sema::SetDeclDefaulted(Decl *Dcl, SourceLocation DefaultLoc) { case CXXMoveConstructor: { CXXConstructorDecl *CD = cast<CXXConstructorDecl>(MD); - CheckExplicitlyDefaultedSpecialMember(CD); if (!CD->isInvalidDecl()) DefineImplicitMoveConstructor(DefaultLoc, CD); break; } case CXXMoveAssignment: { - CheckExplicitlyDefaultedSpecialMember(MD); if (!MD->isInvalidDecl()) DefineImplicitMoveAssignment(DefaultLoc, MD); break; @@ -10753,7 +10757,7 @@ bool Sema::DefineUsedVTables() { // Note: The VTableUses vector could grow as a result of marking // the members of a class as "used", so we check the size each - // time through the loop and prefer indices (with are stable) to + // time through the loop and prefer indices (which are stable) to // iterators (which are not). bool DefinedAnything = false; for (unsigned I = 0; I != VTableUses.size(); ++I) { @@ -10763,6 +10767,8 @@ bool Sema::DefineUsedVTables() { SourceLocation Loc = VTableUses[I].second; + bool DefineVTable = true; + // If this class has a key function, but that key function is // defined in another translation unit, we don't need to emit the // vtable even though we're using it. @@ -10773,7 +10779,8 @@ bool Sema::DefineUsedVTables() { case TSK_ExplicitSpecialization: case TSK_ExplicitInstantiationDeclaration: // The key function is in another translation unit. - continue; + DefineVTable = false; + break; case TSK_ExplicitInstantiationDefinition: case TSK_ImplicitInstantiation: @@ -10802,7 +10809,15 @@ bool Sema::DefineUsedVTables() { } if (IsExplicitInstantiationDeclaration) - continue; + DefineVTable = false; + } + + // The exception specifications for all virtual members may be needed even + // if we are not providing an authoritative form of the vtable in this TU. + // We may choose to emit it available_externally anyway. + if (!DefineVTable) { + MarkVirtualMemberExceptionSpecsNeeded(Loc, Class); + continue; } // Mark all of the virtual members of this class as referenced, so @@ -10831,6 +10846,14 @@ bool Sema::DefineUsedVTables() { return DefinedAnything; } +void Sema::MarkVirtualMemberExceptionSpecsNeeded(SourceLocation Loc, + const CXXRecordDecl *RD) { + for (CXXRecordDecl::method_iterator I = RD->method_begin(), + E = RD->method_end(); I != E; ++I) + if ((*I)->isVirtual() && !(*I)->isPure()) + ResolveExceptionSpec(Loc, (*I)->getType()->castAs<FunctionProtoType>()); +} + void Sema::MarkVirtualMembersReferenced(SourceLocation Loc, const CXXRecordDecl *RD) { // Mark all functions which will appear in RD's vtable as used. @@ -11067,8 +11090,8 @@ bool Sema::checkThisInStaticMemberFunctionExceptionSpec(CXXMethodDecl *Method) { switch (Proto->getExceptionSpecType()) { case EST_Uninstantiated: + case EST_Unevaluated: case EST_BasicNoexcept: - case EST_Delayed: case EST_DynamicNone: case EST_MSAny: case EST_None: diff --git a/lib/Sema/SemaExceptionSpec.cpp b/lib/Sema/SemaExceptionSpec.cpp index f88ead56f4..63bfa9dc2d 100644 --- a/lib/Sema/SemaExceptionSpec.cpp +++ b/lib/Sema/SemaExceptionSpec.cpp @@ -100,20 +100,22 @@ bool Sema::CheckDistantExceptionSpec(QualType T) { const FunctionProtoType * Sema::ResolveExceptionSpec(SourceLocation Loc, const FunctionProtoType *FPT) { - // FIXME: If FD is a special member, we should delay computing its exception - // specification until this point. - if (FPT->getExceptionSpecType() != EST_Uninstantiated) + if (!isUnresolvedExceptionSpec(FPT->getExceptionSpecType())) return FPT; FunctionDecl *SourceDecl = FPT->getExceptionSpecDecl(); const FunctionProtoType *SourceFPT = SourceDecl->getType()->castAs<FunctionProtoType>(); - if (SourceFPT->getExceptionSpecType() != EST_Uninstantiated) + // If the exception specification has already been resolved, just return it. + if (!isUnresolvedExceptionSpec(SourceFPT->getExceptionSpecType())) return SourceFPT; - // Instantiate the exception specification now. - InstantiateExceptionSpec(Loc, SourceDecl); + // Compute or instantiate the exception specification now. + if (FPT->getExceptionSpecType() == EST_Unevaluated) + EvaluateImplicitExceptionSpec(Loc, cast<CXXMethodDecl>(SourceDecl)); + else + InstantiateExceptionSpec(Loc, SourceDecl); return SourceDecl->getType()->castAs<FunctionProtoType>(); } @@ -346,8 +348,8 @@ bool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID, ExceptionSpecificationType OldEST = Old->getExceptionSpecType(); ExceptionSpecificationType NewEST = New->getExceptionSpecType(); - assert(OldEST != EST_Delayed && NewEST != EST_Delayed && - OldEST != EST_Uninstantiated && NewEST != EST_Uninstantiated && + assert(!isUnresolvedExceptionSpec(OldEST) && + !isUnresolvedExceptionSpec(NewEST) && "Shouldn't see unknown exception specifications here"); // Shortcut the case where both have no spec. @@ -544,8 +546,8 @@ bool Sema::CheckExceptionSpecSubset( ExceptionSpecificationType SubEST = Subset->getExceptionSpecType(); - assert(SuperEST != EST_Delayed && SubEST != EST_Delayed && - SuperEST != EST_Uninstantiated && SubEST != EST_Uninstantiated && + assert(!isUnresolvedExceptionSpec(SuperEST) && + !isUnresolvedExceptionSpec(SubEST) && "Shouldn't see unknown exception specifications here"); // It does not. If the subset contains everything, we've failed. @@ -808,15 +810,6 @@ static CanThrowResult canCalleeThrow(Sema &S, const Expr *E, if (!FT) return CT_Can; - if (FT->getExceptionSpecType() == EST_Delayed) { - // FIXME: Try to resolve a delayed exception spec in ResolveExceptionSpec. - assert(isa<CXXConstructorDecl>(D) && - "only constructor exception specs can be unknown"); - S.Diag(E->getLocStart(), diag::err_exception_spec_unknown) - << E->getSourceRange(); - return CT_Can; - } - return FT->isNothrow(S.Context) ? CT_Cannot : CT_Can; } diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 9b5f003dae..19259b30ec 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -10224,11 +10224,11 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func) { // FIXME: Is this really right? if (CurContext == Func) return; - // Instantiate the exception specification for any function which is + // Resolve the exception specification for any function which is // used: CodeGen will need it. const FunctionProtoType *FPT = Func->getType()->getAs<FunctionProtoType>(); - if (FPT && FPT->getExceptionSpecType() == EST_Uninstantiated) - InstantiateExceptionSpec(Loc, Func); + if (FPT && isUnresolvedExceptionSpec(FPT->getExceptionSpecType())) + ResolveExceptionSpec(Loc, FPT); // Implicit instantiation of function templates and member functions of // class templates. diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index ec4bf8221f..278549b4b7 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -3190,8 +3190,6 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT, CPT = Self.ResolveExceptionSpec(KeyLoc, CPT); if (!CPT) return false; - if (CPT->getExceptionSpecType() == EST_Delayed) - return false; if (!CPT->isNothrow(Self.Context)) return false; } @@ -3232,8 +3230,6 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT, CPT = Self.ResolveExceptionSpec(KeyLoc, CPT); if (!CPT) return false; - if (CPT->getExceptionSpecType() == EST_Delayed) - return false; // FIXME: check whether evaluating default arguments can throw. // For now, we'll be conservative and assume that they can throw. if (!CPT->isNothrow(Self.Context) || CPT->getNumArgs() > 1) @@ -3270,8 +3266,6 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT, CPT = Self.ResolveExceptionSpec(KeyLoc, CPT); if (!CPT) return false; - if (CPT->getExceptionSpecType() == EST_Delayed) - return false; // TODO: check whether evaluating default arguments can throw. // For now, we'll be conservative and assume that they can throw. return CPT->isNothrow(Self.Context) && CPT->getNumArgs() == 0; diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index 082b2e847f..102ec993ef 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -1996,8 +1996,7 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, Instantiator.disableLateAttributeInstantiation(); LateAttrs.clear(); - if (!FieldsWithMemberInitializers.empty()) - ActOnFinishDelayedMemberInitializers(Instantiation); + ActOnFinishDelayedMemberInitializers(Instantiation); if (TSK == TSK_ImplicitInstantiation) { Instantiation->setLocation(Pattern->getLocation()); diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index aeda975565..15ddd7df98 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -2395,8 +2395,17 @@ void Sema::InstantiateExceptionSpec(SourceLocation PointOfInstantiation, InstantiatingTemplate Inst(*this, PointOfInstantiation, Decl, InstantiatingTemplate::ExceptionSpecification()); - if (Inst) + if (Inst) { + // We hit the instantiation depth limit. Clear the exception specification + // so that our callers don't have to cope with EST_Uninstantiated. + FunctionProtoType::ExtProtoInfo EPI = Proto->getExtProtoInfo(); + EPI.ExceptionSpecType = EST_None; + Decl->setType(Context.getFunctionType(Proto->getResultType(), + Proto->arg_type_begin(), + Proto->getNumArgs(), + EPI)); return; + } // Enter the scope of this instantiation. We don't use // PushDeclContext because we don't have a scope. @@ -2461,6 +2470,8 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New, FunctionDecl *ExceptionSpecTemplate = Tmpl; if (EPI.ExceptionSpecType == EST_Uninstantiated) ExceptionSpecTemplate = EPI.ExceptionSpecTemplate; + assert(EPI.ExceptionSpecType != EST_Unevaluated && + "instantiating implicitly-declared special member"); // Mark the function has having an uninstantiated exception specification. const FunctionProtoType *NewProto @@ -3431,7 +3442,7 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D, void Sema::PerformPendingInstantiations(bool LocalOnly) { // Load pending instantiations from the external source. if (!LocalOnly && ExternalSource) { - SmallVector<std::pair<ValueDecl *, SourceLocation>, 4> Pending; + SmallVector<PendingImplicitInstantiation, 4> Pending; ExternalSource->ReadPendingInstantiations(Pending); PendingInstantiations.insert(PendingInstantiations.begin(), Pending.begin(), Pending.end()); diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp index 4073e32c2c..beef338174 100644 --- a/lib/Serialization/ASTReader.cpp +++ b/lib/Serialization/ASTReader.cpp @@ -3906,6 +3906,8 @@ QualType ASTReader::readTypeRecord(unsigned Index) { } else if (EST == EST_Uninstantiated) { EPI.ExceptionSpecDecl = ReadDeclAs<FunctionDecl>(*Loc.F, Record, Idx); EPI.ExceptionSpecTemplate = ReadDeclAs<FunctionDecl>(*Loc.F, Record, Idx); + } else if (EST == EST_Unevaluated) { + EPI.ExceptionSpecDecl = ReadDeclAs<FunctionDecl>(*Loc.F, Record, Idx); } return Context.getFunctionType(ResultType, ParamTypes.data(), NumParams, EPI); diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp index 6a6863f17b..b7718c4655 100644 --- a/lib/Serialization/ASTWriter.cpp +++ b/lib/Serialization/ASTWriter.cpp @@ -198,6 +198,8 @@ void ASTTypeWriter::VisitFunctionProtoType(const FunctionProtoType *T) { } else if (T->getExceptionSpecType() == EST_Uninstantiated) { Writer.AddDeclRef(T->getExceptionSpecDecl(), Record); Writer.AddDeclRef(T->getExceptionSpecTemplate(), Record); + } else if (T->getExceptionSpecType() == EST_Unevaluated) { + Writer.AddDeclRef(T->getExceptionSpecDecl(), Record); } Code = TYPE_FUNCTION_PROTO; } diff --git a/test/CXX/dcl.decl/dcl.meaning/dcl.fct/dcl.fct.def.default/p1.cpp b/test/CXX/dcl.decl/dcl.meaning/dcl.fct/dcl.fct.def.default/p1.cpp index 15efb48477..21f71f0541 100644 --- a/test/CXX/dcl.decl/dcl.meaning/dcl.fct/dcl.fct.def.default/p1.cpp +++ b/test/CXX/dcl.decl/dcl.meaning/dcl.fct/dcl.fct.def.default/p1.cpp @@ -4,9 +4,11 @@ // [...] // -- not have default arguments struct DefArg { + static DefArg &&make(); DefArg(int n = 5) = default; // expected-error {{an explicitly-defaulted constructor cannot have default arguments}} - DefArg(const DefArg &DA = DefArg(2)) = default; // expected-error {{an explicitly-defaulted constructor cannot have default arguments}} + DefArg(const DefArg &DA = make()) = default; // expected-error {{an explicitly-defaulted constructor cannot have default arguments}} DefArg(const DefArg &DA, int k = 3) = default; // expected-error {{an explicitly-defaulted copy constructor cannot have default arguments}} + DefArg(DefArg &&DA = make()) = default; // expected-error {{an explicitly-defaulted constructor cannot have default arguments}} DefArg(DefArg &&DA, int k = 3) = default; // expected-error {{an explicitly-defaulted move constructor cannot have default arguments}} DefArg &operator=(const DefArg&, int k = 4) = default; // expected-error {{parameter of overloaded 'operator=' cannot have a default argument}} DefArg &operator=(DefArg&&, int k = 4) = default; // expected-error {{parameter of overloaded 'operator=' cannot have a default argument}} diff --git a/test/CodeGenCXX/member-init-ctor.cpp b/test/CodeGenCXX/member-init-ctor.cpp deleted file mode 100644 index 2172394257..0000000000 --- a/test/CodeGenCXX/member-init-ctor.cpp +++ /dev/null @@ -1,14 +0,0 @@ -// RUN: %clang_cc1 %s -std=c++11 -emit-llvm -o - | FileCheck %s - -bool b(); -struct S { - int n = b() ? S().n + 1 : 0; -}; - -S s; - -// CHECK: define {{.*}} @_ZN1SC2Ev( -// CHECK-NOT } -// CHECK: call {{.*}} @_Z1bv() -// CHECK-NOT } -// CHECK: call {{.*}} @_ZN1SC1Ev( diff --git a/test/SemaCXX/cxx0x-defaulted-functions.cpp b/test/SemaCXX/cxx0x-defaulted-functions.cpp index 595d428806..61c4c3338c 100644 --- a/test/SemaCXX/cxx0x-defaulted-functions.cpp +++ b/test/SemaCXX/cxx0x-defaulted-functions.cpp @@ -57,3 +57,63 @@ struct Friends { friend S<bar>::S(const S&); friend S<bar>::S(S&&); }; + +namespace DefaultedFnExceptionSpec { + // DR1330: The exception-specification of an implicitly-declared special + // member function is evaluated as needed. + template<typename T> T &&declval(); + template<typename T> struct pair { + pair(const pair&) noexcept(noexcept(T(declval<T>()))); + }; + + struct Y; + struct X { X(); X(const Y&); }; + struct Y { pair<X> p; }; + + template<typename T> + struct A { + pair<T> p; + }; + struct B { + B(); + B(const A<B>&); + }; + + // Don't crash here. + void f() { + X x = X(); + (void)noexcept(B(declval<B>())); + } + + template<typename T> + struct Error { + // FIXME: Type canonicalization causes all the errors to point at the first + // declaration which has the type 'void () noexcept (T::error)'. We should + // get one error for 'Error<int>::Error()' and one for 'Error<int>::~Error()'. + void f() noexcept(T::error); // expected-error 2{{has no members}} + + Error() noexcept(T::error); + Error(const Error&) noexcept(T::error); + Error(Error&&) noexcept(T::error); + Error &operator=(const Error&) noexcept(T::error); + Error &operator=(Error&&) noexcept(T::error); + ~Error() noexcept(T::error); + }; + + struct DelayImplicit { + Error<int> e; + }; + + // Don't instantiate the exception specification here. + void test1(decltype(declval<DelayImplicit>() = DelayImplicit(DelayImplicit()))); + void test2(decltype(declval<DelayImplicit>() = declval<const DelayImplicit>())); + void test3(decltype(DelayImplicit(declval<const DelayImplicit>()))); + + // Any odr-use causes the exception specification to be evaluated. + struct OdrUse { // \ + expected-note {{instantiation of exception specification for 'Error'}} \ + expected-note {{instantiation of exception specification for '~Error'}} + Error<int> e; + }; + OdrUse use; // expected-note {{implicit default constructor for 'DefaultedFnExceptionSpec::OdrUse' first required here}} +} diff --git a/test/SemaCXX/implicit-exception-spec.cpp b/test/SemaCXX/implicit-exception-spec.cpp index 25316f8d51..b29cff5c5d 100644 --- a/test/SemaCXX/implicit-exception-spec.cpp +++ b/test/SemaCXX/implicit-exception-spec.cpp @@ -17,7 +17,7 @@ namespace InClassInitializers { // is false. bool ThrowSomething() noexcept(false); struct ConstExpr { - bool b = noexcept(ConstExpr()) && ThrowSomething(); // expected-error {{exception specification is not available until end of class definition}} + bool b = noexcept(ConstExpr()) && ThrowSomething(); // expected-error {{cannot be used by non-static data member initializer}} }; // We can use it now. bool w = noexcept(ConstExpr()); @@ -25,18 +25,27 @@ namespace InClassInitializers { // Much more obviously broken: we can't parse the initializer without already // knowing whether it produces a noexcept expression. struct TemplateArg { - int n = ExceptionIf<noexcept(TemplateArg())>::f(); // expected-error {{exception specification is not available until end of class definition}} + int n = ExceptionIf<noexcept(TemplateArg())>::f(); // expected-error {{cannot be used by non-static data member initializer}} }; bool x = noexcept(TemplateArg()); // And within a nested class. + // FIXME: The diagnostic location is terrible here. struct Nested { struct Inner { - int n = ExceptionIf<noexcept(Nested())>::f(); // expected-error {{exception specification is not available until end of class definition}} - } inner; + int n = ExceptionIf<noexcept(Nested())>::f(); + } inner; // expected-error {{cannot be used by non-static data member initializer}} }; bool y = noexcept(Nested()); bool z = noexcept(Nested::Inner()); + + struct Nested2 { + struct Inner; + int n = Inner().n; // expected-error {{cannot be used by non-static data member initializer}} + struct Inner { + int n = ExceptionIf<noexcept(Nested())>::f(); + } inner; + }; } namespace ExceptionSpecification { diff --git a/test/SemaCXX/member-init.cpp b/test/SemaCXX/member-init.cpp index 3ca41a0563..a13941fce5 100644 --- a/test/SemaCXX/member-init.cpp +++ b/test/SemaCXX/member-init.cpp @@ -14,7 +14,7 @@ public: bool b(); int k; struct Recurse { - int &n = b() ? Recurse().n : k; // ok + int &n = b() ? Recurse().n : k; // expected-error {{defaulted default constructor of 'Recurse' cannot be used by non-static data member initializer which appears before end of class definition}} }; struct UnknownBound { diff --git a/test/SemaCXX/type-traits.cpp b/test/SemaCXX/type-traits.cpp index 63286e6e13..bf590f9c72 100644 --- a/test/SemaCXX/type-traits.cpp +++ b/test/SemaCXX/type-traits.cpp @@ -1384,9 +1384,6 @@ void has_nothrow_copy() { { int arr[F(__has_nothrow_copy(cvoid))]; } } -template<bool b> struct assert_expr; -template<> struct assert_expr<true> {}; - void has_nothrow_constructor() { { int arr[T(__has_nothrow_constructor(Int))]; } { int arr[T(__has_nothrow_constructor(IntAr))]; } @@ -1415,11 +1412,6 @@ void has_nothrow_constructor() { { int arr[F(__has_nothrow_constructor(void))]; } { int arr[F(__has_nothrow_constructor(cvoid))]; } { int arr[F(__has_nothrow_constructor(HasTemplateCons))]; } - - // While parsing an in-class initializer, the constructor is not known to be - // non-throwing yet. - struct HasInClassInit { int n = (assert_expr<!__has_nothrow_constructor(HasInClassInit)>(), 0); }; - { int arr[T(__has_nothrow_constructor(HasInClassInit))]; } } void has_virtual_destructor() { diff --git a/test/SemaTemplate/instantiation-depth.cpp b/test/SemaTemplate/instantiation-depth.cpp index 8e1b80368d..c0b8bb2a12 100644 --- a/test/SemaTemplate/instantiation-depth.cpp +++ b/test/SemaTemplate/instantiation-depth.cpp @@ -2,12 +2,30 @@ // RUN: %clang -fsyntax-only -Xclang -verify -ftemplate-depth-5 -ftemplate-backtrace-limit=4 %s // RUN: %clang -fsyntax-only -Xclang -verify -ftemplate-depth=5 -ftemplate-backtrace-limit=4 %s +#ifndef NOEXCEPT + template<typename T> struct X : X<T*> { }; \ // expected-error{{recursive template instantiation exceeded maximum depth of 5}} \ // expected-note 3 {{instantiation of template class}} \ // expected-note {{skipping 2 contexts in backtrace}} \ // expected-note {{use -ftemplate-depth=N to increase recursive template instantiation depth}} -void test() { +void test() { (void)sizeof(X<int>); // expected-note {{instantiation of template class}} } + +#else + +// RUN: %clang_cc1 -fsyntax-only -verify -ftemplate-depth 5 -ftemplate-backtrace-limit 4 -std=c++11 -DNOEXCEPT %s + +template<typename T> struct S { + S() noexcept(noexcept(T())); +}; +struct T : S<T> {}; \ +// expected-error{{recursive template instantiation exceeded maximum depth of 5}} \ +// expected-note 4 {{in instantiation of exception spec}} \ +// expected-note {{skipping 2 contexts in backtrace}} \ +// expected-note {{use -ftemplate-depth=N to increase recursive template instantiation depth}} +T t; // expected-note {{implicit default constructor for 'T' first required here}} + +#endif |