summaryrefslogtreecommitdiff
path: root/lib/Sema/SemaDeclCXX.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2017-04-16 16:02:28 +0000
committerDimitry Andric <dim@FreeBSD.org>2017-04-16 16:02:28 +0000
commit7442d6faa2719e4e7d33a7021c406c5a4facd74d (patch)
treec72b9241553fc9966179aba84f90f17bfa9235c3 /lib/Sema/SemaDeclCXX.cpp
parentb52119637f743680a99710ce5fdb6646da2772af (diff)
downloadsrc-test2-7442d6faa2719e4e7d33a7021c406c5a4facd74d.tar.gz
src-test2-7442d6faa2719e4e7d33a7021c406c5a4facd74d.zip
Notes
Diffstat (limited to 'lib/Sema/SemaDeclCXX.cpp')
-rw-r--r--lib/Sema/SemaDeclCXX.cpp1057
1 files changed, 552 insertions, 505 deletions
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index f265f4c00f71..fd3f266c9a08 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -467,7 +467,7 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old,
// If only one of these is a local function declaration, then they are
// declared in different scopes, even though isDeclInScope may think
// they're in the same scope. (If both are local, the scope check is
- // sufficent, and if neither is local, then they are in the same scope.)
+ // sufficient, and if neither is local, then they are in the same scope.)
continue;
}
@@ -647,6 +647,17 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old,
Invalid = true;
}
+ // FIXME: It's not clear what should happen if multiple declarations of a
+ // deduction guide have different explicitness. For now at least we simply
+ // reject any case where the explicitness changes.
+ auto *NewGuide = dyn_cast<CXXDeductionGuideDecl>(New);
+ if (NewGuide && NewGuide->isExplicitSpecified() !=
+ cast<CXXDeductionGuideDecl>(Old)->isExplicitSpecified()) {
+ Diag(New->getLocation(), diag::err_deduction_guide_explicit_mismatch)
+ << NewGuide->isExplicitSpecified();
+ Diag(Old->getLocation(), diag::note_previous_declaration);
+ }
+
// C++11 [dcl.fct.default]p4: If a friend declaration specifies a default
// argument expression, that declaration shall be a definition and shall be
// the only declaration of the function or function template in the
@@ -970,7 +981,8 @@ namespace { enum class IsTupleLike { TupleLike, NotTupleLike, Error }; }
static IsTupleLike isTupleLike(Sema &S, SourceLocation Loc, QualType T,
llvm::APSInt &Size) {
- EnterExpressionEvaluationContext ContextRAII(S, Sema::ConstantEvaluated);
+ EnterExpressionEvaluationContext ContextRAII(
+ S, Sema::ExpressionEvaluationContext::ConstantEvaluated);
DeclarationName Value = S.PP.getIdentifierInfo("value");
LookupResult R(S, Value, Loc, Sema::LookupOrdinaryName);
@@ -2705,8 +2717,7 @@ void Sema::DiagnoseAbsenceOfOverrideControl(NamedDecl *D) {
if (D->isInvalidDecl() || D->hasAttr<OverrideAttr>())
return;
CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D);
- if (!MD || MD->isImplicit() || MD->hasAttr<FinalAttr>() ||
- isa<CXXDestructorDecl>(MD))
+ if (!MD || MD->isImplicit() || MD->hasAttr<FinalAttr>())
return;
SourceLocation Loc = MD->getLocation();
@@ -2716,10 +2727,12 @@ void Sema::DiagnoseAbsenceOfOverrideControl(NamedDecl *D) {
SpellingLoc = getSourceManager().getSpellingLoc(SpellingLoc);
if (SpellingLoc.isValid() && getSourceManager().isInSystemHeader(SpellingLoc))
return;
-
+
if (MD->size_overridden_methods() > 0) {
- Diag(MD->getLocation(), diag::warn_function_marked_not_override_overriding)
- << MD->getDeclName();
+ unsigned DiagID = isa<CXXDestructorDecl>(MD)
+ ? diag::warn_destructor_marked_not_override_overriding
+ : diag::warn_function_marked_not_override_overriding;
+ Diag(MD->getLocation(), DiagID) << MD->getDeclName();
const CXXMethodDecl *OMD = *MD->begin_overridden_methods();
Diag(OMD->getLocation(), diag::note_overridden_virtual_function);
}
@@ -2758,6 +2771,56 @@ static AttributeList *getMSPropertyAttr(AttributeList *list) {
return nullptr;
}
+// Check if there is a field shadowing.
+void Sema::CheckShadowInheritedFields(const SourceLocation &Loc,
+ DeclarationName FieldName,
+ const CXXRecordDecl *RD) {
+ if (Diags.isIgnored(diag::warn_shadow_field, Loc))
+ return;
+
+ // To record a shadowed field in a base
+ std::map<CXXRecordDecl*, NamedDecl*> Bases;
+ auto FieldShadowed = [&](const CXXBaseSpecifier *Specifier,
+ CXXBasePath &Path) {
+ const auto Base = Specifier->getType()->getAsCXXRecordDecl();
+ // Record an ambiguous path directly
+ if (Bases.find(Base) != Bases.end())
+ return true;
+ for (const auto Field : Base->lookup(FieldName)) {
+ if ((isa<FieldDecl>(Field) || isa<IndirectFieldDecl>(Field)) &&
+ Field->getAccess() != AS_private) {
+ assert(Field->getAccess() != AS_none);
+ assert(Bases.find(Base) == Bases.end());
+ Bases[Base] = Field;
+ return true;
+ }
+ }
+ return false;
+ };
+
+ CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
+ /*DetectVirtual=*/true);
+ if (!RD->lookupInBases(FieldShadowed, Paths))
+ return;
+
+ for (const auto &P : Paths) {
+ auto Base = P.back().Base->getType()->getAsCXXRecordDecl();
+ auto It = Bases.find(Base);
+ // Skip duplicated bases
+ if (It == Bases.end())
+ continue;
+ auto BaseField = It->second;
+ assert(BaseField->getAccess() != AS_private);
+ if (AS_none !=
+ CXXRecordDecl::MergeAccess(P.Access, BaseField->getAccess())) {
+ Diag(Loc, diag::warn_shadow_field)
+ << FieldName.getAsString() << RD->getName() << Base->getName();
+ Diag(BaseField->getLocation(), diag::note_shadow_field);
+ Bases.erase(It);
+ }
+ }
+}
+
/// 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
@@ -2957,6 +3020,8 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
if (!Member)
return nullptr;
}
+
+ CheckShadowInheritedFields(Loc, Name, cast<CXXRecordDecl>(CurContext));
} else {
Member = HandleDeclarator(S, D, TemplateParameterLists);
if (!Member)
@@ -3673,6 +3738,9 @@ Sema::BuildMemInitializer(Decl *ConstructorD,
BaseType = GetTypeFromParser(TemplateTypeTy, &TInfo);
} else if (DS.getTypeSpecType() == TST_decltype) {
BaseType = BuildDecltypeType(DS.getRepAsExpr(), DS.getTypeSpecTypeLoc());
+ } else if (DS.getTypeSpecType() == TST_decltype_auto) {
+ Diag(DS.getTypeSpecTypeLoc(), diag::err_decltype_auto_invalid);
+ return true;
} else {
LookupResult R(*this, MemberOrBase, IdLoc, LookupOrdinaryName);
LookupParsedName(R, S, &SS);
@@ -4332,11 +4400,8 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
}
}
- if (SemaRef.getLangOpts().ObjCAutoRefCount &&
- FieldBaseElementType->isObjCRetainableType() &&
- FieldBaseElementType.getObjCLifetime() != Qualifiers::OCL_None &&
- FieldBaseElementType.getObjCLifetime() != Qualifiers::OCL_ExplicitNone) {
- // ARC:
+ if (FieldBaseElementType.hasNonTrivialObjCLifetime()) {
+ // ARC and Weak:
// Default-initialize Objective-C pointers to NULL.
CXXMemberInit
= new (SemaRef.Context) CXXCtorInitializer(SemaRef.Context, Field,
@@ -5015,6 +5080,10 @@ Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location,
DiagnoseUseOfDecl(Dtor, Location);
}
+ // We only potentially invoke the destructors of potentially constructed
+ // subobjects.
+ bool VisitVirtualBases = !ClassDecl->isAbstract();
+
llvm::SmallPtrSet<const RecordType *, 8> DirectVirtualBases;
// Bases.
@@ -5023,8 +5092,11 @@ Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location,
const RecordType *RT = Base.getType()->getAs<RecordType>();
// Remember direct virtual bases.
- if (Base.isVirtual())
+ if (Base.isVirtual()) {
+ if (!VisitVirtualBases)
+ continue;
DirectVirtualBases.insert(RT);
+ }
CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(RT->getDecl());
// If our base class is invalid, we probably can't get its dtor anyway.
@@ -5046,6 +5118,9 @@ Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location,
MarkFunctionReferenced(Location, Dtor);
DiagnoseUseOfDecl(Dtor, Location);
}
+
+ if (!VisitVirtualBases)
+ return;
// Virtual bases.
for (const auto &VBase : ClassDecl->vbases()) {
@@ -5378,7 +5453,7 @@ static void ReferenceDllExportedMethods(Sema &S, CXXRecordDecl *Class) {
// Synthesize and instantiate non-trivial implicit methods, explicitly
// defaulted methods, and the copy and move assignment operators. The
// latter are exported even if they are trivial, because the address of
- // an operator can be taken and should compare equal accross libraries.
+ // an operator can be taken and should compare equal across libraries.
DiagnosticErrorTrap Trap(S.Diags);
S.MarkFunctionReferenced(Class->getLocation(), MD);
if (Trap.hasErrorOccurred()) {
@@ -5786,7 +5861,7 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
/// \param ConstRHS True if this is a copy operation with a const object
/// on its RHS, that is, if the argument to the outer special member
/// function is 'const' and this is not a field marked 'mutable'.
-static Sema::SpecialMemberOverloadResult *lookupCallFromSpecialMember(
+static Sema::SpecialMemberOverloadResult lookupCallFromSpecialMember(
Sema &S, CXXRecordDecl *Class, Sema::CXXSpecialMember CSM,
unsigned FieldQuals, bool ConstRHS) {
unsigned LHSQuals = 0;
@@ -5909,13 +5984,13 @@ specialMemberIsConstexpr(Sema &S, CXXRecordDecl *ClassDecl,
if (CSM == Sema::CXXDefaultConstructor)
return ClassDecl->hasConstexprDefaultConstructor();
- Sema::SpecialMemberOverloadResult *SMOR =
+ Sema::SpecialMemberOverloadResult SMOR =
lookupCallFromSpecialMember(S, ClassDecl, CSM, Quals, ConstRHS);
- if (!SMOR || !SMOR->getMethod())
+ if (!SMOR.getMethod())
// A constructor we wouldn't select can't be "involved in initializing"
// anything.
return true;
- return SMOR->getMethod()->isConstexpr();
+ return SMOR.getMethod()->isConstexpr();
}
/// Determine whether the specified special member function would be constexpr
@@ -6025,27 +6100,23 @@ static bool defaultedSpecialMemberIsConstexpr(
}
static Sema::ImplicitExceptionSpecification
+ComputeDefaultedSpecialMemberExceptionSpec(
+ Sema &S, SourceLocation Loc, CXXMethodDecl *MD, Sema::CXXSpecialMember CSM,
+ Sema::InheritedConstructorInfo *ICI);
+
+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;
- }
- assert(cast<CXXConstructorDecl>(MD)->getInheritedConstructor() &&
+ auto CSM = S.getSpecialMember(MD);
+ if (CSM != Sema::CXXInvalid)
+ return ComputeDefaultedSpecialMemberExceptionSpec(S, Loc, MD, CSM, nullptr);
+
+ auto *CD = cast<CXXConstructorDecl>(MD);
+ assert(CD->getInheritedConstructor() &&
"only special members have implicit exception specs");
- return S.ComputeInheritingCtorExceptionSpec(Loc,
- cast<CXXConstructorDecl>(MD));
+ Sema::InheritedConstructorInfo ICI(
+ S, Loc, CD->getInheritedConstructor().getShadowDecl());
+ return ComputeDefaultedSpecialMemberExceptionSpec(
+ S, Loc, CD, Sema::CXXDefaultConstructor, &ICI);
}
static FunctionProtoType::ExtProtoInfo getImplicitMethodEPI(Sema &S,
@@ -6300,45 +6371,35 @@ void Sema::CheckDelayedMemberExceptionSpecs() {
}
namespace {
-struct SpecialMemberDeletionInfo {
+/// CRTP base class for visiting operations performed by a special member
+/// function (or inherited constructor).
+template<typename Derived>
+struct SpecialMemberVisitor {
Sema &S;
CXXMethodDecl *MD;
Sema::CXXSpecialMember CSM;
Sema::InheritedConstructorInfo *ICI;
- bool Diagnose;
// Properties of the special member, computed for convenience.
- bool IsConstructor, IsAssignment, IsMove, ConstArg;
- SourceLocation Loc;
-
- bool AllFieldsAreConst;
+ bool IsConstructor = false, IsAssignment = false, ConstArg = false;
- SpecialMemberDeletionInfo(Sema &S, CXXMethodDecl *MD,
- Sema::CXXSpecialMember CSM,
- Sema::InheritedConstructorInfo *ICI, bool Diagnose)
- : S(S), MD(MD), CSM(CSM), ICI(ICI), Diagnose(Diagnose),
- IsConstructor(false), IsAssignment(false), IsMove(false),
- ConstArg(false), Loc(MD->getLocation()), AllFieldsAreConst(true) {
+ SpecialMemberVisitor(Sema &S, CXXMethodDecl *MD, Sema::CXXSpecialMember CSM,
+ Sema::InheritedConstructorInfo *ICI)
+ : S(S), MD(MD), CSM(CSM), ICI(ICI) {
switch (CSM) {
- case Sema::CXXDefaultConstructor:
- case Sema::CXXCopyConstructor:
- IsConstructor = true;
- break;
- case Sema::CXXMoveConstructor:
- IsConstructor = true;
- IsMove = true;
- break;
- case Sema::CXXCopyAssignment:
- IsAssignment = true;
- break;
- case Sema::CXXMoveAssignment:
- IsAssignment = true;
- IsMove = true;
- break;
- case Sema::CXXDestructor:
- break;
- case Sema::CXXInvalid:
- llvm_unreachable("invalid special member kind");
+ case Sema::CXXDefaultConstructor:
+ case Sema::CXXCopyConstructor:
+ case Sema::CXXMoveConstructor:
+ IsConstructor = true;
+ break;
+ case Sema::CXXCopyAssignment:
+ case Sema::CXXMoveAssignment:
+ IsAssignment = true;
+ break;
+ case Sema::CXXDestructor:
+ break;
+ case Sema::CXXInvalid:
+ llvm_unreachable("invalid special member kind");
}
if (MD->getNumParams()) {
@@ -6348,21 +6409,109 @@ struct SpecialMemberDeletionInfo {
}
}
- bool inUnion() const { return MD->getParent()->isUnion(); }
+ Derived &getDerived() { return static_cast<Derived&>(*this); }
- Sema::CXXSpecialMember getEffectiveCSM() {
- return ICI ? Sema::CXXInvalid : CSM;
+ /// Is this a "move" special member?
+ bool isMove() const {
+ return CSM == Sema::CXXMoveConstructor || CSM == Sema::CXXMoveAssignment;
}
/// Look up the corresponding special member in the given class.
- Sema::SpecialMemberOverloadResult *lookupIn(CXXRecordDecl *Class,
- unsigned Quals, bool IsMutable) {
+ Sema::SpecialMemberOverloadResult lookupIn(CXXRecordDecl *Class,
+ unsigned Quals, bool IsMutable) {
return lookupCallFromSpecialMember(S, Class, CSM, Quals,
ConstArg && !IsMutable);
}
+ /// Look up the constructor for the specified base class to see if it's
+ /// overridden due to this being an inherited constructor.
+ Sema::SpecialMemberOverloadResult lookupInheritedCtor(CXXRecordDecl *Class) {
+ if (!ICI)
+ return {};
+ assert(CSM == Sema::CXXDefaultConstructor);
+ auto *BaseCtor =
+ cast<CXXConstructorDecl>(MD)->getInheritedConstructor().getConstructor();
+ if (auto *MD = ICI->findConstructorForBase(Class, BaseCtor).first)
+ return MD;
+ return {};
+ }
+
+ /// A base or member subobject.
typedef llvm::PointerUnion<CXXBaseSpecifier*, FieldDecl*> Subobject;
+ /// Get the location to use for a subobject in diagnostics.
+ static SourceLocation getSubobjectLoc(Subobject Subobj) {
+ // FIXME: For an indirect virtual base, the direct base leading to
+ // the indirect virtual base would be a more useful choice.
+ if (auto *B = Subobj.dyn_cast<CXXBaseSpecifier*>())
+ return B->getBaseTypeLoc();
+ else
+ return Subobj.get<FieldDecl*>()->getLocation();
+ }
+
+ enum BasesToVisit {
+ /// Visit all non-virtual (direct) bases.
+ VisitNonVirtualBases,
+ /// Visit all direct bases, virtual or not.
+ VisitDirectBases,
+ /// Visit all non-virtual bases, and all virtual bases if the class
+ /// is not abstract.
+ VisitPotentiallyConstructedBases,
+ /// Visit all direct or virtual bases.
+ VisitAllBases
+ };
+
+ // Visit the bases and members of the class.
+ bool visit(BasesToVisit Bases) {
+ CXXRecordDecl *RD = MD->getParent();
+
+ if (Bases == VisitPotentiallyConstructedBases)
+ Bases = RD->isAbstract() ? VisitNonVirtualBases : VisitAllBases;
+
+ for (auto &B : RD->bases())
+ if ((Bases == VisitDirectBases || !B.isVirtual()) &&
+ getDerived().visitBase(&B))
+ return true;
+
+ if (Bases == VisitAllBases)
+ for (auto &B : RD->vbases())
+ if (getDerived().visitBase(&B))
+ return true;
+
+ for (auto *F : RD->fields())
+ if (!F->isInvalidDecl() && !F->isUnnamedBitfield() &&
+ getDerived().visitField(F))
+ return true;
+
+ return false;
+ }
+};
+}
+
+namespace {
+struct SpecialMemberDeletionInfo
+ : SpecialMemberVisitor<SpecialMemberDeletionInfo> {
+ bool Diagnose;
+
+ SourceLocation Loc;
+
+ bool AllFieldsAreConst;
+
+ SpecialMemberDeletionInfo(Sema &S, CXXMethodDecl *MD,
+ Sema::CXXSpecialMember CSM,
+ Sema::InheritedConstructorInfo *ICI, bool Diagnose)
+ : SpecialMemberVisitor(S, MD, CSM, ICI), Diagnose(Diagnose),
+ Loc(MD->getLocation()), AllFieldsAreConst(true) {}
+
+ bool inUnion() const { return MD->getParent()->isUnion(); }
+
+ Sema::CXXSpecialMember getEffectiveCSM() {
+ return ICI ? Sema::CXXInvalid : CSM;
+ }
+
+ bool visitBase(CXXBaseSpecifier *Base) { return shouldDeleteForBase(Base); }
+ bool visitField(FieldDecl *Field) { return shouldDeleteForField(Field); }
+
bool shouldDeleteForBase(CXXBaseSpecifier *Base);
bool shouldDeleteForField(FieldDecl *FD);
bool shouldDeleteForAllConstMembers();
@@ -6370,7 +6519,7 @@ struct SpecialMemberDeletionInfo {
bool shouldDeleteForClassSubobject(CXXRecordDecl *Class, Subobject Subobj,
unsigned Quals);
bool shouldDeleteForSubobjectCall(Subobject Subobj,
- Sema::SpecialMemberOverloadResult *SMOR,
+ Sema::SpecialMemberOverloadResult SMOR,
bool IsDtorCallInCtor);
bool isAccessible(Subobject Subobj, CXXMethodDecl *D);
@@ -6400,16 +6549,16 @@ bool SpecialMemberDeletionInfo::isAccessible(Subobject Subobj,
/// Check whether we should delete a special member due to the implicit
/// definition containing a call to a special member of a subobject.
bool SpecialMemberDeletionInfo::shouldDeleteForSubobjectCall(
- Subobject Subobj, Sema::SpecialMemberOverloadResult *SMOR,
+ Subobject Subobj, Sema::SpecialMemberOverloadResult SMOR,
bool IsDtorCallInCtor) {
- CXXMethodDecl *Decl = SMOR->getMethod();
+ CXXMethodDecl *Decl = SMOR.getMethod();
FieldDecl *Field = Subobj.dyn_cast<FieldDecl*>();
int DiagKind = -1;
- if (SMOR->getKind() == Sema::SpecialMemberOverloadResult::NoMemberOrDeleted)
+ if (SMOR.getKind() == Sema::SpecialMemberOverloadResult::NoMemberOrDeleted)
DiagKind = !Decl ? 0 : 1;
- else if (SMOR->getKind() == Sema::SpecialMemberOverloadResult::Ambiguous)
+ else if (SMOR.getKind() == Sema::SpecialMemberOverloadResult::Ambiguous)
DiagKind = 2;
else if (!isAccessible(Subobj, Decl))
DiagKind = 3;
@@ -6479,7 +6628,7 @@ bool SpecialMemberDeletionInfo::shouldDeleteForClassSubobject(
// -- any direct or virtual base class or non-static data member has a
// type with a destructor that is deleted or inaccessible
if (IsConstructor) {
- Sema::SpecialMemberOverloadResult *SMOR =
+ Sema::SpecialMemberOverloadResult SMOR =
S.LookupSpecialMember(Class, Sema::CXXDestructor,
false, false, false, false, false);
if (shouldDeleteForSubobjectCall(Subobj, SMOR, true))
@@ -6499,23 +6648,20 @@ bool SpecialMemberDeletionInfo::shouldDeleteForBase(CXXBaseSpecifier *Base) {
return false;
// If we have an inheriting constructor, check whether we're calling an
// inherited constructor instead of a default constructor.
- if (ICI) {
- assert(CSM == Sema::CXXDefaultConstructor);
- auto *BaseCtor =
- ICI->findConstructorForBase(BaseClass, cast<CXXConstructorDecl>(MD)
- ->getInheritedConstructor()
- .getConstructor())
- .first;
- if (BaseCtor) {
- if (BaseCtor->isDeleted() && Diagnose) {
- S.Diag(Base->getLocStart(),
- diag::note_deleted_special_member_class_subobject)
- << getEffectiveCSM() << MD->getParent() << /*IsField*/false
- << Base->getType() << /*Deleted*/1 << /*IsDtorCallInCtor*/false;
- S.NoteDeletedFunction(BaseCtor);
- }
- return BaseCtor->isDeleted();
+ Sema::SpecialMemberOverloadResult SMOR = lookupInheritedCtor(BaseClass);
+ if (auto *BaseCtor = SMOR.getMethod()) {
+ // Note that we do not check access along this path; other than that,
+ // this is the same as shouldDeleteForSubobjectCall(Base, BaseCtor, false);
+ // FIXME: Check that the base has a usable destructor! Sink this into
+ // shouldDeleteForClassSubobject.
+ if (BaseCtor->isDeleted() && Diagnose) {
+ S.Diag(Base->getLocStart(),
+ diag::note_deleted_special_member_class_subobject)
+ << getEffectiveCSM() << MD->getParent() << /*IsField*/false
+ << Base->getType() << /*Deleted*/1 << /*IsDtorCallInCtor*/false;
+ S.NoteDeletedFunction(BaseCtor);
}
+ return BaseCtor->isDeleted();
}
return shouldDeleteForClassSubobject(BaseClass, Base, 0);
}
@@ -6564,7 +6710,7 @@ bool SpecialMemberDeletionInfo::shouldDeleteForField(FieldDecl *FD) {
if (FieldType->isReferenceType()) {
if (Diagnose)
S.Diag(FD->getLocation(), diag::note_deleted_assign_field)
- << IsMove << MD->getParent() << FD << FieldType << /*Reference*/0;
+ << isMove() << MD->getParent() << FD << FieldType << /*Reference*/0;
return true;
}
if (!FieldRecord && FieldType.isConstQualified()) {
@@ -6572,7 +6718,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 << FD->getType() << /*Const*/1;
+ << isMove() << MD->getParent() << FD << FD->getType() << /*Const*/1;
return true;
}
}
@@ -6743,24 +6889,15 @@ bool Sema::ShouldDeleteSpecialMember(CXXMethodDecl *MD, CXXSpecialMember CSM,
SpecialMemberDeletionInfo SMI(*this, MD, CSM, ICI, Diagnose);
- for (auto &BI : RD->bases())
- if ((SMI.IsAssignment || !BI.isVirtual()) &&
- SMI.shouldDeleteForBase(&BI))
- return true;
-
// Per DR1611, do not consider virtual bases of constructors of abstract
- // classes, since we are not going to construct them. For assignment
- // operators, we only assign (and thus only consider) direct bases.
- if ((!RD->isAbstract() || !SMI.IsConstructor) && !SMI.IsAssignment) {
- for (auto &BI : RD->vbases())
- if (SMI.shouldDeleteForBase(&BI))
- return true;
- }
-
- for (auto *FI : RD->fields())
- if (!FI->isInvalidDecl() && !FI->isUnnamedBitfield() &&
- SMI.shouldDeleteForField(FI))
- return true;
+ // classes, since we are not going to construct them.
+ // Per DR1658, do not consider virtual bases of destructors of abstract
+ // classes either.
+ // Per DR2180, for assignment operators we only assign (and thus only
+ // consider) direct bases.
+ if (SMI.visit(SMI.IsAssignment ? SMI.VisitDirectBases
+ : SMI.VisitPotentiallyConstructedBases))
+ return true;
if (SMI.shouldDeleteForAllConstMembers())
return true;
@@ -6874,18 +7011,18 @@ static bool findTrivialSpecialMember(Sema &S, CXXRecordDecl *RD,
case Sema::CXXMoveConstructor:
case Sema::CXXMoveAssignment:
NeedOverloadResolution:
- Sema::SpecialMemberOverloadResult *SMOR =
+ Sema::SpecialMemberOverloadResult SMOR =
lookupCallFromSpecialMember(S, RD, CSM, Quals, ConstRHS);
// The standard doesn't describe how to behave if the lookup is ambiguous.
// We treat it as not making the member non-trivial, just like the standard
// mandates for the default constructor. This should rarely matter, because
// the member will also be deleted.
- if (SMOR->getKind() == Sema::SpecialMemberOverloadResult::Ambiguous)
+ if (SMOR.getKind() == Sema::SpecialMemberOverloadResult::Ambiguous)
return true;
- if (!SMOR->getMethod()) {
- assert(SMOR->getKind() ==
+ if (!SMOR.getMethod()) {
+ assert(SMOR.getKind() ==
Sema::SpecialMemberOverloadResult::NoMemberOrDeleted);
return false;
}
@@ -6893,8 +7030,8 @@ static bool findTrivialSpecialMember(Sema &S, CXXRecordDecl *RD,
// We deliberately don't check if we found a deleted special member. We're
// not supposed to!
if (Selected)
- *Selected = SMOR->getMethod();
- return SMOR->getMethod()->isTrivial();
+ *Selected = SMOR.getMethod();
+ return SMOR.getMethod()->isTrivial();
}
llvm_unreachable("unknown special method kind");
@@ -7009,8 +7146,7 @@ static bool checkTrivialClassMembers(Sema &S, CXXRecordDecl *RD,
// [...] nontrivally ownership-qualified types are [...] not trivially
// default constructible, copy constructible, move constructible, copy
// assignable, move assignable, or destructible [...]
- if (S.getLangOpts().ObjCAutoRefCount &&
- FieldType.hasNonTrivialObjCLifetime()) {
+ if (FieldType.hasNonTrivialObjCLifetime()) {
if (Diagnose)
S.Diag(FI->getLocation(), diag::note_nontrivial_objc_ownership)
<< RD << FieldType.getObjCLifetime();
@@ -8033,6 +8169,154 @@ Decl *Sema::ActOnConversionDeclarator(CXXConversionDecl *Conversion) {
return Conversion;
}
+namespace {
+/// Utility class to accumulate and print a diagnostic listing the invalid
+/// specifier(s) on a declaration.
+struct BadSpecifierDiagnoser {
+ BadSpecifierDiagnoser(Sema &S, SourceLocation Loc, unsigned DiagID)
+ : S(S), Diagnostic(S.Diag(Loc, DiagID)) {}
+ ~BadSpecifierDiagnoser() {
+ Diagnostic << Specifiers;
+ }
+
+ template<typename T> void check(SourceLocation SpecLoc, T Spec) {
+ return check(SpecLoc, DeclSpec::getSpecifierName(Spec));
+ }
+ void check(SourceLocation SpecLoc, DeclSpec::TST Spec) {
+ return check(SpecLoc,
+ DeclSpec::getSpecifierName(Spec, S.getPrintingPolicy()));
+ }
+ void check(SourceLocation SpecLoc, const char *Spec) {
+ if (SpecLoc.isInvalid()) return;
+ Diagnostic << SourceRange(SpecLoc, SpecLoc);
+ if (!Specifiers.empty()) Specifiers += " ";
+ Specifiers += Spec;
+ }
+
+ Sema &S;
+ Sema::SemaDiagnosticBuilder Diagnostic;
+ std::string Specifiers;
+};
+}
+
+/// Check the validity of a declarator that we parsed for a deduction-guide.
+/// These aren't actually declarators in the grammar, so we need to check that
+/// the user didn't specify any pieces that are not part of the deduction-guide
+/// grammar.
+void Sema::CheckDeductionGuideDeclarator(Declarator &D, QualType &R,
+ StorageClass &SC) {
+ TemplateName GuidedTemplate = D.getName().TemplateName.get().get();
+ TemplateDecl *GuidedTemplateDecl = GuidedTemplate.getAsTemplateDecl();
+ assert(GuidedTemplateDecl && "missing template decl for deduction guide");
+
+ // C++ [temp.deduct.guide]p3:
+ // A deduction-gide shall be declared in the same scope as the
+ // corresponding class template.
+ if (!CurContext->getRedeclContext()->Equals(
+ GuidedTemplateDecl->getDeclContext()->getRedeclContext())) {
+ Diag(D.getIdentifierLoc(), diag::err_deduction_guide_wrong_scope)
+ << GuidedTemplateDecl;
+ Diag(GuidedTemplateDecl->getLocation(), diag::note_template_decl_here);
+ }
+
+ auto &DS = D.getMutableDeclSpec();
+ // We leave 'friend' and 'virtual' to be rejected in the normal way.
+ if (DS.hasTypeSpecifier() || DS.getTypeQualifiers() ||
+ DS.getStorageClassSpecLoc().isValid() || DS.isInlineSpecified() ||
+ DS.isNoreturnSpecified() || DS.isConstexprSpecified() ||
+ DS.isConceptSpecified()) {
+ BadSpecifierDiagnoser Diagnoser(
+ *this, D.getIdentifierLoc(),
+ diag::err_deduction_guide_invalid_specifier);
+
+ Diagnoser.check(DS.getStorageClassSpecLoc(), DS.getStorageClassSpec());
+ DS.ClearStorageClassSpecs();
+ SC = SC_None;
+
+ // 'explicit' is permitted.
+ Diagnoser.check(DS.getInlineSpecLoc(), "inline");
+ Diagnoser.check(DS.getNoreturnSpecLoc(), "_Noreturn");
+ Diagnoser.check(DS.getConstexprSpecLoc(), "constexpr");
+ Diagnoser.check(DS.getConceptSpecLoc(), "concept");
+ DS.ClearConstexprSpec();
+ DS.ClearConceptSpec();
+
+ Diagnoser.check(DS.getConstSpecLoc(), "const");
+ Diagnoser.check(DS.getRestrictSpecLoc(), "__restrict");
+ Diagnoser.check(DS.getVolatileSpecLoc(), "volatile");
+ Diagnoser.check(DS.getAtomicSpecLoc(), "_Atomic");
+ Diagnoser.check(DS.getUnalignedSpecLoc(), "__unaligned");
+ DS.ClearTypeQualifiers();
+
+ Diagnoser.check(DS.getTypeSpecComplexLoc(), DS.getTypeSpecComplex());
+ Diagnoser.check(DS.getTypeSpecSignLoc(), DS.getTypeSpecSign());
+ Diagnoser.check(DS.getTypeSpecWidthLoc(), DS.getTypeSpecWidth());
+ Diagnoser.check(DS.getTypeSpecTypeLoc(), DS.getTypeSpecType());
+ DS.ClearTypeSpecType();
+ }
+
+ if (D.isInvalidType())
+ return;
+
+ // Check the declarator is simple enough.
+ bool FoundFunction = false;
+ for (const DeclaratorChunk &Chunk : llvm::reverse(D.type_objects())) {
+ if (Chunk.Kind == DeclaratorChunk::Paren)
+ continue;
+ if (Chunk.Kind != DeclaratorChunk::Function || FoundFunction) {
+ Diag(D.getDeclSpec().getLocStart(),
+ diag::err_deduction_guide_with_complex_decl)
+ << D.getSourceRange();
+ break;
+ }
+ if (!Chunk.Fun.hasTrailingReturnType()) {
+ Diag(D.getName().getLocStart(),
+ diag::err_deduction_guide_no_trailing_return_type);
+ break;
+ }
+
+ // Check that the return type is written as a specialization of
+ // the template specified as the deduction-guide's name.
+ ParsedType TrailingReturnType = Chunk.Fun.getTrailingReturnType();
+ TypeSourceInfo *TSI = nullptr;
+ QualType RetTy = GetTypeFromParser(TrailingReturnType, &TSI);
+ assert(TSI && "deduction guide has valid type but invalid return type?");
+ bool AcceptableReturnType = false;
+ bool MightInstantiateToSpecialization = false;
+ if (auto RetTST =
+ TSI->getTypeLoc().getAs<TemplateSpecializationTypeLoc>()) {
+ TemplateName SpecifiedName = RetTST.getTypePtr()->getTemplateName();
+ bool TemplateMatches =
+ Context.hasSameTemplateName(SpecifiedName, GuidedTemplate);
+ if (SpecifiedName.getKind() == TemplateName::Template && TemplateMatches)
+ AcceptableReturnType = true;
+ else {
+ // This could still instantiate to the right type, unless we know it
+ // names the wrong class template.
+ auto *TD = SpecifiedName.getAsTemplateDecl();
+ MightInstantiateToSpecialization = !(TD && isa<ClassTemplateDecl>(TD) &&
+ !TemplateMatches);
+ }
+ } else if (!RetTy.hasQualifiers() && RetTy->isDependentType()) {
+ MightInstantiateToSpecialization = true;
+ }
+
+ if (!AcceptableReturnType) {
+ Diag(TSI->getTypeLoc().getLocStart(),
+ diag::err_deduction_guide_bad_trailing_return_type)
+ << GuidedTemplate << TSI->getType() << MightInstantiateToSpecialization
+ << TSI->getTypeLoc().getSourceRange();
+ }
+
+ // Keep going to check that we don't have any inner declarator pieces (we
+ // could still have a function returning a pointer to a function).
+ FoundFunction = true;
+ }
+
+ if (D.isFunctionDefinition())
+ Diag(D.getIdentifierLoc(), diag::err_deduction_guide_defines_function);
+}
+
//===----------------------------------------------------------------------===//
// Namespace Handling
//===----------------------------------------------------------------------===//
@@ -8397,7 +8681,7 @@ QualType Sema::BuildStdInitializerList(QualType Element, SourceLocation Loc) {
CheckTemplateIdType(TemplateName(StdInitializerList), Loc, Args));
}
-bool Sema::isInitListConstructor(const CXXConstructorDecl* Ctor) {
+bool Sema::isInitListConstructor(const FunctionDecl *Ctor) {
// C++ [dcl.init.list]p2:
// A constructor is an initializer-list constructor if its first parameter
// is of type std::initializer_list<E> or reference to possibly cv-qualified
@@ -8613,6 +8897,9 @@ Decl *Sema::ActOnUsingDeclaration(Scope *S,
Diag(Name.getLocStart(), diag::err_using_decl_template_id)
<< SourceRange(Name.TemplateId->LAngleLoc, Name.TemplateId->RAngleLoc);
return nullptr;
+
+ case UnqualifiedId::IK_DeductionGuideName:
+ llvm_unreachable("cannot parse qualified deduction guide name");
}
DeclarationNameInfo TargetNameInfo = GetNameFromUnqualifiedId(Name);
@@ -9169,15 +9456,18 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS,
HasTypenameKeyword, IsInstantiation, SS.getScopeRep(),
dyn_cast<CXXRecordDecl>(CurContext)),
CTK_ErrorRecovery)) {
- // We reject any correction for which ND would be NULL.
- NamedDecl *ND = Corrected.getCorrectionDecl();
-
// We reject candidates where DroppedSpecifier == true, hence the
// literal '0' below.
diagnoseTypo(Corrected, PDiag(diag::err_no_member_suggest)
<< NameInfo.getName() << LookupContext << 0
<< SS.getRange());
+ // If we picked a correction with no attached Decl we can't do anything
+ // useful with it, bail out.
+ NamedDecl *ND = Corrected.getCorrectionDecl();
+ if (!ND)
+ return BuildInvalid();
+
// If we corrected to an inheriting constructor, handle it as one.
auto *RD = dyn_cast<CXXRecordDecl>(ND);
if (RD && RD->isInjectedClassName()) {
@@ -9816,123 +10106,113 @@ Decl *Sema::ActOnNamespaceAliasDef(Scope *S, SourceLocation NamespaceLoc,
return AliasDecl;
}
-Sema::ImplicitExceptionSpecification
-Sema::ComputeDefaultedDefaultCtorExceptionSpec(SourceLocation Loc,
- CXXMethodDecl *MD) {
- CXXRecordDecl *ClassDecl = MD->getParent();
+namespace {
+struct SpecialMemberExceptionSpecInfo
+ : SpecialMemberVisitor<SpecialMemberExceptionSpecInfo> {
+ SourceLocation Loc;
+ Sema::ImplicitExceptionSpecification ExceptSpec;
- // C++ [except.spec]p14:
- // An implicitly declared special member function (Clause 12) shall have an
- // exception-specification. [...]
- ImplicitExceptionSpecification ExceptSpec(*this);
- if (ClassDecl->isInvalidDecl())
- return ExceptSpec;
+ SpecialMemberExceptionSpecInfo(Sema &S, CXXMethodDecl *MD,
+ Sema::CXXSpecialMember CSM,
+ Sema::InheritedConstructorInfo *ICI,
+ SourceLocation Loc)
+ : SpecialMemberVisitor(S, MD, CSM, ICI), Loc(Loc), ExceptSpec(S) {}
- // Direct base-class constructors.
- for (const auto &B : ClassDecl->bases()) {
- if (B.isVirtual()) // Handled below.
- continue;
-
- if (const RecordType *BaseType = B.getType()->getAs<RecordType>()) {
- CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(BaseType->getDecl());
- CXXConstructorDecl *Constructor = LookupDefaultConstructor(BaseClassDecl);
- // 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)
- ExceptSpec.CalledDecl(B.getLocStart(), Constructor);
- }
- }
+ bool visitBase(CXXBaseSpecifier *Base);
+ bool visitField(FieldDecl *FD);
- // Virtual base-class constructors.
- for (const auto &B : ClassDecl->vbases()) {
- if (const RecordType *BaseType = B.getType()->getAs<RecordType>()) {
- CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(BaseType->getDecl());
- CXXConstructorDecl *Constructor = LookupDefaultConstructor(BaseClassDecl);
- // 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)
- ExceptSpec.CalledDecl(B.getLocStart(), Constructor);
- }
- }
-
- // Field constructors.
- for (auto *F : ClassDecl->fields()) {
- if (F->hasInClassInitializer()) {
- Expr *E = F->getInClassInitializer();
- if (!E)
- // FIXME: It's a little wasteful to build and throw away a
- // CXXDefaultInitExpr here.
- E = BuildCXXDefaultInitExpr(Loc, F).get();
- if (E)
- ExceptSpec.CalledExpr(E);
- } else if (const RecordType *RecordTy
- = Context.getBaseElementType(F->getType())->getAs<RecordType>()) {
- CXXRecordDecl *FieldRecDecl = cast<CXXRecordDecl>(RecordTy->getDecl());
- CXXConstructorDecl *Constructor = LookupDefaultConstructor(FieldRecDecl);
- // 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
- // might just be ill-formed because this function attempts to refer to
- // a deleted function here.
- if (Constructor)
- ExceptSpec.CalledDecl(F->getLocation(), Constructor);
- }
- }
+ void visitClassSubobject(CXXRecordDecl *Class, Subobject Subobj,
+ unsigned Quals);
- return ExceptSpec;
+ void visitSubobjectCall(Subobject Subobj,
+ Sema::SpecialMemberOverloadResult SMOR);
+};
}
-Sema::ImplicitExceptionSpecification
-Sema::ComputeInheritingCtorExceptionSpec(SourceLocation Loc,
- CXXConstructorDecl *CD) {
- CXXRecordDecl *ClassDecl = CD->getParent();
+bool SpecialMemberExceptionSpecInfo::visitBase(CXXBaseSpecifier *Base) {
+ auto *RT = Base->getType()->getAs<RecordType>();
+ if (!RT)
+ return false;
- // C++ [except.spec]p14:
- // An inheriting constructor [...] shall have an exception-specification. [...]
- ImplicitExceptionSpecification ExceptSpec(*this);
- if (ClassDecl->isInvalidDecl())
- return ExceptSpec;
+ auto *BaseClass = cast<CXXRecordDecl>(RT->getDecl());
+ Sema::SpecialMemberOverloadResult SMOR = lookupInheritedCtor(BaseClass);
+ if (auto *BaseCtor = SMOR.getMethod()) {
+ visitSubobjectCall(Base, BaseCtor);
+ return false;
+ }
- auto Inherited = CD->getInheritedConstructor();
- InheritedConstructorInfo ICI(*this, Loc, Inherited.getShadowDecl());
+ visitClassSubobject(BaseClass, Base, 0);
+ return false;
+}
- // Direct and virtual base-class constructors.
- for (bool VBase : {false, true}) {
- for (CXXBaseSpecifier &B :
- VBase ? ClassDecl->vbases() : ClassDecl->bases()) {
- // Don't visit direct vbases twice.
- if (B.isVirtual() != VBase)
- continue;
+bool SpecialMemberExceptionSpecInfo::visitField(FieldDecl *FD) {
+ if (CSM == Sema::CXXDefaultConstructor && FD->hasInClassInitializer()) {
+ Expr *E = FD->getInClassInitializer();
+ if (!E)
+ // FIXME: It's a little wasteful to build and throw away a
+ // CXXDefaultInitExpr here.
+ // FIXME: We should have a single context note pointing at Loc, and
+ // this location should be MD->getLocation() instead, since that's
+ // the location where we actually use the default init expression.
+ E = S.BuildCXXDefaultInitExpr(Loc, FD).get();
+ if (E)
+ ExceptSpec.CalledExpr(E);
+ } else if (auto *RT = S.Context.getBaseElementType(FD->getType())
+ ->getAs<RecordType>()) {
+ visitClassSubobject(cast<CXXRecordDecl>(RT->getDecl()), FD,
+ FD->getType().getCVRQualifiers());
+ }
+ return false;
+}
- CXXRecordDecl *BaseClass = B.getType()->getAsCXXRecordDecl();
- if (!BaseClass)
- continue;
+void SpecialMemberExceptionSpecInfo::visitClassSubobject(CXXRecordDecl *Class,
+ Subobject Subobj,
+ unsigned Quals) {
+ FieldDecl *Field = Subobj.dyn_cast<FieldDecl*>();
+ bool IsMutable = Field && Field->isMutable();
+ visitSubobjectCall(Subobj, lookupIn(Class, Quals, IsMutable));
+}
- CXXConstructorDecl *Constructor =
- ICI.findConstructorForBase(BaseClass, Inherited.getConstructor())
- .first;
- if (!Constructor)
- Constructor = LookupDefaultConstructor(BaseClass);
- if (Constructor)
- ExceptSpec.CalledDecl(B.getLocStart(), Constructor);
- }
- }
+void SpecialMemberExceptionSpecInfo::visitSubobjectCall(
+ Subobject Subobj, Sema::SpecialMemberOverloadResult SMOR) {
+ // Note, if lookup fails, it doesn't matter what exception specification we
+ // choose because the special member will be deleted.
+ if (CXXMethodDecl *MD = SMOR.getMethod())
+ ExceptSpec.CalledDecl(getSubobjectLoc(Subobj), MD);
+}
- // Field constructors.
- for (const auto *F : ClassDecl->fields()) {
- if (F->hasInClassInitializer()) {
- if (Expr *E = F->getInClassInitializer())
- ExceptSpec.CalledExpr(E);
- } else if (const RecordType *RecordTy
- = Context.getBaseElementType(F->getType())->getAs<RecordType>()) {
- CXXRecordDecl *FieldRecDecl = cast<CXXRecordDecl>(RecordTy->getDecl());
- CXXConstructorDecl *Constructor = LookupDefaultConstructor(FieldRecDecl);
- if (Constructor)
- ExceptSpec.CalledDecl(F->getLocation(), Constructor);
- }
- }
+static Sema::ImplicitExceptionSpecification
+ComputeDefaultedSpecialMemberExceptionSpec(
+ Sema &S, SourceLocation Loc, CXXMethodDecl *MD, Sema::CXXSpecialMember CSM,
+ Sema::InheritedConstructorInfo *ICI) {
+ CXXRecordDecl *ClassDecl = MD->getParent();
- return ExceptSpec;
+ // C++ [except.spec]p14:
+ // An implicitly declared special member function (Clause 12) shall have an
+ // exception-specification. [...]
+ SpecialMemberExceptionSpecInfo Info(S, MD, CSM, ICI, Loc);
+ if (ClassDecl->isInvalidDecl())
+ return Info.ExceptSpec;
+
+ // C++1z [except.spec]p7:
+ // [Look for exceptions thrown by] a constructor selected [...] to
+ // initialize a potentially constructed subobject,
+ // C++1z [except.spec]p8:
+ // The exception specification for an implicitly-declared destructor, or a
+ // destructor without a noexcept-specifier, is potentially-throwing if and
+ // only if any of the destructors for any of its potentially constructed
+ // subojects is potentially throwing.
+ // FIXME: We respect the first rule but ignore the "potentially constructed"
+ // in the second rule to resolve a core issue (no number yet) that would have
+ // us reject:
+ // struct A { virtual void f() = 0; virtual ~A() noexcept(false) = 0; };
+ // struct B : A {};
+ // struct C : B { void f(); };
+ // ... due to giving B::~B() a non-throwing exception specification.
+ Info.visit(Info.IsConstructor ? Info.VisitPotentiallyConstructedBases
+ : Info.VisitAllBases);
+
+ return Info.ExceptSpec;
}
namespace {
@@ -9944,19 +10224,34 @@ struct DeclaringSpecialMember {
bool WasAlreadyBeingDeclared;
DeclaringSpecialMember(Sema &S, CXXRecordDecl *RD, Sema::CXXSpecialMember CSM)
- : S(S), D(RD, CSM), SavedContext(S, RD) {
+ : S(S), D(RD, CSM), SavedContext(S, RD) {
WasAlreadyBeingDeclared = !S.SpecialMembersBeingDeclared.insert(D).second;
if (WasAlreadyBeingDeclared)
// This almost never happens, but if it does, ensure that our cache
// doesn't contain a stale result.
S.SpecialMemberCache.clear();
-
- // FIXME: Register a note to be produced if we encounter an error while
- // declaring the special member.
+ else {
+ // Register a note to be produced if we encounter an error while
+ // declaring the special member.
+ Sema::CodeSynthesisContext Ctx;
+ Ctx.Kind = Sema::CodeSynthesisContext::DeclaringSpecialMember;
+ // FIXME: We don't have a location to use here. Using the class's
+ // location maintains the fiction that we declare all special members
+ // with the class, but (1) it's not clear that lying about that helps our
+ // users understand what's going on, and (2) there may be outer contexts
+ // on the stack (some of which are relevant) and printing them exposes
+ // our lies.
+ Ctx.PointOfInstantiation = RD->getLocation();
+ Ctx.Entity = RD;
+ Ctx.SpecialMember = CSM;
+ S.pushCodeSynthesisContext(Ctx);
+ }
}
~DeclaringSpecialMember() {
- if (!WasAlreadyBeingDeclared)
+ if (!WasAlreadyBeingDeclared) {
S.SpecialMembersBeingDeclared.erase(D);
+ S.popCodeSynthesisContext();
+ }
}
/// \brief Are we already trying to declare this special member?
@@ -9978,7 +10273,7 @@ void Sema::CheckImplicitSpecialMemberDeclaration(Scope *S, FunctionDecl *FD) {
R.resolveKind();
R.suppressDiagnostics();
- CheckFunctionDeclaration(S, FD, R, /*IsExplicitSpecialization*/false);
+ CheckFunctionDeclaration(S, FD, R, /*IsMemberSpecialization*/false);
}
CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor(
@@ -10262,45 +10557,6 @@ void Sema::DefineInheritingConstructor(SourceLocation CurrentLocation,
DiagnoseUninitializedFields(*this, Constructor);
}
-Sema::ImplicitExceptionSpecification
-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.
- ImplicitExceptionSpecification ExceptSpec(*this);
- if (ClassDecl->isInvalidDecl())
- return ExceptSpec;
-
- // Direct base-class destructors.
- for (const auto &B : ClassDecl->bases()) {
- if (B.isVirtual()) // Handled below.
- continue;
-
- if (const RecordType *BaseType = B.getType()->getAs<RecordType>())
- ExceptSpec.CalledDecl(B.getLocStart(),
- LookupDestructor(cast<CXXRecordDecl>(BaseType->getDecl())));
- }
-
- // Virtual base-class destructors.
- for (const auto &B : ClassDecl->vbases()) {
- if (const RecordType *BaseType = B.getType()->getAs<RecordType>())
- ExceptSpec.CalledDecl(B.getLocStart(),
- LookupDestructor(cast<CXXRecordDecl>(BaseType->getDecl())));
- }
-
- // Field destructors.
- for (const auto *F : ClassDecl->fields()) {
- if (const RecordType *RecordTy
- = Context.getBaseElementType(F->getType())->getAs<RecordType>())
- ExceptSpec.CalledDecl(F->getLocation(),
- LookupDestructor(cast<CXXRecordDecl>(RecordTy->getDecl())));
- }
-
- return ExceptSpec;
-}
-
CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) {
// C++ [class.dtor]p2:
// If a class has no user-declared destructor, a destructor is
@@ -10852,7 +11108,7 @@ buildSingleCopyAssignRecursively(Sema &S, SourceLocation Loc, QualType T,
= new (S.Context) BinaryOperator(IterationVarRefRVal.build(S, Loc),
IntegerLiteral::Create(S.Context, Upper, SizeType, Loc),
BO_NE, S.Context.BoolTy,
- VK_RValue, OK_Ordinary, Loc, false);
+ VK_RValue, OK_Ordinary, Loc, FPOptions());
// Create the pre-increment of the iteration variable.
Expr *Increment
@@ -10887,62 +11143,6 @@ buildSingleCopyAssign(Sema &S, SourceLocation Loc, QualType T,
return Result;
}
-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->getNumParams() == 1 && "not a copy assignment op");
- unsigned ArgQuals =
- T->getParamType(0).getNonReferenceType().getCVRQualifiers();
-
- // C++ [except.spec]p14:
- // An implicitly declared special member function (Clause 12) shall have an
- // exception-specification. [...]
-
- // It is unspecified whether or not an implicit copy assignment operator
- // attempts to deduplicate calls to assignment operators of virtual bases are
- // made. As such, this exception specification is effectively unspecified.
- // 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.
- for (const auto &Base : ClassDecl->bases()) {
- if (Base.isVirtual())
- continue;
-
- CXXRecordDecl *BaseClassDecl
- = cast<CXXRecordDecl>(Base.getType()->getAs<RecordType>()->getDecl());
- if (CXXMethodDecl *CopyAssign = LookupCopyingAssignment(BaseClassDecl,
- ArgQuals, false, 0))
- ExceptSpec.CalledDecl(Base.getLocStart(), CopyAssign);
- }
-
- for (const auto &Base : ClassDecl->vbases()) {
- CXXRecordDecl *BaseClassDecl
- = cast<CXXRecordDecl>(Base.getType()->getAs<RecordType>()->getDecl());
- if (CXXMethodDecl *CopyAssign = LookupCopyingAssignment(BaseClassDecl,
- ArgQuals, false, 0))
- ExceptSpec.CalledDecl(Base.getLocStart(), CopyAssign);
- }
-
- for (const auto *Field : ClassDecl->fields()) {
- QualType FieldType = Context.getBaseElementType(Field->getType());
- if (CXXRecordDecl *FieldClassDecl = FieldType->getAsCXXRecordDecl()) {
- if (CXXMethodDecl *CopyAssign =
- LookupCopyingAssignment(FieldClassDecl,
- ArgQuals | FieldType.getCVRQualifiers(),
- false, 0))
- ExceptSpec.CalledDecl(Field->getLocation(), CopyAssign);
- }
- }
-
- return ExceptSpec;
-}
-
CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) {
// Note: The following rules are largely analoguous to the copy
// constructor rules. Note that virtual bases are not taken into account
@@ -11286,59 +11486,6 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
}
}
-Sema::ImplicitExceptionSpecification
-Sema::ComputeDefaultedMoveAssignmentExceptionSpec(CXXMethodDecl *MD) {
- CXXRecordDecl *ClassDecl = MD->getParent();
-
- ImplicitExceptionSpecification ExceptSpec(*this);
- if (ClassDecl->isInvalidDecl())
- return ExceptSpec;
-
- // C++0x [except.spec]p14:
- // An implicitly declared special member function (Clause 12) shall have an
- // exception-specification. [...]
-
- // It is unspecified whether or not an implicit move assignment operator
- // attempts to deduplicate calls to assignment operators of virtual bases are
- // made. As such, this exception specification is effectively unspecified.
- // 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.
- // Note that a move constructor is not implicitly declared when there are
- // virtual bases, but it can still be user-declared and explicitly defaulted.
- for (const auto &Base : ClassDecl->bases()) {
- if (Base.isVirtual())
- continue;
-
- CXXRecordDecl *BaseClassDecl
- = cast<CXXRecordDecl>(Base.getType()->getAs<RecordType>()->getDecl());
- if (CXXMethodDecl *MoveAssign = LookupMovingAssignment(BaseClassDecl,
- 0, false, 0))
- ExceptSpec.CalledDecl(Base.getLocStart(), MoveAssign);
- }
-
- for (const auto &Base : ClassDecl->vbases()) {
- CXXRecordDecl *BaseClassDecl
- = cast<CXXRecordDecl>(Base.getType()->getAs<RecordType>()->getDecl());
- if (CXXMethodDecl *MoveAssign = LookupMovingAssignment(BaseClassDecl,
- 0, false, 0))
- ExceptSpec.CalledDecl(Base.getLocStart(), MoveAssign);
- }
-
- for (const auto *Field : ClassDecl->fields()) {
- QualType FieldType = Context.getBaseElementType(Field->getType());
- if (CXXRecordDecl *FieldClassDecl = FieldType->getAsCXXRecordDecl()) {
- if (CXXMethodDecl *MoveAssign =
- LookupMovingAssignment(FieldClassDecl,
- FieldType.getCVRQualifiers(),
- false, 0))
- ExceptSpec.CalledDecl(Field->getLocation(), MoveAssign);
- }
- }
-
- return ExceptSpec;
-}
-
CXXMethodDecl *Sema::DeclareImplicitMoveAssignment(CXXRecordDecl *ClassDecl) {
assert(ClassDecl->needsImplicitMoveAssignment());
@@ -11449,13 +11596,13 @@ static void checkMoveAssignmentForRepeatedMove(Sema &S, CXXRecordDecl *Class,
// If we're not actually going to call a move assignment for this base,
// or the selected move assignment is trivial, skip it.
- Sema::SpecialMemberOverloadResult *SMOR =
+ Sema::SpecialMemberOverloadResult SMOR =
S.LookupSpecialMember(Base, Sema::CXXMoveAssignment,
/*ConstArg*/false, /*VolatileArg*/false,
/*RValueThis*/true, /*ConstThis*/false,
/*VolatileThis*/false);
- if (!SMOR->getMethod() || SMOR->getMethod()->isTrivial() ||
- !SMOR->getMethod()->isMoveAssignmentOperator())
+ if (!SMOR.getMethod() || SMOR.getMethod()->isTrivial() ||
+ !SMOR.getMethod()->isMoveAssignmentOperator())
continue;
if (BaseSpec->isVirtual()) {
@@ -11486,7 +11633,7 @@ static void checkMoveAssignmentForRepeatedMove(Sema &S, CXXRecordDecl *Class,
// Only walk over bases that have defaulted move assignment operators.
// We assume that any user-provided move assignment operator handles
// the multiple-moves-of-vbase case itself somehow.
- if (!SMOR->getMethod()->isDefaulted())
+ if (!SMOR.getMethod()->isDefaulted())
continue;
// We're going to move the base classes of Base. Add them to the list.
@@ -11723,52 +11870,6 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation,
}
}
-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->getNumParams() >= 1 && "not a copy ctor");
- unsigned Quals = T->getParamType(0).getNonReferenceType().getCVRQualifiers();
-
- // C++ [except.spec]p14:
- // An implicitly declared special member function (Clause 12) shall have an
- // exception-specification. [...]
- for (const auto &Base : ClassDecl->bases()) {
- // Virtual bases are handled below.
- if (Base.isVirtual())
- continue;
-
- CXXRecordDecl *BaseClassDecl
- = cast<CXXRecordDecl>(Base.getType()->getAs<RecordType>()->getDecl());
- if (CXXConstructorDecl *CopyConstructor =
- LookupCopyingConstructor(BaseClassDecl, Quals))
- ExceptSpec.CalledDecl(Base.getLocStart(), CopyConstructor);
- }
- for (const auto &Base : ClassDecl->vbases()) {
- CXXRecordDecl *BaseClassDecl
- = cast<CXXRecordDecl>(Base.getType()->getAs<RecordType>()->getDecl());
- if (CXXConstructorDecl *CopyConstructor =
- LookupCopyingConstructor(BaseClassDecl, Quals))
- ExceptSpec.CalledDecl(Base.getLocStart(), CopyConstructor);
- }
- for (const auto *Field : ClassDecl->fields()) {
- QualType FieldType = Context.getBaseElementType(Field->getType());
- if (CXXRecordDecl *FieldClassDecl = FieldType->getAsCXXRecordDecl()) {
- if (CXXConstructorDecl *CopyConstructor =
- LookupCopyingConstructor(FieldClassDecl,
- Quals | FieldType.getCVRQualifiers()))
- ExceptSpec.CalledDecl(Field->getLocation(), CopyConstructor);
- }
- }
-
- return ExceptSpec;
-}
-
CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor(
CXXRecordDecl *ClassDecl) {
// C++ [class.copy]p4:
@@ -11896,65 +11997,6 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation,
}
}
-Sema::ImplicitExceptionSpecification
-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. [...]
- ImplicitExceptionSpecification ExceptSpec(*this);
- if (ClassDecl->isInvalidDecl())
- return ExceptSpec;
-
- // Direct base-class constructors.
- for (const auto &B : ClassDecl->bases()) {
- if (B.isVirtual()) // Handled below.
- continue;
-
- if (const RecordType *BaseType = B.getType()->getAs<RecordType>()) {
- CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(BaseType->getDecl());
- 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)
- ExceptSpec.CalledDecl(B.getLocStart(), Constructor);
- }
- }
-
- // Virtual base-class constructors.
- for (const auto &B : ClassDecl->vbases()) {
- if (const RecordType *BaseType = B.getType()->getAs<RecordType>()) {
- CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(BaseType->getDecl());
- 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)
- ExceptSpec.CalledDecl(B.getLocStart(), Constructor);
- }
- }
-
- // Field constructors.
- for (const auto *F : ClassDecl->fields()) {
- 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
- // might just be ill-formed because this function attempts to refer to
- // a deleted function here.
- if (Constructor)
- ExceptSpec.CalledDecl(F->getLocation(), Constructor);
- }
- }
-
- return ExceptSpec;
-}
-
CXXConstructorDecl *Sema::DeclareImplicitMoveConstructor(
CXXRecordDecl *ClassDecl) {
assert(ClassDecl->needsImplicitMoveConstructor());
@@ -12198,7 +12240,7 @@ void Sema::DefineImplicitLambdaToBlockPointerConversion(
// Set the body of the conversion function.
Stmt *ReturnS = Return.get();
Conv->setBody(new (Context) CompoundStmt(Context, ReturnS,
- Conv->getLocation(),
+ Conv->getLocation(),
Conv->getLocation()));
// We're done; notify the mutation listener, if any.
@@ -12750,7 +12792,7 @@ checkLiteralOperatorTemplateParameterList(Sema &SemaRef,
PmArgs->getType()->getAs<TemplateTypeParmType>();
if (TArgs && TArgs->getDepth() == PmType->getDepth() &&
TArgs->getIndex() == PmType->getIndex()) {
- if (SemaRef.ActiveTemplateInstantiations.empty())
+ if (!SemaRef.inTemplateInstantiation())
SemaRef.Diag(TpDecl->getLocation(),
diag::ext_string_literal_operator_template);
return false;
@@ -13076,7 +13118,8 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S,
if (!Invalid && !ExDeclType->isDependentType()) {
if (const RecordType *recordType = ExDeclType->getAs<RecordType>()) {
// Insulate this from anything else we might currently be parsing.
- EnterExpressionEvaluationContext scope(*this, PotentiallyEvaluated);
+ EnterExpressionEvaluationContext scope(
+ *this, ExpressionEvaluationContext::PotentiallyEvaluated);
// C++ [except.handle]p16:
// The object declared in an exception-declaration or, if the
@@ -13245,10 +13288,10 @@ FriendDecl *Sema::CheckFriendTypeDecl(SourceLocation LocStart,
// for a class.*
//
// * The class-key of the elaborated-type-specifier is required.
- if (!ActiveTemplateInstantiations.empty()) {
- // Do not complain about the form of friend template types during
- // template instantiation; we will already have complained when the
- // template was declared.
+ if (!CodeSynthesisContexts.empty()) {
+ // Do not complain about the form of friend template types during any kind
+ // of code synthesis. For template instantiation, we will have complained
+ // when the template was defined.
} else {
if (!T->isElaboratedTypeSpecifier()) {
// If we evaluated the type to a record type, suggest putting
@@ -13313,13 +13356,13 @@ Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc,
MultiTemplateParamsArg TempParamLists) {
TagTypeKind Kind = TypeWithKeyword::getTagTypeKindForTypeSpec(TagSpec);
- bool isExplicitSpecialization = false;
+ bool IsMemberSpecialization = false;
bool Invalid = false;
if (TemplateParameterList *TemplateParams =
MatchTemplateParametersToScopeSpecifier(
TagLoc, NameLoc, SS, nullptr, TempParamLists, /*friend*/ true,
- isExplicitSpecialization, Invalid)) {
+ IsMemberSpecialization, Invalid)) {
if (TemplateParams->size() > 0) {
// This is a declaration of a class template.
if (Invalid)
@@ -13334,7 +13377,7 @@ Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc,
// The "template<>" header is extraneous.
Diag(TemplateParams->getTemplateLoc(), diag::err_template_tag_noparams)
<< TypeWithKeyword::getTagTypeKindName(Kind) << Name;
- isExplicitSpecialization = true;
+ IsMemberSpecialization = true;
}
}
@@ -13744,6 +13787,9 @@ NamedDecl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D,
case UnqualifiedId::IK_ConversionFunctionId:
DiagArg = 2;
break;
+ case UnqualifiedId::IK_DeductionGuideName:
+ DiagArg = 3;
+ break;
case UnqualifiedId::IK_Identifier:
case UnqualifiedId::IK_ImplicitSelfParam:
case UnqualifiedId::IK_LiteralOperatorId:
@@ -14157,7 +14203,8 @@ void Sema::ActOnCXXEnterDeclInitializer(Scope *S, Decl *D) {
// new expression evaluation context that is associated with this static
// data member.
if (isStaticDataMember(D))
- PushExpressionEvaluationContext(PotentiallyEvaluated, D);
+ PushExpressionEvaluationContext(
+ ExpressionEvaluationContext::PotentiallyEvaluated, D);
}
/// ActOnCXXExitDeclInitializer - Invoked after we are finished parsing an