summaryrefslogtreecommitdiffstats
path: root/contrib/llvm/tools/clang/lib/Sema/SemaDeclCXX.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Sema/SemaDeclCXX.cpp')
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaDeclCXX.cpp1717
1 files changed, 822 insertions, 895 deletions
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaDeclCXX.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaDeclCXX.cpp
index 66a1121..eeac9b8 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/contrib/llvm/tools/clang/lib/Sema/SemaDeclCXX.cpp
@@ -23,6 +23,7 @@
#include "clang/AST/CharUnits.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/DeclVisitor.h"
+#include "clang/AST/EvaluatedExprVisitor.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/RecordLayout.h"
#include "clang/AST/RecursiveASTVisitor.h"
@@ -127,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
@@ -140,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;
@@ -197,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:
@@ -667,9 +668,9 @@ static bool CheckConstexprParameterTypes(Sema &SemaRef,
SourceLocation ParamLoc = PD->getLocation();
if (!(*i)->isDependentType() &&
SemaRef.RequireLiteralType(ParamLoc, *i,
- SemaRef.PDiag(diag::err_constexpr_non_literal_param)
- << ArgIndex+1 << PD->getSourceRange()
- << isa<CXXConstructorDecl>(FD)))
+ diag::err_constexpr_non_literal_param,
+ ArgIndex+1, PD->getSourceRange(),
+ isa<CXXConstructorDecl>(FD)))
return false;
}
return true;
@@ -725,7 +726,7 @@ bool Sema::CheckConstexprFunctionDecl(const FunctionDecl *NewFD) {
QualType RT = NewFD->getResultType();
if (!RT->isDependentType() &&
RequireLiteralType(NewFD->getLocation(), RT,
- PDiag(diag::err_constexpr_non_literal_return)))
+ diag::err_constexpr_non_literal_return))
return false;
}
@@ -920,7 +921,7 @@ bool Sema::CheckConstexprFunctionBody(const FunctionDecl *Dcl, Stmt *Body) {
unsigned Fields = 0;
for (CXXRecordDecl::field_iterator I = RD->field_begin(),
E = RD->field_end(); I != E; ++I, ++Fields) {
- if ((*I)->isAnonymousStructOrUnion()) {
+ if (I->isAnonymousStructOrUnion()) {
AnyAnonStructUnionMembers = true;
break;
}
@@ -1055,8 +1056,7 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class,
// The class-name in a base-specifier shall not be an incompletely
// defined class.
if (RequireCompleteType(BaseLoc, BaseType,
- PDiag(diag::err_incomplete_base_class)
- << SpecifierRange)) {
+ diag::err_incomplete_base_class, SpecifierRange)) {
Class->setInvalidDecl();
return 0;
}
@@ -1119,6 +1119,8 @@ Sema::ActOnBaseSpecifier(Decl *classdecl, SourceRange SpecifierRange,
Virtual, Access, TInfo,
EllipsisLoc))
return BaseSpec;
+ else
+ Class->setInvalidDecl();
return true;
}
@@ -1403,32 +1405,50 @@ bool Sema::ActOnAccessSpecifier(AccessSpecifier Access,
return ProcessAccessDeclAttributeList(ASDecl, Attrs);
}
-/// CheckOverrideControl - Check C++0x override control semantics.
-void Sema::CheckOverrideControl(const Decl *D) {
+/// CheckOverrideControl - Check C++11 override control semantics.
+void Sema::CheckOverrideControl(Decl *D) {
const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D);
- if (!MD || !MD->isVirtual())
+
+ // Do we know which functions this declaration might be overriding?
+ bool OverridesAreKnown = !MD ||
+ (!MD->getParent()->hasAnyDependentBases() &&
+ !MD->getType()->isDependentType());
+
+ if (!MD || !MD->isVirtual()) {
+ if (OverridesAreKnown) {
+ if (OverrideAttr *OA = D->getAttr<OverrideAttr>()) {
+ Diag(OA->getLocation(),
+ diag::override_keyword_only_allowed_on_virtual_member_functions)
+ << "override" << FixItHint::CreateRemoval(OA->getLocation());
+ D->dropAttr<OverrideAttr>();
+ }
+ if (FinalAttr *FA = D->getAttr<FinalAttr>()) {
+ Diag(FA->getLocation(),
+ diag::override_keyword_only_allowed_on_virtual_member_functions)
+ << "final" << FixItHint::CreateRemoval(FA->getLocation());
+ D->dropAttr<FinalAttr>();
+ }
+ }
return;
+ }
- if (MD->isDependentContext())
+ if (!OverridesAreKnown)
return;
- // C++0x [class.virtual]p3:
- // If a virtual function is marked with the virt-specifier override and does
- // not override a member function of a base class,
- // the program is ill-formed.
- bool HasOverriddenMethods =
+ // C++11 [class.virtual]p5:
+ // If a virtual function is marked with the virt-specifier override and
+ // does not override a member function of a base class, the program is
+ // ill-formed.
+ bool HasOverriddenMethods =
MD->begin_overridden_methods() != MD->end_overridden_methods();
- if (MD->hasAttr<OverrideAttr>() && !HasOverriddenMethods) {
- Diag(MD->getLocation(),
- diag::err_function_marked_override_not_overriding)
+ if (MD->hasAttr<OverrideAttr>() && !HasOverriddenMethods)
+ Diag(MD->getLocation(), diag::err_function_marked_override_not_overriding)
<< MD->getDeclName();
- return;
- }
}
-/// CheckIfOverriddenFunctionIsMarkedFinal - Checks whether a virtual member
+/// CheckIfOverriddenFunctionIsMarkedFinal - Checks whether a virtual member
/// function overrides a virtual member function marked 'final', according to
-/// C++0x [class.virtual]p3.
+/// C++11 [class.virtual]p4.
bool Sema::CheckIfOverriddenFunctionIsMarkedFinal(const CXXMethodDecl *New,
const CXXMethodDecl *Old) {
if (!Old->hasAttr<FinalAttr>())
@@ -1440,16 +1460,26 @@ bool Sema::CheckIfOverriddenFunctionIsMarkedFinal(const CXXMethodDecl *New,
return true;
}
+static bool InitializationHasSideEffects(const FieldDecl &FD) {
+ const Type *T = FD.getType()->getBaseElementTypeUnsafe();
+ // FIXME: Destruction of ObjC lifetime types has side-effects.
+ if (const CXXRecordDecl *RD = T->getAsCXXRecordDecl())
+ return !RD->isCompleteDefinition() ||
+ !RD->hasTrivialDefaultConstructor() ||
+ !RD->hasTrivialDestructor();
+ return false;
+}
+
/// ActOnCXXMemberDeclarator - This is invoked when a C++ class member
/// declarator is parsed. 'AS' is the access specifier, 'BW' specifies the
/// bitfield width if there is one, 'InitExpr' specifies the initializer if
-/// one has been parsed, and 'HasDeferredInit' is true if an initializer is
-/// present but parsing it has been deferred.
+/// one has been parsed, and 'InitStyle' is set if an in-class initializer is
+/// present (but parsing it has been deferred).
Decl *
Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
MultiTemplateParamsArg TemplateParameterLists,
Expr *BW, const VirtSpecifiers &VS,
- bool HasDeferredInit) {
+ InClassInitStyle InitStyle) {
const DeclSpec &DS = D.getDeclSpec();
DeclarationNameInfo NameInfo = GetNameForDeclarator(D);
DeclarationName Name = NameInfo.getName();
@@ -1507,12 +1537,12 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
CXXScopeSpec &SS = D.getCXXScopeSpec();
// Data members must have identifiers for names.
- if (Name.getNameKind() != DeclarationName::Identifier) {
+ if (!Name.isIdentifier()) {
Diag(Loc, diag::err_bad_variable_name)
<< Name;
return 0;
}
-
+
IdentifierInfo *II = Name.getAsIdentifierInfo();
// Member field could not be with "template" keyword.
@@ -1553,10 +1583,10 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
}
Member = HandleField(S, cast<CXXRecordDecl>(CurContext), Loc, D, BitWidth,
- HasDeferredInit, AS);
+ InitStyle, AS);
assert(Member && "HandleField never returns null");
} else {
- assert(!HasDeferredInit);
+ assert(InitStyle == ICIS_NoInit);
Member = HandleDeclarator(S, D, move(TemplateParameterLists));
if (!Member) {
@@ -1596,37 +1626,39 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
FunTmpl->getTemplatedDecl()->setAccess(AS);
}
- if (VS.isOverrideSpecified()) {
- CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Member);
- if (!MD || !MD->isVirtual()) {
- Diag(Member->getLocStart(),
- diag::override_keyword_only_allowed_on_virtual_member_functions)
- << "override" << FixItHint::CreateRemoval(VS.getOverrideLoc());
- } else
- MD->addAttr(new (Context) OverrideAttr(VS.getOverrideLoc(), Context));
- }
- if (VS.isFinalSpecified()) {
- CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Member);
- if (!MD || !MD->isVirtual()) {
- Diag(Member->getLocStart(),
- diag::override_keyword_only_allowed_on_virtual_member_functions)
- << "final" << FixItHint::CreateRemoval(VS.getFinalLoc());
- } else
- MD->addAttr(new (Context) FinalAttr(VS.getFinalLoc(), Context));
- }
+ if (VS.isOverrideSpecified())
+ Member->addAttr(new (Context) OverrideAttr(VS.getOverrideLoc(), Context));
+ if (VS.isFinalSpecified())
+ Member->addAttr(new (Context) FinalAttr(VS.getFinalLoc(), Context));
if (VS.getLastLocation().isValid()) {
// Update the end location of a method that has a virt-specifiers.
if (CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(Member))
MD->setRangeEnd(VS.getLastLocation());
}
-
+
CheckOverrideControl(Member);
assert((Name || isInstField) && "No identifier for non-field ?");
- if (isInstField)
- FieldCollector->Add(cast<FieldDecl>(Member));
+ if (isInstField) {
+ FieldDecl *FD = cast<FieldDecl>(Member);
+ FieldCollector->Add(FD);
+
+ if (Diags.getDiagnosticLevel(diag::warn_unused_private_field,
+ FD->getLocation())
+ != DiagnosticsEngine::Ignored) {
+ // Remember all explicit private FieldDecls that have a name, no side
+ // effects and are not part of a dependent type declaration.
+ if (!FD->isImplicit() && FD->getDeclName() &&
+ FD->getAccess() == AS_private &&
+ !FD->hasAttr<UnusedAttr>() &&
+ !FD->getParent()->isDependentContext() &&
+ !InitializationHasSideEffects(*FD))
+ UnusedPrivateFields.insert(FD);
+ }
+ }
+
return Member;
}
@@ -1635,9 +1667,11 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
/// instantiating an in-class initializer in a class template. Such actions
/// are deferred until the class is complete.
void
-Sema::ActOnCXXInClassMemberInitializer(Decl *D, SourceLocation EqualLoc,
+Sema::ActOnCXXInClassMemberInitializer(Decl *D, SourceLocation InitLoc,
Expr *InitExpr) {
FieldDecl *FD = cast<FieldDecl>(D);
+ assert(FD->getInClassInitStyle() != ICIS_NoInit &&
+ "must set init style when field is created");
if (!InitExpr) {
FD->setInvalidDecl();
@@ -1660,9 +1694,9 @@ Sema::ActOnCXXInClassMemberInitializer(Decl *D, SourceLocation EqualLoc,
Expr **Inits = &InitExpr;
unsigned NumInits = 1;
InitializedEntity Entity = InitializedEntity::InitializeMember(FD);
- InitializationKind Kind = EqualLoc.isInvalid()
+ InitializationKind Kind = FD->getInClassInitStyle() == ICIS_ListInit
? InitializationKind::CreateDirectList(InitExpr->getLocStart())
- : InitializationKind::CreateCopy(InitExpr->getLocStart(), EqualLoc);
+ : InitializationKind::CreateCopy(InitExpr->getLocStart(), InitLoc);
InitializationSequence Seq(*this, Entity, Kind, Inits, NumInits);
Init = Seq.Perform(*this, Entity, Kind, MultiExprArg(Inits, NumInits));
if (Init.isInvalid()) {
@@ -1670,7 +1704,7 @@ Sema::ActOnCXXInClassMemberInitializer(Decl *D, SourceLocation EqualLoc,
return;
}
- CheckImplicitConversions(Init.get(), EqualLoc);
+ CheckImplicitConversions(Init.get(), InitLoc);
}
// C++0x [class.base.init]p7:
@@ -2010,73 +2044,95 @@ static void CheckForDanglingReferenceOrPointer(Sema &S, ValueDecl *Member,
<< (unsigned)IsPointer;
}
-/// Checks an initializer expression for use of uninitialized fields, such as
-/// containing the field that is being initialized. Returns true if there is an
-/// uninitialized field was used an updates the SourceLocation parameter; false
-/// otherwise.
-static bool InitExprContainsUninitializedFields(const Stmt *S,
- const ValueDecl *LhsField,
- SourceLocation *L) {
- assert(isa<FieldDecl>(LhsField) || isa<IndirectFieldDecl>(LhsField));
-
- if (isa<CallExpr>(S)) {
- // Do not descend into function calls or constructors, as the use
- // of an uninitialized field may be valid. One would have to inspect
- // the contents of the function/ctor to determine if it is safe or not.
- // i.e. Pass-by-value is never safe, but pass-by-reference and pointers
- // may be safe, depending on what the function/ctor does.
- return false;
- }
- if (const MemberExpr *ME = dyn_cast<MemberExpr>(S)) {
- const NamedDecl *RhsField = ME->getMemberDecl();
-
- if (const VarDecl *VD = dyn_cast<VarDecl>(RhsField)) {
- // The member expression points to a static data member.
- assert(VD->isStaticDataMember() &&
- "Member points to non-static data member!");
- (void)VD;
- return false;
+namespace {
+ class UninitializedFieldVisitor
+ : public EvaluatedExprVisitor<UninitializedFieldVisitor> {
+ Sema &S;
+ ValueDecl *VD;
+ public:
+ typedef EvaluatedExprVisitor<UninitializedFieldVisitor> Inherited;
+ UninitializedFieldVisitor(Sema &S, ValueDecl *VD) : Inherited(S.Context),
+ S(S), VD(VD) {
}
-
- if (isa<EnumConstantDecl>(RhsField)) {
- // The member expression points to an enum.
- return false;
+
+ void HandleExpr(Expr *E) {
+ if (!E) return;
+
+ // Expressions like x(x) sometimes lack the surrounding expressions
+ // but need to be checked anyways.
+ HandleValue(E);
+ Visit(E);
}
- if (RhsField == LhsField) {
- // Initializing a field with itself. Throw a warning.
- // But wait; there are exceptions!
- // Exception #1: The field may not belong to this record.
- // e.g. Foo(const Foo& rhs) : A(rhs.A) {}
- const Expr *base = ME->getBase();
- if (base != NULL && !isa<CXXThisExpr>(base->IgnoreParenCasts())) {
- // Even though the field matches, it does not belong to this record.
- return false;
+ void HandleValue(Expr *E) {
+ E = E->IgnoreParens();
+
+ if (MemberExpr *ME = dyn_cast<MemberExpr>(E)) {
+ if (isa<EnumConstantDecl>(ME->getMemberDecl()))
+ return;
+ Expr *Base = E;
+ while (isa<MemberExpr>(Base)) {
+ ME = dyn_cast<MemberExpr>(Base);
+ if (VarDecl *VarD = dyn_cast<VarDecl>(ME->getMemberDecl()))
+ if (VarD->hasGlobalStorage())
+ return;
+ Base = ME->getBase();
+ }
+
+ if (VD == ME->getMemberDecl() && isa<CXXThisExpr>(Base)) {
+ S.Diag(ME->getExprLoc(), diag::warn_field_is_uninit);
+ return;
+ }
+ }
+
+ if (ConditionalOperator *CO = dyn_cast<ConditionalOperator>(E)) {
+ HandleValue(CO->getTrueExpr());
+ HandleValue(CO->getFalseExpr());
+ return;
+ }
+
+ if (BinaryConditionalOperator *BCO =
+ dyn_cast<BinaryConditionalOperator>(E)) {
+ HandleValue(BCO->getCommon());
+ HandleValue(BCO->getFalseExpr());
+ return;
+ }
+
+ if (BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) {
+ switch (BO->getOpcode()) {
+ default:
+ return;
+ case(BO_PtrMemD):
+ case(BO_PtrMemI):
+ HandleValue(BO->getLHS());
+ return;
+ case(BO_Comma):
+ HandleValue(BO->getRHS());
+ return;
+ }
}
- // None of the exceptions triggered; return true to indicate an
- // uninitialized field was used.
- *L = ME->getMemberLoc();
- return true;
}
- } else if (isa<UnaryExprOrTypeTraitExpr>(S)) {
- // sizeof/alignof doesn't reference contents, do not warn.
- return false;
- } else if (const UnaryOperator *UOE = dyn_cast<UnaryOperator>(S)) {
- // address-of doesn't reference contents (the pointer may be dereferenced
- // in the same expression but it would be rare; and weird).
- if (UOE->getOpcode() == UO_AddrOf)
- return false;
- }
- for (Stmt::const_child_range it = S->children(); it; ++it) {
- if (!*it) {
- // An expression such as 'member(arg ?: "")' may trigger this.
- continue;
+
+ void VisitImplicitCastExpr(ImplicitCastExpr *E) {
+ if (E->getCastKind() == CK_LValueToRValue)
+ HandleValue(E->getSubExpr());
+
+ Inherited::VisitImplicitCastExpr(E);
}
- if (InitExprContainsUninitializedFields(*it, LhsField, L))
- return true;
+
+ void VisitCXXMemberCallExpr(CXXMemberCallExpr *E) {
+ Expr *Callee = E->getCallee();
+ if (isa<MemberExpr>(Callee))
+ HandleValue(Callee);
+
+ Inherited::VisitCXXMemberCallExpr(E);
+ }
+ };
+ static void CheckInitExprContainsUninitializedFields(Sema &S, Expr *E,
+ ValueDecl *VD) {
+ UninitializedFieldVisitor(S, VD).HandleExpr(E);
}
- return false;
-}
+} // namespace
MemInitResult
Sema::BuildMemberInitializer(ValueDecl *Member, Expr *Init,
@@ -2106,18 +2162,17 @@ Sema::BuildMemberInitializer(ValueDecl *Member, Expr *Init,
Args = InitList->getInits();
NumArgs = InitList->getNumInits();
}
- for (unsigned i = 0; i < NumArgs; ++i) {
- SourceLocation L;
- if (InitExprContainsUninitializedFields(Args[i], Member, &L)) {
- // FIXME: Return true in the case when other fields are used before being
+
+ if (getDiagnostics().getDiagnosticLevel(diag::warn_field_is_uninit, IdLoc)
+ != DiagnosticsEngine::Ignored)
+ for (unsigned i = 0; i < NumArgs; ++i)
+ // FIXME: Warn about the case when other fields are used before being
// uninitialized. For example, let this field be the i'th field. When
// initializing the i'th field, throw a warning if any of the >= i'th
// fields are used, as they are not yet initialized.
// Right now we are only handling the case where the i'th field uses
// itself in its initializer.
- Diag(L, diag::warn_field_is_uninit);
- }
- }
+ CheckInitExprContainsUninitializedFields(*this, Args[i], Member);
SourceRange InitRange = Init->getSourceRange();
@@ -2235,6 +2290,16 @@ Sema::BuildDelegatingInitializer(TypeSourceInfo *TInfo, Expr *Init,
if (DelegationInit.isInvalid())
return true;
+ // If we are in a dependent context, template instantiation will
+ // perform this type-checking again. Just save the arguments that we
+ // received in a ParenListExpr.
+ // FIXME: This isn't quite ideal, since our ASTs don't capture all
+ // of the information that we have about the base
+ // initializer. However, deconstructing the ASTs is a dicey process,
+ // and this approach is far more likely to get the corner cases right.
+ if (CurContext->isDependentContext())
+ DelegationInit = Owned(Init);
+
return new (Context) CXXCtorInitializer(Context, TInfo, InitRange.getBegin(),
DelegationInit.takeAs<Expr>(),
InitRange.getEnd());
@@ -2694,7 +2759,7 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
FieldBaseElementType->isObjCRetainableType() &&
FieldBaseElementType.getObjCLifetime() != Qualifiers::OCL_None &&
FieldBaseElementType.getObjCLifetime() != Qualifiers::OCL_ExplicitNone) {
- // Instant objects:
+ // ARC:
// Default-initialize Objective-C pointers to NULL.
CXXMemberInit
= new (SemaRef.Context) CXXCtorInitializer(SemaRef.Context, Field,
@@ -2741,6 +2806,16 @@ struct BaseAndFieldInfo {
llvm_unreachable("Invalid ImplicitInitializerKind!");
}
+
+ bool addFieldInitializer(CXXCtorInitializer *Init) {
+ AllToInit.push_back(Init);
+
+ // Check whether this initializer makes the field "used".
+ if (Init->getInit() && Init->getInit()->HasSideEffects(S.Context))
+ S.UnusedPrivateFields.remove(Init->getAnyMember());
+
+ return false;
+ }
};
}
@@ -2778,12 +2853,10 @@ static bool CollectFieldInitializer(Sema &SemaRef, BaseAndFieldInfo &Info,
IndirectFieldDecl *Indirect = 0) {
// Overwhelmingly common case: we have a direct initializer for this field.
- if (CXXCtorInitializer *Init = Info.AllBaseFields.lookup(Field)) {
- Info.AllToInit.push_back(Init);
- return false;
- }
+ if (CXXCtorInitializer *Init = Info.AllBaseFields.lookup(Field))
+ return Info.addFieldInitializer(Init);
- // C++0x [class.base.init]p8: if the entity is a non-static data member that
+ // C++11 [class.base.init]p8: if the entity is a non-static data member that
// has a brace-or-equal-initializer, the entity is initialized as specified
// in [dcl.init].
if (Field->hasInClassInitializer() && !Info.isImplicitCopyOrMove()) {
@@ -2798,8 +2871,7 @@ static bool CollectFieldInitializer(Sema &SemaRef, BaseAndFieldInfo &Info,
SourceLocation(),
SourceLocation(), 0,
SourceLocation());
- Info.AllToInit.push_back(Init);
- return false;
+ return Info.addFieldInitializer(Init);
}
// Don't build an implicit initializer for union members if none was
@@ -2823,10 +2895,10 @@ static bool CollectFieldInitializer(Sema &SemaRef, BaseAndFieldInfo &Info,
Indirect, Init))
return true;
- if (Init)
- Info.AllToInit.push_back(Init);
+ if (!Init)
+ return false;
- return false;
+ return Info.addFieldInitializer(Init);
}
bool
@@ -3397,19 +3469,33 @@ void Sema::ActOnDefaultCtorInitializers(Decl *CDtorDecl) {
bool Sema::RequireNonAbstractType(SourceLocation Loc, QualType T,
unsigned DiagID, AbstractDiagSelID SelID) {
- if (SelID == -1)
- return RequireNonAbstractType(Loc, T, PDiag(DiagID));
- else
- return RequireNonAbstractType(Loc, T, PDiag(DiagID) << SelID);
+ class NonAbstractTypeDiagnoser : public TypeDiagnoser {
+ unsigned DiagID;
+ AbstractDiagSelID SelID;
+
+ public:
+ NonAbstractTypeDiagnoser(unsigned DiagID, AbstractDiagSelID SelID)
+ : TypeDiagnoser(DiagID == 0), DiagID(DiagID), SelID(SelID) { }
+
+ virtual void diagnose(Sema &S, SourceLocation Loc, QualType T) {
+ if (Suppressed) return;
+ if (SelID == -1)
+ S.Diag(Loc, DiagID) << T;
+ else
+ S.Diag(Loc, DiagID) << SelID << T;
+ }
+ } Diagnoser(DiagID, SelID);
+
+ return RequireNonAbstractType(Loc, T, Diagnoser);
}
bool Sema::RequireNonAbstractType(SourceLocation Loc, QualType T,
- const PartialDiagnostic &PD) {
+ TypeDiagnoser &Diagnoser) {
if (!getLangOpts().CPlusPlus)
return false;
if (const ArrayType *AT = Context.getAsArrayType(T))
- return RequireNonAbstractType(Loc, AT->getElementType(), PD);
+ return RequireNonAbstractType(Loc, AT->getElementType(), Diagnoser);
if (const PointerType *PT = T->getAs<PointerType>()) {
// Find the innermost pointer type.
@@ -3417,7 +3503,7 @@ bool Sema::RequireNonAbstractType(SourceLocation Loc, QualType T,
PT = T;
if (const ArrayType *AT = Context.getAsArrayType(PT->getPointeeType()))
- return RequireNonAbstractType(Loc, AT->getElementType(), PD);
+ return RequireNonAbstractType(Loc, AT->getElementType(), Diagnoser);
}
const RecordType *RT = T->getAs<RecordType>();
@@ -3436,7 +3522,7 @@ bool Sema::RequireNonAbstractType(SourceLocation Loc, QualType T,
if (!RD->isAbstract())
return false;
- Diag(Loc, PD) << RD->getDeclName();
+ Diagnoser.diagnose(*this, Loc, T);
DiagnoseAbstractType(RD);
return true;
@@ -3732,7 +3818,7 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
for (CXXRecordDecl::method_iterator M = Record->method_begin(),
MEnd = Record->method_end();
M != MEnd; ++M) {
- if (!(*M)->isStatic())
+ if (!M->isStatic())
DiagnoseHiddenVirtualMethods(Record, *M);
}
}
@@ -3762,8 +3848,8 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
case TSK_Undeclared:
case TSK_ExplicitSpecialization:
- RequireLiteralType((*M)->getLocation(), Context.getRecordType(Record),
- PDiag(diag::err_constexpr_method_non_literal));
+ RequireLiteralType(M->getLocation(), Context.getRecordType(Record),
+ diag::err_constexpr_method_non_literal);
break;
}
@@ -3781,558 +3867,354 @@ 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) {
for (CXXRecordDecl::method_iterator MI = Record->method_begin(),
ME = Record->method_end();
- MI != ME; ++MI) {
- if (!MI->isInvalidDecl() && MI->isExplicitlyDefaulted()) {
- switch (getSpecialMember(*MI)) {
- case CXXDefaultConstructor:
- CheckExplicitlyDefaultedDefaultConstructor(
- cast<CXXConstructorDecl>(*MI));
- break;
-
- case CXXDestructor:
- CheckExplicitlyDefaultedDestructor(cast<CXXDestructorDecl>(*MI));
- break;
-
- case CXXCopyConstructor:
- CheckExplicitlyDefaultedCopyConstructor(cast<CXXConstructorDecl>(*MI));
- break;
-
- case CXXCopyAssignment:
- CheckExplicitlyDefaultedCopyAssignment(*MI);
- break;
-
- case CXXMoveConstructor:
- CheckExplicitlyDefaultedMoveConstructor(cast<CXXConstructorDecl>(*MI));
- break;
-
- case CXXMoveAssignment:
- CheckExplicitlyDefaultedMoveAssignment(*MI);
- break;
-
- case CXXInvalid:
- llvm_unreachable("non-special member explicitly defaulted!");
- }
- }
- }
-
+ MI != ME; ++MI)
+ if (!MI->isInvalidDecl() && MI->isExplicitlyDefaulted())
+ CheckExplicitlyDefaultedSpecialMember(*MI);
+}
+
+/// Is the special member function which would be selected to perform the
+/// specified operation on the specified class type a constexpr constructor?
+static bool specialMemberIsConstexpr(Sema &S, CXXRecordDecl *ClassDecl,
+ Sema::CXXSpecialMember CSM,
+ bool ConstArg) {
+ Sema::SpecialMemberOverloadResult *SMOR =
+ S.LookupSpecialMember(ClassDecl, CSM, ConstArg,
+ false, false, false, false);
+ if (!SMOR || !SMOR->getMethod())
+ // A constructor we wouldn't select can't be "involved in initializing"
+ // anything.
+ return true;
+ return SMOR->getMethod()->isConstexpr();
}
-void Sema::CheckExplicitlyDefaultedDefaultConstructor(CXXConstructorDecl *CD) {
- assert(CD->isExplicitlyDefaulted() && CD->isDefaultConstructor());
-
- // Whether this was the first-declared instance of the constructor.
- // This affects whether we implicitly add an exception spec (and, eventually,
- // constexpr). It is also ill-formed to explicitly default a constructor such
- // that it would be deleted. (C++0x [decl.fct.def.default])
- bool First = CD == CD->getCanonicalDecl();
+/// Determine whether the specified special member function would be constexpr
+/// if it were implicitly defined.
+static bool defaultedSpecialMemberIsConstexpr(Sema &S, CXXRecordDecl *ClassDecl,
+ Sema::CXXSpecialMember CSM,
+ bool ConstArg) {
+ if (!S.getLangOpts().CPlusPlus0x)
+ return false;
- bool HadError = false;
- if (CD->getNumParams() != 0) {
- Diag(CD->getLocation(), diag::err_defaulted_default_ctor_params)
- << CD->getSourceRange();
- HadError = true;
- }
+ // C++11 [dcl.constexpr]p4:
+ // In the definition of a constexpr constructor [...]
+ switch (CSM) {
+ case Sema::CXXDefaultConstructor:
+ // Since default constructor lookup is essentially trivial (and cannot
+ // involve, for instance, template instantiation), we compute whether a
+ // defaulted default constructor is constexpr directly within CXXRecordDecl.
+ //
+ // This is important for performance; we need to know whether the default
+ // constructor is constexpr to determine whether the type is a literal type.
+ return ClassDecl->defaultedDefaultConstructorIsConstexpr();
- ImplicitExceptionSpecification Spec
- = ComputeDefaultedDefaultCtorExceptionSpec(CD->getParent());
- FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI();
- if (EPI.ExceptionSpecType == EST_Delayed) {
- // Exception specification depends on some deferred part of the class. We'll
- // try again when the class's definition has been fully processed.
- return;
- }
- const FunctionProtoType *CtorType = CD->getType()->getAs<FunctionProtoType>(),
- *ExceptionType = Context.getFunctionType(
- Context.VoidTy, 0, 0, EPI)->getAs<FunctionProtoType>();
+ case Sema::CXXCopyConstructor:
+ case Sema::CXXMoveConstructor:
+ // For copy or move constructors, we need to perform overload resolution.
+ break;
- // C++11 [dcl.fct.def.default]p2:
- // An explicitly-defaulted function may be declared constexpr only if it
- // would have been implicitly declared as constexpr,
- // Do not apply this rule to templates, since core issue 1358 makes such
- // functions always instantiate to constexpr functions.
- if (CD->isConstexpr() &&
- CD->getTemplatedKind() == FunctionDecl::TK_NonTemplate) {
- if (!CD->getParent()->defaultedDefaultConstructorIsConstexpr()) {
- Diag(CD->getLocStart(), diag::err_incorrect_defaulted_constexpr)
- << CXXDefaultConstructor;
- HadError = true;
- }
- }
- // and may have an explicit exception-specification only if it is compatible
- // with the exception-specification on the implicit declaration.
- if (CtorType->hasExceptionSpec()) {
- if (CheckEquivalentExceptionSpec(
- PDiag(diag::err_incorrect_defaulted_exception_spec)
- << CXXDefaultConstructor,
- PDiag(),
- ExceptionType, SourceLocation(),
- CtorType, CD->getLocation())) {
- HadError = true;
- }
+ case Sema::CXXCopyAssignment:
+ case Sema::CXXMoveAssignment:
+ case Sema::CXXDestructor:
+ case Sema::CXXInvalid:
+ return false;
}
- // If a function is explicitly defaulted on its first declaration,
- if (First) {
- // -- it is implicitly considered to be constexpr if the implicit
- // definition would be,
- CD->setConstexpr(CD->getParent()->defaultedDefaultConstructorIsConstexpr());
+ // -- if the class is a non-empty union, or for each non-empty anonymous
+ // union member of a non-union class, exactly one non-static data member
+ // shall be initialized; [DR1359]
+ //
+ // If we squint, this is guaranteed, since exactly one non-static data member
+ // will be initialized (if the constructor isn't deleted), we just don't know
+ // which one.
+ if (ClassDecl->isUnion())
+ return true;
- // -- it is implicitly considered to have the same
- // exception-specification as if it had been implicitly declared
- //
- // FIXME: a compatible, but different, explicit exception specification
- // will be silently overridden. We should issue a warning if this happens.
- EPI.ExtInfo = CtorType->getExtInfo();
+ // -- the class shall not have any virtual base classes;
+ if (ClassDecl->getNumVBases())
+ return false;
- // Such a function is also trivial if the implicitly-declared function
- // would have been.
- CD->setTrivial(CD->getParent()->hasTrivialDefaultConstructor());
- }
+ // -- every constructor involved in initializing [...] base class
+ // sub-objects shall be a constexpr constructor;
+ for (CXXRecordDecl::base_class_iterator B = ClassDecl->bases_begin(),
+ BEnd = ClassDecl->bases_end();
+ B != BEnd; ++B) {
+ const RecordType *BaseType = B->getType()->getAs<RecordType>();
+ if (!BaseType) continue;
- if (HadError) {
- CD->setInvalidDecl();
- return;
+ CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(BaseType->getDecl());
+ if (!specialMemberIsConstexpr(S, BaseClassDecl, CSM, ConstArg))
+ return false;
}
- if (ShouldDeleteSpecialMember(CD, CXXDefaultConstructor)) {
- if (First) {
- CD->setDeletedAsWritten();
- } else {
- Diag(CD->getLocation(), diag::err_out_of_line_default_deletes)
- << CXXDefaultConstructor;
- CD->setInvalidDecl();
+ // -- every constructor involved in initializing non-static data members
+ // [...] shall be a constexpr constructor;
+ // -- every non-static data member and base class sub-object shall be
+ // initialized
+ for (RecordDecl::field_iterator F = ClassDecl->field_begin(),
+ FEnd = ClassDecl->field_end();
+ F != FEnd; ++F) {
+ if (F->isInvalidDecl())
+ continue;
+ if (const RecordType *RecordTy =
+ S.Context.getBaseElementType(F->getType())->getAs<RecordType>()) {
+ CXXRecordDecl *FieldRecDecl = cast<CXXRecordDecl>(RecordTy->getDecl());
+ if (!specialMemberIsConstexpr(S, FieldRecDecl, CSM, ConstArg))
+ return false;
}
}
-}
-
-void Sema::CheckExplicitlyDefaultedCopyConstructor(CXXConstructorDecl *CD) {
- assert(CD->isExplicitlyDefaulted() && CD->isCopyConstructor());
-
- // Whether this was the first-declared instance of the constructor.
- bool First = CD == CD->getCanonicalDecl();
-
- bool HadError = false;
- if (CD->getNumParams() != 1) {
- Diag(CD->getLocation(), diag::err_defaulted_copy_ctor_params)
- << CD->getSourceRange();
- HadError = true;
- }
- ImplicitExceptionSpecification Spec(*this);
- bool Const;
- llvm::tie(Spec, Const) =
- ComputeDefaultedCopyCtorExceptionSpecAndConst(CD->getParent());
-
- FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI();
- const FunctionProtoType *CtorType = CD->getType()->getAs<FunctionProtoType>(),
- *ExceptionType = Context.getFunctionType(
- Context.VoidTy, 0, 0, EPI)->getAs<FunctionProtoType>();
-
- // Check for parameter type matching.
- // This is a copy ctor so we know it's a cv-qualified reference to T.
- QualType ArgType = CtorType->getArgType(0);
- if (ArgType->getPointeeType().isVolatileQualified()) {
- Diag(CD->getLocation(), diag::err_defaulted_copy_ctor_volatile_param);
- HadError = true;
- }
- if (ArgType->getPointeeType().isConstQualified() && !Const) {
- Diag(CD->getLocation(), diag::err_defaulted_copy_ctor_const_param);
- HadError = true;
- }
+ // All OK, it's constexpr!
+ return true;
+}
- // C++11 [dcl.fct.def.default]p2:
- // An explicitly-defaulted function may be declared constexpr only if it
- // would have been implicitly declared as constexpr,
- // Do not apply this rule to templates, since core issue 1358 makes such
- // functions always instantiate to constexpr functions.
- if (CD->isConstexpr() &&
- CD->getTemplatedKind() == FunctionDecl::TK_NonTemplate) {
- if (!CD->getParent()->defaultedCopyConstructorIsConstexpr()) {
- Diag(CD->getLocStart(), diag::err_incorrect_defaulted_constexpr)
- << CXXCopyConstructor;
- HadError = true;
- }
- }
- // and may have an explicit exception-specification only if it is compatible
- // with the exception-specification on the implicit declaration.
- if (CtorType->hasExceptionSpec()) {
- if (CheckEquivalentExceptionSpec(
- PDiag(diag::err_incorrect_defaulted_exception_spec)
- << CXXCopyConstructor,
- PDiag(),
- ExceptionType, SourceLocation(),
- CtorType, CD->getLocation())) {
- HadError = 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");
+}
- // If a function is explicitly defaulted on its first declaration,
- if (First) {
- // -- it is implicitly considered to be constexpr if the implicit
- // definition would be,
- CD->setConstexpr(CD->getParent()->defaultedCopyConstructorIsConstexpr());
+static void
+updateExceptionSpec(Sema &S, FunctionDecl *FD, const FunctionProtoType *FPT,
+ const Sema::ImplicitExceptionSpecification &ExceptSpec) {
+ FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
+ ExceptSpec.getEPI(EPI);
+ const FunctionProtoType *NewFPT = cast<FunctionProtoType>(
+ S.Context.getFunctionType(FPT->getResultType(), FPT->arg_type_begin(),
+ FPT->getNumArgs(), EPI));
+ FD->setType(QualType(NewFPT, 0));
+}
+
+void Sema::EvaluateImplicitExceptionSpec(SourceLocation Loc, CXXMethodDecl *MD) {
+ const FunctionProtoType *FPT = MD->getType()->castAs<FunctionProtoType>();
+ if (FPT->getExceptionSpecType() != EST_Unevaluated)
+ return;
- // -- it is implicitly considered to have the same
- // exception-specification as if it had been implicitly declared, and
- //
- // FIXME: a compatible, but different, explicit exception specification
- // will be silently overridden. We should issue a warning if this happens.
- EPI.ExtInfo = CtorType->getExtInfo();
+ // Evaluate the exception specification.
+ ImplicitExceptionSpecification ExceptSpec =
+ computeImplicitExceptionSpec(*this, Loc, MD);
- // -- [...] it shall have the same parameter type as if it had been
- // implicitly declared.
- CD->setType(Context.getFunctionType(Context.VoidTy, &ArgType, 1, EPI));
+ // Update the type of the special member to use it.
+ updateExceptionSpec(*this, MD, FPT, ExceptSpec);
- // Such a function is also trivial if the implicitly-declared function
- // would have been.
- CD->setTrivial(CD->getParent()->hasTrivialCopyConstructor());
- }
+ // A user-provided destructor can be defined outside the class. When that
+ // happens, be sure to update the exception specification on both
+ // declarations.
+ const FunctionProtoType *CanonicalFPT =
+ MD->getCanonicalDecl()->getType()->castAs<FunctionProtoType>();
+ if (CanonicalFPT->getExceptionSpecType() == EST_Unevaluated)
+ updateExceptionSpec(*this, MD->getCanonicalDecl(),
+ CanonicalFPT, ExceptSpec);
+}
- if (HadError) {
- CD->setInvalidDecl();
- return;
- }
+static bool isImplicitCopyCtorArgConst(Sema &S, CXXRecordDecl *ClassDecl);
+static bool isImplicitCopyAssignmentArgConst(Sema &S, CXXRecordDecl *ClassDecl);
- if (ShouldDeleteSpecialMember(CD, CXXCopyConstructor)) {
- if (First) {
- CD->setDeletedAsWritten();
- } else {
- Diag(CD->getLocation(), diag::err_out_of_line_default_deletes)
- << CXXCopyConstructor;
- CD->setInvalidDecl();
- }
- }
-}
+void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) {
+ CXXRecordDecl *RD = MD->getParent();
+ CXXSpecialMember CSM = getSpecialMember(MD);
-void Sema::CheckExplicitlyDefaultedCopyAssignment(CXXMethodDecl *MD) {
- assert(MD->isExplicitlyDefaulted());
+ assert(MD->isExplicitlyDefaulted() && CSM != CXXInvalid &&
+ "not an explicitly-defaulted special member");
- // Whether this was the first-declared instance of the operator
+ // Whether this was the first-declared instance of the constructor.
+ // This affects whether we implicitly add an exception spec and constexpr.
bool First = MD == MD->getCanonicalDecl();
bool HadError = false;
- if (MD->getNumParams() != 1) {
- Diag(MD->getLocation(), diag::err_defaulted_copy_assign_params)
- << MD->getSourceRange();
- HadError = true;
- }
- QualType ReturnType =
- MD->getType()->getAs<FunctionType>()->getResultType();
- if (!ReturnType->isLValueReferenceType() ||
- !Context.hasSameType(
- Context.getCanonicalType(ReturnType->getPointeeType()),
- Context.getCanonicalType(Context.getTypeDeclType(MD->getParent())))) {
- Diag(MD->getLocation(), diag::err_defaulted_copy_assign_return_type);
+ // C++11 [dcl.fct.def.default]p1:
+ // A function that is explicitly defaulted shall
+ // -- be a special member function (checked elsewhere),
+ // -- have the same type (except for ref-qualifiers, and except that a
+ // copy operation can take a non-const reference) as an implicit
+ // declaration, and
+ // -- not have default arguments.
+ unsigned ExpectedParams = 1;
+ if (CSM == CXXDefaultConstructor || CSM == CXXDestructor)
+ ExpectedParams = 0;
+ if (MD->getNumParams() != ExpectedParams) {
+ // This also checks for default arguments: a copy or move constructor with a
+ // default argument is classified as a default constructor, and assignment
+ // operations and destructors can't have default arguments.
+ Diag(MD->getLocation(), diag::err_defaulted_special_member_params)
+ << CSM << MD->getSourceRange();
HadError = true;
}
- ImplicitExceptionSpecification Spec(*this);
- bool Const;
- llvm::tie(Spec, Const) =
- ComputeDefaultedCopyCtorExceptionSpecAndConst(MD->getParent());
-
- FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI();
- const FunctionProtoType *OperType = MD->getType()->getAs<FunctionProtoType>(),
- *ExceptionType = Context.getFunctionType(
- Context.VoidTy, 0, 0, EPI)->getAs<FunctionProtoType>();
+ const FunctionProtoType *Type = MD->getType()->getAs<FunctionProtoType>();
- QualType ArgType = OperType->getArgType(0);
- if (!ArgType->isLValueReferenceType()) {
- Diag(MD->getLocation(), diag::err_defaulted_copy_assign_not_ref);
- HadError = true;
- } else {
- if (ArgType->getPointeeType().isVolatileQualified()) {
- Diag(MD->getLocation(), diag::err_defaulted_copy_assign_volatile_param);
+ // Compute argument constness, constexpr, and triviality.
+ bool CanHaveConstParam = false;
+ bool Trivial;
+ switch (CSM) {
+ case CXXDefaultConstructor:
+ Trivial = RD->hasTrivialDefaultConstructor();
+ break;
+ case CXXCopyConstructor:
+ CanHaveConstParam = isImplicitCopyCtorArgConst(*this, RD);
+ Trivial = RD->hasTrivialCopyConstructor();
+ break;
+ case CXXCopyAssignment:
+ CanHaveConstParam = isImplicitCopyAssignmentArgConst(*this, RD);
+ Trivial = RD->hasTrivialCopyAssignment();
+ break;
+ case CXXMoveConstructor:
+ Trivial = RD->hasTrivialMoveConstructor();
+ break;
+ case CXXMoveAssignment:
+ Trivial = RD->hasTrivialMoveAssignment();
+ break;
+ case CXXDestructor:
+ Trivial = RD->hasTrivialDestructor();
+ break;
+ case CXXInvalid:
+ llvm_unreachable("non-special member explicitly defaulted!");
+ }
+
+ QualType ReturnType = Context.VoidTy;
+ if (CSM == CXXCopyAssignment || CSM == CXXMoveAssignment) {
+ // Check for return type matching.
+ ReturnType = Type->getResultType();
+ QualType ExpectedReturnType =
+ Context.getLValueReferenceType(Context.getTypeDeclType(RD));
+ if (!Context.hasSameType(ReturnType, ExpectedReturnType)) {
+ Diag(MD->getLocation(), diag::err_defaulted_special_member_return_type)
+ << (CSM == CXXMoveAssignment) << ExpectedReturnType;
HadError = true;
}
- if (ArgType->getPointeeType().isConstQualified() && !Const) {
- Diag(MD->getLocation(), diag::err_defaulted_copy_assign_const_param);
+
+ // A defaulted special member cannot have cv-qualifiers.
+ if (Type->getTypeQuals()) {
+ Diag(MD->getLocation(), diag::err_defaulted_special_member_quals)
+ << (CSM == CXXMoveAssignment);
HadError = true;
}
}
- if (OperType->getTypeQuals()) {
- Diag(MD->getLocation(), diag::err_defaulted_copy_assign_quals);
- HadError = true;
- }
-
- if (OperType->hasExceptionSpec()) {
- if (CheckEquivalentExceptionSpec(
- PDiag(diag::err_incorrect_defaulted_exception_spec)
- << CXXCopyAssignment,
- PDiag(),
- ExceptionType, SourceLocation(),
- OperType, MD->getLocation())) {
+ // Check for parameter type matching.
+ QualType ArgType = ExpectedParams ? Type->getArgType(0) : QualType();
+ bool HasConstParam = false;
+ if (ExpectedParams && ArgType->isReferenceType()) {
+ // Argument must be reference to possibly-const T.
+ QualType ReferentType = ArgType->getPointeeType();
+ HasConstParam = ReferentType.isConstQualified();
+
+ if (ReferentType.isVolatileQualified()) {
+ Diag(MD->getLocation(),
+ diag::err_defaulted_special_member_volatile_param) << CSM;
HadError = true;
}
- }
- if (First) {
- // We set the declaration to have the computed exception spec here.
- // We duplicate the one parameter type.
- EPI.RefQualifier = OperType->getRefQualifier();
- EPI.ExtInfo = OperType->getExtInfo();
- MD->setType(Context.getFunctionType(ReturnType, &ArgType, 1, EPI));
- // Such a function is also trivial if the implicitly-declared function
- // would have been.
- MD->setTrivial(MD->getParent()->hasTrivialCopyAssignment());
- }
-
- if (HadError) {
- MD->setInvalidDecl();
- return;
- }
-
- if (ShouldDeleteSpecialMember(MD, CXXCopyAssignment)) {
- if (First) {
- MD->setDeletedAsWritten();
- } else {
- Diag(MD->getLocation(), diag::err_out_of_line_default_deletes)
- << CXXCopyAssignment;
- MD->setInvalidDecl();
+ if (HasConstParam && !CanHaveConstParam) {
+ if (CSM == CXXCopyConstructor || CSM == CXXCopyAssignment) {
+ Diag(MD->getLocation(),
+ diag::err_defaulted_special_member_copy_const_param)
+ << (CSM == CXXCopyAssignment);
+ // FIXME: Explain why this special member can't be const.
+ } else {
+ Diag(MD->getLocation(),
+ diag::err_defaulted_special_member_move_const_param)
+ << (CSM == CXXMoveAssignment);
+ }
+ HadError = true;
}
- }
-}
-
-void Sema::CheckExplicitlyDefaultedMoveConstructor(CXXConstructorDecl *CD) {
- assert(CD->isExplicitlyDefaulted() && CD->isMoveConstructor());
-
- // Whether this was the first-declared instance of the constructor.
- bool First = CD == CD->getCanonicalDecl();
- bool HadError = false;
- if (CD->getNumParams() != 1) {
- Diag(CD->getLocation(), diag::err_defaulted_move_ctor_params)
- << CD->getSourceRange();
+ // If a function is explicitly defaulted on its first declaration, it shall
+ // have the same parameter type as if it had been implicitly declared.
+ // (Presumably this is to prevent it from being trivial?)
+ if (!HasConstParam && CanHaveConstParam && First)
+ Diag(MD->getLocation(),
+ diag::err_defaulted_special_member_copy_non_const_param)
+ << (CSM == CXXCopyAssignment);
+ } else if (ExpectedParams) {
+ // A copy assignment operator can take its argument by value, but a
+ // defaulted one cannot.
+ assert(CSM == CXXCopyAssignment && "unexpected non-ref argument");
+ Diag(MD->getLocation(), diag::err_defaulted_copy_assign_not_ref);
HadError = true;
}
- ImplicitExceptionSpecification Spec(
- ComputeDefaultedMoveCtorExceptionSpec(CD->getParent()));
-
- FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI();
- const FunctionProtoType *CtorType = CD->getType()->getAs<FunctionProtoType>(),
- *ExceptionType = Context.getFunctionType(
- Context.VoidTy, 0, 0, EPI)->getAs<FunctionProtoType>();
-
- // Check for parameter type matching.
- // This is a move ctor so we know it's a cv-qualified rvalue reference to T.
- QualType ArgType = CtorType->getArgType(0);
- if (ArgType->getPointeeType().isVolatileQualified()) {
- Diag(CD->getLocation(), diag::err_defaulted_move_ctor_volatile_param);
- HadError = true;
- }
- if (ArgType->getPointeeType().isConstQualified()) {
- Diag(CD->getLocation(), diag::err_defaulted_move_ctor_const_param);
- HadError = true;
+ // 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
// would have been implicitly declared as constexpr,
- // Do not apply this rule to templates, since core issue 1358 makes such
- // functions always instantiate to constexpr functions.
- if (CD->isConstexpr() &&
- CD->getTemplatedKind() == FunctionDecl::TK_NonTemplate) {
- if (!CD->getParent()->defaultedMoveConstructorIsConstexpr()) {
- Diag(CD->getLocStart(), diag::err_incorrect_defaulted_constexpr)
- << CXXMoveConstructor;
- HadError = true;
- }
+ // Do not apply this rule to members of class templates, since core issue 1358
+ // makes such functions always instantiate to constexpr functions. For
+ // non-constructors, this is checked elsewhere.
+ bool Constexpr = defaultedSpecialMemberIsConstexpr(*this, RD, CSM,
+ HasConstParam);
+ if (isa<CXXConstructorDecl>(MD) && MD->isConstexpr() && !Constexpr &&
+ MD->getTemplatedKind() == FunctionDecl::TK_NonTemplate) {
+ Diag(MD->getLocStart(), diag::err_incorrect_defaulted_constexpr) << CSM;
+ // FIXME: Explain why the constructor can't be constexpr.
+ HadError = true;
}
// and may have an explicit exception-specification only if it is compatible
// with the exception-specification on the implicit declaration.
- if (CtorType->hasExceptionSpec()) {
- if (CheckEquivalentExceptionSpec(
- PDiag(diag::err_incorrect_defaulted_exception_spec)
- << CXXMoveConstructor,
- PDiag(),
- ExceptionType, SourceLocation(),
- CtorType, CD->getLocation())) {
- HadError = true;
- }
- }
+ if (Type->hasExceptionSpec() &&
+ CheckEquivalentExceptionSpec(
+ PDiag(diag::err_incorrect_defaulted_exception_spec) << CSM,
+ PDiag(), ImplicitType, SourceLocation(), Type, MD->getLocation()))
+ HadError = true;
// If a function is explicitly defaulted on its first declaration,
if (First) {
// -- it is implicitly considered to be constexpr if the implicit
// definition would be,
- CD->setConstexpr(CD->getParent()->defaultedMoveConstructorIsConstexpr());
+ MD->setConstexpr(Constexpr);
- // -- it is implicitly considered to have the same
- // exception-specification as if it had been implicitly declared, and
- //
- // FIXME: a compatible, but different, explicit exception specification
- // will be silently overridden. We should issue a warning if this happens.
- EPI.ExtInfo = CtorType->getExtInfo();
-
- // -- [...] it shall have the same parameter type as if it had been
- // implicitly declared.
- CD->setType(Context.getFunctionType(Context.VoidTy, &ArgType, 1, EPI));
+ // -- it is implicitly considered to have the same exception-specification
+ // as if it had been implicitly declared,
+ MD->setType(QualType(ImplicitType, 0));
// Such a function is also trivial if the implicitly-declared function
// would have been.
- CD->setTrivial(CD->getParent()->hasTrivialMoveConstructor());
- }
-
- if (HadError) {
- CD->setInvalidDecl();
- return;
+ MD->setTrivial(Trivial);
}
- if (ShouldDeleteSpecialMember(CD, CXXMoveConstructor)) {
+ if (ShouldDeleteSpecialMember(MD, CSM)) {
if (First) {
- CD->setDeletedAsWritten();
+ MD->setDeletedAsWritten();
} else {
- Diag(CD->getLocation(), diag::err_out_of_line_default_deletes)
- << CXXMoveConstructor;
- CD->setInvalidDecl();
- }
- }
-}
-
-void Sema::CheckExplicitlyDefaultedMoveAssignment(CXXMethodDecl *MD) {
- assert(MD->isExplicitlyDefaulted());
-
- // Whether this was the first-declared instance of the operator
- bool First = MD == MD->getCanonicalDecl();
-
- bool HadError = false;
- if (MD->getNumParams() != 1) {
- Diag(MD->getLocation(), diag::err_defaulted_move_assign_params)
- << MD->getSourceRange();
- HadError = true;
- }
-
- QualType ReturnType =
- MD->getType()->getAs<FunctionType>()->getResultType();
- if (!ReturnType->isLValueReferenceType() ||
- !Context.hasSameType(
- Context.getCanonicalType(ReturnType->getPointeeType()),
- Context.getCanonicalType(Context.getTypeDeclType(MD->getParent())))) {
- Diag(MD->getLocation(), diag::err_defaulted_move_assign_return_type);
- HadError = true;
- }
-
- ImplicitExceptionSpecification Spec(
- ComputeDefaultedMoveCtorExceptionSpec(MD->getParent()));
-
- FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI();
- const FunctionProtoType *OperType = MD->getType()->getAs<FunctionProtoType>(),
- *ExceptionType = Context.getFunctionType(
- Context.VoidTy, 0, 0, EPI)->getAs<FunctionProtoType>();
-
- QualType ArgType = OperType->getArgType(0);
- if (!ArgType->isRValueReferenceType()) {
- Diag(MD->getLocation(), diag::err_defaulted_move_assign_not_ref);
- HadError = true;
- } else {
- if (ArgType->getPointeeType().isVolatileQualified()) {
- Diag(MD->getLocation(), diag::err_defaulted_move_assign_volatile_param);
- HadError = true;
- }
- if (ArgType->getPointeeType().isConstQualified()) {
- Diag(MD->getLocation(), diag::err_defaulted_move_assign_const_param);
+ // C++11 [dcl.fct.def.default]p4:
+ // [For a] user-provided explicitly-defaulted function [...] if such a
+ // function is implicitly defined as deleted, the program is ill-formed.
+ Diag(MD->getLocation(), diag::err_out_of_line_default_deletes) << CSM;
HadError = true;
}
}
- if (OperType->getTypeQuals()) {
- Diag(MD->getLocation(), diag::err_defaulted_move_assign_quals);
- HadError = true;
- }
-
- if (OperType->hasExceptionSpec()) {
- if (CheckEquivalentExceptionSpec(
- PDiag(diag::err_incorrect_defaulted_exception_spec)
- << CXXMoveAssignment,
- PDiag(),
- ExceptionType, SourceLocation(),
- OperType, MD->getLocation())) {
- HadError = true;
- }
- }
- if (First) {
- // We set the declaration to have the computed exception spec here.
- // We duplicate the one parameter type.
- EPI.RefQualifier = OperType->getRefQualifier();
- EPI.ExtInfo = OperType->getExtInfo();
- MD->setType(Context.getFunctionType(ReturnType, &ArgType, 1, EPI));
-
- // Such a function is also trivial if the implicitly-declared function
- // would have been.
- MD->setTrivial(MD->getParent()->hasTrivialMoveAssignment());
- }
-
- if (HadError) {
+ if (HadError)
MD->setInvalidDecl();
- return;
- }
-
- if (ShouldDeleteSpecialMember(MD, CXXMoveAssignment)) {
- if (First) {
- MD->setDeletedAsWritten();
- } else {
- Diag(MD->getLocation(), diag::err_out_of_line_default_deletes)
- << CXXMoveAssignment;
- MD->setInvalidDecl();
- }
- }
-}
-
-void Sema::CheckExplicitlyDefaultedDestructor(CXXDestructorDecl *DD) {
- assert(DD->isExplicitlyDefaulted());
-
- // Whether this was the first-declared instance of the destructor.
- bool First = DD == DD->getCanonicalDecl();
-
- ImplicitExceptionSpecification Spec
- = ComputeDefaultedDtorExceptionSpec(DD->getParent());
- FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI();
- const FunctionProtoType *DtorType = DD->getType()->getAs<FunctionProtoType>(),
- *ExceptionType = Context.getFunctionType(
- Context.VoidTy, 0, 0, EPI)->getAs<FunctionProtoType>();
-
- if (DtorType->hasExceptionSpec()) {
- if (CheckEquivalentExceptionSpec(
- PDiag(diag::err_incorrect_defaulted_exception_spec)
- << CXXDestructor,
- PDiag(),
- ExceptionType, SourceLocation(),
- DtorType, DD->getLocation())) {
- DD->setInvalidDecl();
- return;
- }
- }
- if (First) {
- // We set the declaration to have the computed exception spec here.
- // There are no parameters.
- EPI.ExtInfo = DtorType->getExtInfo();
- DD->setType(Context.getFunctionType(Context.VoidTy, 0, 0, EPI));
-
- // Such a function is also trivial if the implicitly-declared function
- // would have been.
- DD->setTrivial(DD->getParent()->hasTrivialDestructor());
- }
-
- if (ShouldDeleteSpecialMember(DD, CXXDestructor)) {
- if (First) {
- DD->setDeletedAsWritten();
- } else {
- Diag(DD->getLocation(), diag::err_out_of_line_default_deletes)
- << CXXDestructor;
- DD->setInvalidDecl();
- }
- }
}
namespace {
@@ -4385,9 +4267,15 @@ struct SpecialMemberDeletionInfo {
bool inUnion() const { return MD->getParent()->isUnion(); }
/// Look up the corresponding special member in the given class.
- Sema::SpecialMemberOverloadResult *lookupIn(CXXRecordDecl *Class) {
+ Sema::SpecialMemberOverloadResult *lookupIn(CXXRecordDecl *Class,
+ unsigned Quals) {
unsigned TQ = MD->getTypeQualifiers();
- return S.LookupSpecialMember(Class, CSM, ConstArg, VolatileArg,
+ // cv-qualifiers on class members don't affect default ctor / dtor calls.
+ if (CSM == Sema::CXXDefaultConstructor || CSM == Sema::CXXDestructor)
+ Quals = 0;
+ return S.LookupSpecialMember(Class, CSM,
+ ConstArg || (Quals & Qualifiers::Const),
+ VolatileArg || (Quals & Qualifiers::Volatile),
MD->getRefQualifier() == RQ_RValue,
TQ & Qualifiers::Const,
TQ & Qualifiers::Volatile);
@@ -4399,7 +4287,8 @@ struct SpecialMemberDeletionInfo {
bool shouldDeleteForField(FieldDecl *FD);
bool shouldDeleteForAllConstMembers();
- bool shouldDeleteForClassSubobject(CXXRecordDecl *Class, Subobject Subobj);
+ bool shouldDeleteForClassSubobject(CXXRecordDecl *Class, Subobject Subobj,
+ unsigned Quals);
bool shouldDeleteForSubobjectCall(Subobject Subobj,
Sema::SpecialMemberOverloadResult *SMOR,
bool IsDtorCallInCtor);
@@ -4480,9 +4369,9 @@ bool SpecialMemberDeletionInfo::shouldDeleteForSubobjectCall(
}
/// Check whether we should delete a special member function due to having a
-/// direct or virtual base class or static data member of class type M.
+/// direct or virtual base class or non-static data member of class type M.
bool SpecialMemberDeletionInfo::shouldDeleteForClassSubobject(
- CXXRecordDecl *Class, Subobject Subobj) {
+ CXXRecordDecl *Class, Subobject Subobj, unsigned Quals) {
FieldDecl *Field = Subobj.dyn_cast<FieldDecl*>();
// C++11 [class.ctor]p5:
@@ -4501,7 +4390,7 @@ bool SpecialMemberDeletionInfo::shouldDeleteForClassSubobject(
// that is deleted or inaccessible
if (!(CSM == Sema::CXXDefaultConstructor &&
Field && Field->hasInClassInitializer()) &&
- shouldDeleteForSubobjectCall(Subobj, lookupIn(Class), false))
+ shouldDeleteForSubobjectCall(Subobj, lookupIn(Class, Quals), false))
return true;
// C++11 [class.ctor]p5, C++11 [class.copy]p11:
@@ -4522,7 +4411,7 @@ bool SpecialMemberDeletionInfo::shouldDeleteForClassSubobject(
/// having a particular direct or virtual base class.
bool SpecialMemberDeletionInfo::shouldDeleteForBase(CXXBaseSpecifier *Base) {
CXXRecordDecl *BaseClass = Base->getType()->getAsCXXRecordDecl();
- return shouldDeleteForClassSubobject(BaseClass, Base);
+ return shouldDeleteForClassSubobject(BaseClass, Base, 0);
}
/// Check whether we should delete a special member function due to the class
@@ -4549,7 +4438,7 @@ bool SpecialMemberDeletionInfo::shouldDeleteForField(FieldDecl *FD) {
(!FieldRecord || !FieldRecord->hasUserProvidedDefaultConstructor())) {
if (Diagnose)
S.Diag(FD->getLocation(), diag::note_deleted_default_ctor_uninit_field)
- << MD->getParent() << FD << FieldType << /*Const*/1;
+ << MD->getParent() << FD << FD->getType() << /*Const*/1;
return true;
}
@@ -4577,7 +4466,7 @@ bool SpecialMemberDeletionInfo::shouldDeleteForField(FieldDecl *FD) {
// -- a non-static data member of const non-class type (or array thereof)
if (Diagnose)
S.Diag(FD->getLocation(), diag::note_deleted_assign_field)
- << IsMove << MD->getParent() << FD << FieldType << /*Const*/1;
+ << IsMove << MD->getParent() << FD << FD->getType() << /*Const*/1;
return true;
}
}
@@ -4599,7 +4488,8 @@ bool SpecialMemberDeletionInfo::shouldDeleteForField(FieldDecl *FD) {
CXXRecordDecl *UnionFieldRecord = UnionFieldType->getAsCXXRecordDecl();
if (UnionFieldRecord &&
- shouldDeleteForClassSubobject(UnionFieldRecord, *UI))
+ shouldDeleteForClassSubobject(UnionFieldRecord, *UI,
+ UnionFieldType.getCVRQualifiers()))
return true;
}
@@ -4618,7 +4508,8 @@ bool SpecialMemberDeletionInfo::shouldDeleteForField(FieldDecl *FD) {
return false;
}
- if (shouldDeleteForClassSubobject(FieldRecord, FD))
+ if (shouldDeleteForClassSubobject(FieldRecord, FD,
+ FieldType.getCVRQualifiers()))
return true;
}
@@ -4647,7 +4538,8 @@ bool SpecialMemberDeletionInfo::shouldDeleteForAllConstMembers() {
/// C++11 [class.copy]p23, and C++11 [class.dtor]p5.
bool Sema::ShouldDeleteSpecialMember(CXXMethodDecl *MD, CXXSpecialMember CSM,
bool Diagnose) {
- assert(!MD->isInvalidDecl());
+ if (MD->isInvalidDecl())
+ return false;
CXXRecordDecl *RD = MD->getParent();
assert(!RD->isDependentType() && "do deletion after instantiation");
if (!LangOpts.CPlusPlus0x || RD->isInvalidDecl())
@@ -4803,7 +4695,7 @@ void Sema::DiagnoseHiddenVirtualMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) {
if (Diags.getDiagnosticLevel(diag::warn_overloaded_virtual,
MD->getLocation()) == DiagnosticsEngine::Ignored)
return;
- if (MD->getDeclName().getNameKind() != DeclarationName::Identifier)
+ if (!MD->getDeclName().isIdentifier())
return;
CXXBasePaths Paths(/*FindAmbiguities=*/true, // true to look in all bases.
@@ -4850,6 +4742,14 @@ void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc,
AdjustDeclIfTemplate(TagDecl);
+ for (const AttributeList* l = AttrList; l; l = l->getNext()) {
+ if (l->getKind() != AttributeList::AT_Visibility)
+ continue;
+ l->setInvalid();
+ Diag(l->getLoc(), diag::warn_attribute_after_definition_ignored) <<
+ l->getName();
+ }
+
ActOnFields(S, RLoc, TagDecl, llvm::makeArrayRef(
// strict aliasing violation!
reinterpret_cast<Decl**>(FieldCollector->getCurFields()),
@@ -5572,6 +5472,8 @@ Decl *Sema::ActOnStartNamespaceDef(Scope *NamespcScope,
}
}
+ ActOnDocumentableDecl(Namespc);
+
// Although we could have an invalid decl (i.e. the namespace name is a
// redefinition), push it as current DeclContext and try to continue parsing.
// FIXME: We should be able to push Namespc here, so that the each DeclContext
@@ -6734,6 +6636,7 @@ Decl *Sema::ActOnAliasDeclaration(Scope *S,
if (!Redeclaration)
PushOnScopeChains(NewND, S);
+ ActOnDocumentableDecl(NewND);
return NewND;
}
@@ -6816,7 +6719,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. [...]
@@ -6863,7 +6769,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());
@@ -6892,9 +6812,9 @@ 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);
// Create the actual constructor declaration.
CanQualType ClassType
@@ -6904,16 +6824,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,
- /*isConstexpr=*/ClassDecl->defaultedDefaultConstructorIsConstexpr() &&
- getLangOpts().CPlusPlus0x);
+ 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;
@@ -6948,7 +6872,7 @@ void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation,
}
SourceLocation Loc = Constructor->getLocation();
- Constructor->setBody(new (Context) CompoundStmt(Context, 0, 0, Loc, Loc));
+ Constructor->setBody(new (Context) CompoundStmt(Loc));
Constructor->setUsed();
MarkVTableUsed(CurrentLocation, ClassDecl);
@@ -6958,58 +6882,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())
- CheckExplicitlyDefaultedDefaultConstructor(CtorDecl);
+ if (!ClassDecl->isDependentType())
+ CheckExplicitlyDefaultedMethods(ClassDecl);
}
void Sema::DeclareInheritedConstructors(CXXRecordDecl *ClassDecl) {
@@ -7193,7 +7073,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.
@@ -7240,14 +7122,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();
@@ -7255,24 +7131,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);
@@ -7309,7 +7188,7 @@ void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation,
}
SourceLocation Loc = Destructor->getLocation();
- Destructor->setBody(new (Context) CompoundStmt(Context, 0, 0, Loc, Loc));
+ Destructor->setBody(new (Context) CompoundStmt(Loc));
Destructor->setImplicitlyDefined(true);
Destructor->setUsed();
MarkVTableUsed(CurrentLocation, ClassDecl);
@@ -7322,15 +7201,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();
@@ -7345,44 +7215,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
@@ -7584,11 +7443,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), false);
+ return true;
// C++ [class.copy]p10:
// If the class definition does not explicitly declare a copy
@@ -7599,37 +7460,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;
}
}
@@ -7639,23 +7497,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
@@ -7664,8 +7535,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) {
@@ -7693,15 +7562,17 @@ Sema::ComputeDefaultedCopyAssignmentExceptionSpecAndConst(
FieldEnd = ClassDecl->field_end();
Field != FieldEnd;
++Field) {
- QualType FieldType = Context.getBaseElementType((*Field)->getType());
+ QualType FieldType = Context.getBaseElementType(Field->getType());
if (CXXRecordDecl *FieldClassDecl = FieldType->getAsCXXRecordDecl()) {
if (CXXMethodDecl *CopyAssign =
- LookupCopyingAssignment(FieldClassDecl, ArgQuals, false, 0))
+ LookupCopyingAssignment(FieldClassDecl,
+ ArgQuals | FieldType.getCVRQualifiers(),
+ false, 0))
ExceptSpec.CalledDecl(Field->getLocation(), CopyAssign);
}
}
- return std::make_pair(ExceptSpec, HasConstCopyAssignment);
+ return ExceptSpec;
}
CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) {
@@ -7710,26 +7581,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,
@@ -7738,7 +7602,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,
@@ -8076,9 +7946,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;
@@ -8103,7 +7974,7 @@ Sema::ComputeDefaultedMoveAssignmentExceptionSpec(CXXRecordDecl *ClassDecl) {
CXXRecordDecl *BaseClassDecl
= cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
if (CXXMethodDecl *MoveAssign = LookupMovingAssignment(BaseClassDecl,
- false, 0))
+ 0, false, 0))
ExceptSpec.CalledDecl(Base->getLocStart(), MoveAssign);
}
@@ -8113,7 +7984,7 @@ Sema::ComputeDefaultedMoveAssignmentExceptionSpec(CXXRecordDecl *ClassDecl) {
CXXRecordDecl *BaseClassDecl
= cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
if (CXXMethodDecl *MoveAssign = LookupMovingAssignment(BaseClassDecl,
- false, 0))
+ 0, false, 0))
ExceptSpec.CalledDecl(Base->getLocStart(), MoveAssign);
}
@@ -8121,10 +7992,12 @@ Sema::ComputeDefaultedMoveAssignmentExceptionSpec(CXXRecordDecl *ClassDecl) {
FieldEnd = ClassDecl->field_end();
Field != FieldEnd;
++Field) {
- QualType FieldType = Context.getBaseElementType((*Field)->getType());
+ QualType FieldType = Context.getBaseElementType(Field->getType());
if (CXXRecordDecl *FieldClassDecl = FieldType->getAsCXXRecordDecl()) {
- if (CXXMethodDecl *MoveAssign = LookupMovingAssignment(FieldClassDecl,
- false, 0))
+ if (CXXMethodDecl *MoveAssign =
+ LookupMovingAssignment(FieldClassDecl,
+ FieldType.getCVRQualifiers(),
+ false, 0))
ExceptSpec.CalledDecl(Field->getLocation(), MoveAssign);
}
}
@@ -8167,7 +8040,7 @@ hasMoveOrIsTriviallyCopyable(Sema &S, QualType Type, bool IsConstructor) {
// reference types, are supposed to return false here, but that appears
// to be a standard defect.
CXXRecordDecl *ClassDecl = Type->getAsCXXRecordDecl();
- if (!ClassDecl)
+ if (!ClassDecl || !ClassDecl->getDefinition())
return true;
if (Type.isTriviallyCopyableType(S.Context))
@@ -8209,7 +8082,7 @@ static bool subobjectsHaveMoveOrTrivialCopy(Sema &S, CXXRecordDecl *ClassDecl,
for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
FieldEnd = ClassDecl->field_end();
Field != FieldEnd; ++Field) {
- if (!hasMoveOrIsTriviallyCopyable(S, (*Field)->getType(), IsConstructor))
+ if (!hasMoveOrIsTriviallyCopyable(S, Field->getType(), IsConstructor))
return false;
}
@@ -8244,22 +8117,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,
@@ -8270,6 +8138,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,
@@ -8620,10 +8494,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), false);
+ return true;
// C++ [class.copy]p5:
// The implicitly-declared copy constructor for a class X will
@@ -8632,60 +8508,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;
@@ -8714,15 +8601,16 @@ Sema::ComputeDefaultedCopyCtorExceptionSpecAndConst(CXXRecordDecl *ClassDecl) {
FieldEnd = ClassDecl->field_end();
Field != FieldEnd;
++Field) {
- QualType FieldType = Context.getBaseElementType((*Field)->getType());
+ QualType FieldType = Context.getBaseElementType(Field->getType());
if (CXXRecordDecl *FieldClassDecl = FieldType->getAsCXXRecordDecl()) {
if (CXXConstructorDecl *CopyConstructor =
- LookupCopyingConstructor(FieldClassDecl, Quals))
+ LookupCopyingConstructor(FieldClassDecl,
+ Quals | FieldType.getCVRQualifiers()))
ExceptSpec.CalledDecl(Field->getLocation(), CopyConstructor);
}
}
- return std::make_pair(ExceptSpec, HasConstCopyConstructor);
+ return ExceptSpec;
}
CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor(
@@ -8731,18 +8619,16 @@ 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,
+ Const);
DeclarationName Name
= Context.DeclarationNames.getCXXConstructorName(
@@ -8753,15 +8639,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,
- /*isConstexpr=*/ClassDecl->defaultedCopyConstructorIsConstexpr() &&
- getLangOpts().CPlusPlus0x);
+ 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;
@@ -8825,7 +8716,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. [...]
@@ -8842,7 +8735,8 @@ Sema::ComputeDefaultedMoveCtorExceptionSpec(CXXRecordDecl *ClassDecl) {
if (const RecordType *BaseType = B->getType()->getAs<RecordType>()) {
CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(BaseType->getDecl());
- CXXConstructorDecl *Constructor = LookupMovingConstructor(BaseClassDecl);
+ CXXConstructorDecl *Constructor =
+ LookupMovingConstructor(BaseClassDecl, 0);
// If this is a deleted function, add it anyway. This might be conformant
// with the standard. This might not. I'm not sure. It might not matter.
if (Constructor)
@@ -8856,7 +8750,8 @@ Sema::ComputeDefaultedMoveCtorExceptionSpec(CXXRecordDecl *ClassDecl) {
B != BEnd; ++B) {
if (const RecordType *BaseType = B->getType()->getAs<RecordType>()) {
CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(BaseType->getDecl());
- CXXConstructorDecl *Constructor = LookupMovingConstructor(BaseClassDecl);
+ CXXConstructorDecl *Constructor =
+ LookupMovingConstructor(BaseClassDecl, 0);
// If this is a deleted function, add it anyway. This might be conformant
// with the standard. This might not. I'm not sure. It might not matter.
if (Constructor)
@@ -8868,10 +8763,10 @@ Sema::ComputeDefaultedMoveCtorExceptionSpec(CXXRecordDecl *ClassDecl) {
for (RecordDecl::field_iterator F = ClassDecl->field_begin(),
FEnd = ClassDecl->field_end();
F != FEnd; ++F) {
- if (const RecordType *RecordTy
- = Context.getBaseElementType(F->getType())->getAs<RecordType>()) {
- CXXRecordDecl *FieldRecDecl = cast<CXXRecordDecl>(RecordTy->getDecl());
- CXXConstructorDecl *Constructor = LookupMovingConstructor(FieldRecDecl);
+ QualType FieldType = Context.getBaseElementType(F->getType());
+ if (CXXRecordDecl *FieldRecDecl = FieldType->getAsCXXRecordDecl()) {
+ CXXConstructorDecl *Constructor =
+ LookupMovingConstructor(FieldRecDecl, FieldType.getCVRQualifiers());
// If this is a deleted function, add it anyway. This might be conformant
// with the standard. This might not. I'm not sure. It might not matter.
// In particular, the problem is that this function never gets called. It
@@ -8906,13 +8801,12 @@ 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,
+ false);
DeclarationName Name
= Context.DeclarationNames.getCXXConstructorName(
@@ -8924,15 +8818,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,
- /*isConstexpr=*/ClassDecl->defaultedMoveConstructorIsConstexpr() &&
- getLangOpts().CPlusPlus0x);
+ 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,
@@ -9046,8 +8945,7 @@ void Sema::DefineImplicitLambdaToFunctionPointerConversion(
// will fill in the actual details.
Invoke->setUsed();
Invoke->setReferenced();
- Invoke->setBody(new (Context) CompoundStmt(Context, 0, 0, Conv->getLocation(),
- Conv->getLocation()));
+ Invoke->setBody(new (Context) CompoundStmt(Conv->getLocation()));
if (ASTMutationListener *L = getASTMutationListener()) {
L->CompletedImplicitDefinition(Conv);
@@ -9171,13 +9069,6 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
unsigned NumExprs = ExprArgs.size();
Expr **Exprs = (Expr **)ExprArgs.release();
- for (specific_attr_iterator<NonNullAttr>
- i = Constructor->specific_attr_begin<NonNullAttr>(),
- e = Constructor->specific_attr_end<NonNullAttr>(); i != e; ++i) {
- const NonNullAttr *NonNull = *i;
- CheckNonNullArguments(NonNull, ExprArgs.get(), ConstructLoc);
- }
-
MarkFunctionReferenced(ConstructLoc, Constructor);
return Owned(CXXConstructExpr::Create(Context, DeclInitType, ConstructLoc,
Constructor, Elidable, Exprs, NumExprs,
@@ -9243,7 +9134,7 @@ void Sema::FinalizeVarWithDestructor(VarDecl *VD, const RecordType *Record) {
bool
Sema::CompleteConstructorCall(CXXConstructorDecl *Constructor,
MultiExprArg ArgsPtr,
- SourceLocation Loc,
+ SourceLocation Loc,
ASTOwningVector<Expr*> &ConvertedArgs,
bool AllowExplicit) {
// FIXME: This duplicates a lot of code from Sema::ConvertArgumentsForCall.
@@ -9271,7 +9162,8 @@ Sema::CompleteConstructorCall(CXXConstructorDecl *Constructor,
DiagnoseSentinelCalls(Constructor, Loc, AllArgs.data(), AllArgs.size());
- // FIXME: Missing call to CheckFunctionCall or equivalent
+ CheckConstructorCall(Constructor, AllArgs.data(), AllArgs.size(),
+ Proto, Loc);
return Invalid;
}
@@ -9329,7 +9221,7 @@ CheckOperatorNewDeleteTypes(Sema &SemaRef, const FunctionDecl *FnDecl,
diag::err_operator_new_delete_too_few_parameters)
<< FnDecl->getDeclName();
- // Check the the first parameter type is not dependent.
+ // Check the first parameter type is not dependent.
QualType FirstParamType = FnDecl->getParamDecl(0)->getType();
if (FirstParamType->isDependentType())
return SemaRef.Diag(FnDecl->getLocation(), DependentParamTypeDiag)
@@ -9568,7 +9460,7 @@ bool Sema::CheckLiteralOperatorDeclaration(FunctionDecl *FnDecl) {
TemplateParameterList *Params = TpDecl->getTemplateParameters();
if (Params->size() == 1) {
NonTypeTemplateParmDecl *PmDecl =
- cast<NonTypeTemplateParmDecl>(Params->getParam(0));
+ dyn_cast<NonTypeTemplateParmDecl>(Params->getParam(0));
// The template parameter must be a char parameter pack.
if (PmDecl && PmDecl->isTemplateParameterPack() &&
@@ -9769,7 +9661,8 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S,
Diag(Loc, diag::err_objc_object_catch);
Invalid = true;
} else if (T->isObjCObjectPointerType()) {
- if (!getLangOpts().ObjCNonFragileABI)
+ // FIXME: should this be a test for macosx-fragile specifically?
+ if (getLangOpts().ObjCRuntime.isFragile())
Diag(Loc, diag::warn_objc_pointer_cxx_catch_fragile);
}
}
@@ -9881,37 +9774,49 @@ Decl *Sema::ActOnExceptionDeclarator(Scope *S, Declarator &D) {
Decl *Sema::ActOnStaticAssertDeclaration(SourceLocation StaticAssertLoc,
Expr *AssertExpr,
- Expr *AssertMessageExpr_,
+ Expr *AssertMessageExpr,
SourceLocation RParenLoc) {
- StringLiteral *AssertMessage = cast<StringLiteral>(AssertMessageExpr_);
+ StringLiteral *AssertMessage = cast<StringLiteral>(AssertMessageExpr);
- if (!AssertExpr->isTypeDependent() && !AssertExpr->isValueDependent()) {
+ if (DiagnoseUnexpandedParameterPack(AssertExpr, UPPC_StaticAssertExpression))
+ return 0;
+
+ return BuildStaticAssertDeclaration(StaticAssertLoc, AssertExpr,
+ AssertMessage, RParenLoc, false);
+}
+
+Decl *Sema::BuildStaticAssertDeclaration(SourceLocation StaticAssertLoc,
+ Expr *AssertExpr,
+ StringLiteral *AssertMessage,
+ SourceLocation RParenLoc,
+ bool Failed) {
+ if (!AssertExpr->isTypeDependent() && !AssertExpr->isValueDependent() &&
+ !Failed) {
// In a static_assert-declaration, the constant-expression shall be a
// constant expression that can be contextually converted to bool.
ExprResult Converted = PerformContextuallyConvertToBool(AssertExpr);
if (Converted.isInvalid())
- return 0;
+ Failed = true;
llvm::APSInt Cond;
- if (VerifyIntegerConstantExpression(Converted.get(), &Cond,
- PDiag(diag::err_static_assert_expression_is_not_constant),
+ if (!Failed && VerifyIntegerConstantExpression(Converted.get(), &Cond,
+ diag::err_static_assert_expression_is_not_constant,
/*AllowFold=*/false).isInvalid())
- return 0;
+ Failed = true;
- if (!Cond) {
+ if (!Failed && !Cond) {
llvm::SmallString<256> MsgBuffer;
llvm::raw_svector_ostream Msg(MsgBuffer);
- AssertMessage->printPretty(Msg, Context, 0, getPrintingPolicy());
+ AssertMessage->printPretty(Msg, 0, getPrintingPolicy());
Diag(StaticAssertLoc, diag::err_static_assert_failed)
<< Msg.str() << AssertExpr->getSourceRange();
+ Failed = true;
}
}
- if (DiagnoseUnexpandedParameterPack(AssertExpr, UPPC_StaticAssertExpression))
- return 0;
-
Decl *Decl = StaticAssertDecl::Create(Context, CurContext, StaticAssertLoc,
- AssertExpr, AssertMessage, RParenLoc);
+ AssertExpr, AssertMessage, RParenLoc,
+ Failed);
CurContext->addDecl(Decl);
return Decl;
@@ -10116,7 +10021,7 @@ Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc,
/// friend class A<T>::B<unsigned>;
/// We permit this as a special case; if there are any template
/// parameters present at all, require proper matching, i.e.
-/// template <> template <class T> friend class A<int>::B;
+/// template <> template \<class T> friend class A<int>::B;
Decl *Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS,
MultiTemplateParamsArg TempParams) {
SourceLocation Loc = DS.getLocStart();
@@ -10438,9 +10343,11 @@ Decl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D,
FrD->setAccess(AS_public);
CurContext->addDecl(FrD);
- if (ND->isInvalidDecl())
+ if (ND->isInvalidDecl()) {
FrD->setInvalidDecl();
- else {
+ } else {
+ if (DC->isRecord()) CheckFriendAccess(ND);
+
FunctionDecl *FD;
if (FunctionTemplateDecl *FTD = dyn_cast<FunctionTemplateDecl>(ND))
FD = FTD->getTemplatedDecl();
@@ -10464,8 +10371,13 @@ void Sema::SetDeclDeleted(Decl *Dcl, SourceLocation DelLoc) {
return;
}
if (const FunctionDecl *Prev = Fn->getPreviousDecl()) {
- Diag(DelLoc, diag::err_deleted_decl_not_first);
- Diag(Prev->getLocation(), diag::note_previous_declaration);
+ // Don't consider the implicit declaration we generate for explicit
+ // specializations. FIXME: Do not generate these implicit declarations.
+ if ((Prev->getTemplateSpecializationKind() != TSK_ExplicitSpecialization
+ || Prev->getPreviousDecl()) && !Prev->isDefined()) {
+ Diag(DelLoc, diag::err_deleted_decl_not_first);
+ Diag(Prev->getLocation(), diag::note_previous_declaration);
+ }
// If the declaration wasn't the first, we delete the function anyway for
// recovery.
}
@@ -10531,10 +10443,11 @@ void Sema::SetDeclDefaulted(Decl *Dcl, SourceLocation DefaultLoc) {
if (Primary == Primary->getCanonicalDecl())
return;
+ CheckExplicitlyDefaultedSpecialMember(MD);
+
switch (Member) {
case CXXDefaultConstructor: {
CXXConstructorDecl *CD = cast<CXXConstructorDecl>(MD);
- CheckExplicitlyDefaultedDefaultConstructor(CD);
if (!CD->isInvalidDecl())
DefineImplicitDefaultConstructor(DefaultLoc, CD);
break;
@@ -10542,14 +10455,12 @@ void Sema::SetDeclDefaulted(Decl *Dcl, SourceLocation DefaultLoc) {
case CXXCopyConstructor: {
CXXConstructorDecl *CD = cast<CXXConstructorDecl>(MD);
- CheckExplicitlyDefaultedCopyConstructor(CD);
if (!CD->isInvalidDecl())
DefineImplicitCopyConstructor(DefaultLoc, CD);
break;
}
case CXXCopyAssignment: {
- CheckExplicitlyDefaultedCopyAssignment(MD);
if (!MD->isInvalidDecl())
DefineImplicitCopyAssignment(DefaultLoc, MD);
break;
@@ -10557,7 +10468,6 @@ void Sema::SetDeclDefaulted(Decl *Dcl, SourceLocation DefaultLoc) {
case CXXDestructor: {
CXXDestructorDecl *DD = cast<CXXDestructorDecl>(MD);
- CheckExplicitlyDefaultedDestructor(DD);
if (!DD->isInvalidDecl())
DefineImplicitDestructor(DefaultLoc, DD);
break;
@@ -10565,14 +10475,12 @@ void Sema::SetDeclDefaulted(Decl *Dcl, SourceLocation DefaultLoc) {
case CXXMoveConstructor: {
CXXConstructorDecl *CD = cast<CXXConstructorDecl>(MD);
- CheckExplicitlyDefaultedMoveConstructor(CD);
if (!CD->isInvalidDecl())
DefineImplicitMoveConstructor(DefaultLoc, CD);
break;
}
case CXXMoveAssignment: {
- CheckExplicitlyDefaultedMoveAssignment(MD);
if (!MD->isInvalidDecl())
DefineImplicitMoveAssignment(DefaultLoc, MD);
break;
@@ -10650,8 +10558,8 @@ bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New,
if (const RecordType *RT = NewClassTy->getAs<RecordType>()) {
if (!RT->isBeingDefined() &&
RequireCompleteType(New->getLocation(), NewClassTy,
- PDiag(diag::err_covariant_return_incomplete)
- << New->getDeclName()))
+ diag::err_covariant_return_incomplete,
+ New->getDeclName()))
return true;
}
@@ -10857,7 +10765,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) {
@@ -10867,6 +10775,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.
@@ -10877,7 +10787,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:
@@ -10906,7 +10817,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
@@ -10935,6 +10854,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.
@@ -11171,8 +11098,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:
@@ -11299,7 +11226,7 @@ Sema::checkExceptionSpecification(ExceptionSpecificationType EST,
if (!NoexceptExpr->isValueDependent())
NoexceptExpr = VerifyIntegerConstantExpression(NoexceptExpr, 0,
- PDiag(diag::err_noexcept_needs_constant_expression),
+ diag::err_noexcept_needs_constant_expression,
/*AllowFold*/ false).take();
EPI.NoexceptExpr = NoexceptExpr;
}
OpenPOWER on IntegriCloud