aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/AST/Type.h14
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td5
-rw-r--r--include/clang/Basic/ExceptionSpecificationType.h6
-rw-r--r--include/clang/Sema/DeclSpec.h3
-rw-r--r--include/clang/Sema/Sema.h40
-rw-r--r--lib/AST/ASTContext.cpp9
-rw-r--r--lib/AST/Type.cpp8
-rw-r--r--lib/Analysis/CFG.cpp2
-rw-r--r--lib/Sema/SemaDecl.cpp8
-rw-r--r--lib/Sema/SemaDeclCXX.cpp479
-rw-r--r--lib/Sema/SemaExceptionSpec.cpp31
-rw-r--r--lib/Sema/SemaExpr.cpp6
-rw-r--r--lib/Sema/SemaExprCXX.cpp6
-rw-r--r--lib/Sema/SemaTemplateInstantiate.cpp3
-rw-r--r--lib/Sema/SemaTemplateInstantiateDecl.cpp15
-rw-r--r--lib/Serialization/ASTReader.cpp2
-rw-r--r--lib/Serialization/ASTWriter.cpp2
-rw-r--r--test/CXX/dcl.decl/dcl.meaning/dcl.fct/dcl.fct.def.default/p1.cpp4
-rw-r--r--test/CodeGenCXX/member-init-ctor.cpp14
-rw-r--r--test/SemaCXX/cxx0x-defaulted-functions.cpp60
-rw-r--r--test/SemaCXX/implicit-exception-spec.cpp17
-rw-r--r--test/SemaCXX/member-init.cpp2
-rw-r--r--test/SemaCXX/type-traits.cpp8
-rw-r--r--test/SemaTemplate/instantiation-depth.cpp20
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 possi