summaryrefslogtreecommitdiff
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.cpp1414
1 files changed, 802 insertions, 612 deletions
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaDeclCXX.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaDeclCXX.cpp
index 82d81a85fa90..e161c87f1739 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/contrib/llvm/tools/clang/lib/Sema/SemaDeclCXX.cpp
@@ -471,7 +471,7 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old,
continue;
}
- // We found our guy.
+ // We found the right previous declaration.
break;
}
@@ -3356,34 +3356,7 @@ BuildImplicitBaseInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
ExprResult BaseInit;
switch (ImplicitInitKind) {
- case IIK_Inherit: {
- const CXXRecordDecl *Inherited =
- Constructor->getInheritedConstructor()->getParent();
- const CXXRecordDecl *Base = BaseSpec->getType()->getAsCXXRecordDecl();
- if (Base && Inherited->getCanonicalDecl() == Base->getCanonicalDecl()) {
- // C++11 [class.inhctor]p8:
- // Each expression in the expression-list is of the form
- // static_cast<T&&>(p), where p is the name of the corresponding
- // constructor parameter and T is the declared type of p.
- SmallVector<Expr*, 16> Args;
- for (unsigned I = 0, E = Constructor->getNumParams(); I != E; ++I) {
- ParmVarDecl *PD = Constructor->getParamDecl(I);
- ExprResult ArgExpr =
- SemaRef.BuildDeclRefExpr(PD, PD->getType().getNonReferenceType(),
- VK_LValue, SourceLocation());
- if (ArgExpr.isInvalid())
- return true;
- Args.push_back(CastForMoving(SemaRef, ArgExpr.get(), PD->getType()));
- }
-
- InitializationKind InitKind = InitializationKind::CreateDirect(
- Constructor->getLocation(), SourceLocation(), SourceLocation());
- InitializationSequence InitSeq(SemaRef, InitEntity, InitKind, Args);
- BaseInit = InitSeq.Perform(SemaRef, InitEntity, InitKind, Args);
- break;
- }
- }
- // Fall through.
+ case IIK_Inherit:
case IIK_Default: {
InitializationKind InitKind
= InitializationKind::CreateDefault(Constructor->getLocation());
@@ -3694,12 +3667,12 @@ struct BaseAndFieldInfo {
BaseAndFieldInfo(Sema &S, CXXConstructorDecl *Ctor, bool ErrorsInInits)
: S(S), Ctor(Ctor), AnyErrorsInInits(ErrorsInInits) {
bool Generated = Ctor->isImplicit() || Ctor->isDefaulted();
- if (Generated && Ctor->isCopyConstructor())
+ if (Ctor->getInheritedConstructor())
+ IIK = IIK_Inherit;
+ else if (Generated && Ctor->isCopyConstructor())
IIK = IIK_Copy;
else if (Generated && Ctor->isMoveConstructor())
IIK = IIK_Move;
- else if (Ctor->getInheritedConstructor())
- IIK = IIK_Inherit;
else
IIK = IIK_Default;
}
@@ -4774,7 +4747,6 @@ void Sema::checkClassLevelDLLAttribute(CXXRecordDecl *Class) {
// The class is either imported or exported.
const bool ClassExported = ClassAttr->getKind() == attr::DLLExport;
- const bool ClassImported = !ClassExported;
TemplateSpecializationKind TSK = Class->getTemplateSpecializationKind();
@@ -4809,11 +4781,20 @@ void Sema::checkClassLevelDLLAttribute(CXXRecordDecl *Class) {
if (!Context.getTargetInfo().getCXXABI().isMicrosoft())
continue;
- // MSVC versions before 2015 don't export the move assignment operators,
- // so don't attempt to import them if we have a definition.
- if (ClassImported && MD->isMoveAssignmentOperator() &&
+ // MSVC versions before 2015 don't export the move assignment operators
+ // and move constructor, so don't attempt to import/export them if
+ // we have a definition.
+ auto *Ctor = dyn_cast<CXXConstructorDecl>(MD);
+ if ((MD->isMoveAssignmentOperator() ||
+ (Ctor && Ctor->isMoveConstructor())) &&
!getLangOpts().isCompatibleWithMSVC(LangOptions::MSVC2015))
continue;
+
+ // MSVC2015 doesn't export trivial defaulted x-tor but copy assign
+ // operator is exported anyway.
+ if (getLangOpts().isCompatibleWithMSVC(LangOptions::MSVC2015) &&
+ (Ctor || isa<CXXDestructorDecl>(MD)) && MD->isTrivial())
+ continue;
}
}
@@ -4887,6 +4868,33 @@ void Sema::propagateDLLAttrToBaseClassTemplate(
}
}
+static void DefineImplicitSpecialMember(Sema &S, CXXMethodDecl *MD,
+ SourceLocation DefaultLoc) {
+ switch (S.getSpecialMember(MD)) {
+ case Sema::CXXDefaultConstructor:
+ S.DefineImplicitDefaultConstructor(DefaultLoc,
+ cast<CXXConstructorDecl>(MD));
+ break;
+ case Sema::CXXCopyConstructor:
+ S.DefineImplicitCopyConstructor(DefaultLoc, cast<CXXConstructorDecl>(MD));
+ break;
+ case Sema::CXXCopyAssignment:
+ S.DefineImplicitCopyAssignment(DefaultLoc, MD);
+ break;
+ case Sema::CXXDestructor:
+ S.DefineImplicitDestructor(DefaultLoc, cast<CXXDestructorDecl>(MD));
+ break;
+ case Sema::CXXMoveConstructor:
+ S.DefineImplicitMoveConstructor(DefaultLoc, cast<CXXConstructorDecl>(MD));
+ break;
+ case Sema::CXXMoveAssignment:
+ S.DefineImplicitMoveAssignment(DefaultLoc, MD);
+ break;
+ case Sema::CXXInvalid:
+ llvm_unreachable("Invalid special member.");
+ }
+}
+
/// \brief Perform semantic checks on a class definition that has been
/// completing, introducing implicitly-declared members, checking for
/// abstract types, etc.
@@ -4982,8 +4990,8 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
// For an explicitly defaulted or deleted special member, we defer
// determining triviality until the class is complete. That time is now!
+ CXXSpecialMember CSM = getSpecialMember(M);
if (!M->isImplicit() && !M->isUserProvided()) {
- CXXSpecialMember CSM = getSpecialMember(M);
if (CSM != CXXInvalid) {
M->setTrivial(SpecialMemberIsTrivial(M, CSM));
@@ -4991,6 +4999,20 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
Record->finishedDefaultedOrDeletedMember(M);
}
}
+
+ if (!M->isInvalidDecl() && M->isExplicitlyDefaulted() &&
+ M->hasAttr<DLLExportAttr>()) {
+ if (getLangOpts().isCompatibleWithMSVC(LangOptions::MSVC2015) &&
+ M->isTrivial() &&
+ (CSM == CXXDefaultConstructor || CSM == CXXCopyConstructor ||
+ CSM == CXXDestructor))
+ M->dropAttr<DLLExportAttr>();
+
+ if (M->hasAttr<DLLExportAttr>()) {
+ DefineImplicitSpecialMember(*this, M, M->getLocation());
+ ActOnFinishInlineFunctionDef(M);
+ }
+ }
}
}
@@ -5016,15 +5038,6 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
Diag(Record->getLocation(), diag::warn_cxx_ms_struct);
}
- // Declare inheriting constructors. We do this eagerly here because:
- // - The standard requires an eager diagnostic for conflicting inheriting
- // constructors from different classes.
- // - The lazy declaration of the other implicit constructors is so as to not
- // waste space and performance on classes that are not meant to be
- // instantiated (e.g. meta-functions). This doesn't apply to classes that
- // have inheriting constructors.
- DeclareInheritingConstructors(Record);
-
checkClassLevelDLLAttribute(Record);
}
@@ -5058,11 +5071,108 @@ static Sema::SpecialMemberOverloadResult *lookupCallFromSpecialMember(
LHSQuals & Qualifiers::Volatile);
}
+class Sema::InheritedConstructorInfo {
+ Sema &S;
+ SourceLocation UseLoc;
+
+ /// A mapping from the base classes through which the constructor was
+ /// inherited to the using shadow declaration in that base class (or a null
+ /// pointer if the constructor was declared in that base class).
+ llvm::DenseMap<CXXRecordDecl *, ConstructorUsingShadowDecl *>
+ InheritedFromBases;
+
+public:
+ InheritedConstructorInfo(Sema &S, SourceLocation UseLoc,
+ ConstructorUsingShadowDecl *Shadow)
+ : S(S), UseLoc(UseLoc) {
+ bool DiagnosedMultipleConstructedBases = false;
+ CXXRecordDecl *ConstructedBase = nullptr;
+ UsingDecl *ConstructedBaseUsing = nullptr;
+
+ // Find the set of such base class subobjects and check that there's a
+ // unique constructed subobject.
+ for (auto *D : Shadow->redecls()) {
+ auto *DShadow = cast<ConstructorUsingShadowDecl>(D);
+ auto *DNominatedBase = DShadow->getNominatedBaseClass();
+ auto *DConstructedBase = DShadow->getConstructedBaseClass();
+
+ InheritedFromBases.insert(
+ std::make_pair(DNominatedBase->getCanonicalDecl(),
+ DShadow->getNominatedBaseClassShadowDecl()));
+ if (DShadow->constructsVirtualBase())
+ InheritedFromBases.insert(
+ std::make_pair(DConstructedBase->getCanonicalDecl(),
+ DShadow->getConstructedBaseClassShadowDecl()));
+ else
+ assert(DNominatedBase == DConstructedBase);
+
+ // [class.inhctor.init]p2:
+ // If the constructor was inherited from multiple base class subobjects
+ // of type B, the program is ill-formed.
+ if (!ConstructedBase) {
+ ConstructedBase = DConstructedBase;
+ ConstructedBaseUsing = D->getUsingDecl();
+ } else if (ConstructedBase != DConstructedBase &&
+ !Shadow->isInvalidDecl()) {
+ if (!DiagnosedMultipleConstructedBases) {
+ S.Diag(UseLoc, diag::err_ambiguous_inherited_constructor)
+ << Shadow->getTargetDecl();
+ S.Diag(ConstructedBaseUsing->getLocation(),
+ diag::note_ambiguous_inherited_constructor_using)
+ << ConstructedBase;
+ DiagnosedMultipleConstructedBases = true;
+ }
+ S.Diag(D->getUsingDecl()->getLocation(),
+ diag::note_ambiguous_inherited_constructor_using)
+ << DConstructedBase;
+ }
+ }
+
+ if (DiagnosedMultipleConstructedBases)
+ Shadow->setInvalidDecl();
+ }
+
+ /// Find the constructor to use for inherited construction of a base class,
+ /// and whether that base class constructor inherits the constructor from a
+ /// virtual base class (in which case it won't actually invoke it).
+ std::pair<CXXConstructorDecl *, bool>
+ findConstructorForBase(CXXRecordDecl *Base, CXXConstructorDecl *Ctor) const {
+ auto It = InheritedFromBases.find(Base->getCanonicalDecl());
+ if (It == InheritedFromBases.end())
+ return std::make_pair(nullptr, false);
+
+ // This is an intermediary class.
+ if (It->second)
+ return std::make_pair(
+ S.findInheritingConstructor(UseLoc, Ctor, It->second),
+ It->second->constructsVirtualBase());
+
+ // This is the base class from which the constructor was inherited.
+ return std::make_pair(Ctor, false);
+ }
+};
+
/// 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,
- unsigned Quals, bool ConstRHS) {
+static bool
+specialMemberIsConstexpr(Sema &S, CXXRecordDecl *ClassDecl,
+ Sema::CXXSpecialMember CSM, unsigned Quals,
+ bool ConstRHS,
+ CXXConstructorDecl *InheritedCtor = nullptr,
+ Sema::InheritedConstructorInfo *Inherited = nullptr) {
+ // If we're inheriting a constructor, see if we need to call it for this base
+ // class.
+ if (InheritedCtor) {
+ assert(CSM == Sema::CXXDefaultConstructor);
+ auto BaseCtor =
+ Inherited->findConstructorForBase(ClassDecl, InheritedCtor).first;
+ if (BaseCtor)
+ return BaseCtor->isConstexpr();
+ }
+
+ if (CSM == Sema::CXXDefaultConstructor)
+ return ClassDecl->hasConstexprDefaultConstructor();
+
Sema::SpecialMemberOverloadResult *SMOR =
lookupCallFromSpecialMember(S, ClassDecl, CSM, Quals, ConstRHS);
if (!SMOR || !SMOR->getMethod())
@@ -5074,9 +5184,10 @@ static bool specialMemberIsConstexpr(Sema &S, CXXRecordDecl *ClassDecl,
/// 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) {
+static bool defaultedSpecialMemberIsConstexpr(
+ Sema &S, CXXRecordDecl *ClassDecl, Sema::CXXSpecialMember CSM,
+ bool ConstArg, CXXConstructorDecl *InheritedCtor = nullptr,
+ Sema::InheritedConstructorInfo *Inherited = nullptr) {
if (!S.getLangOpts().CPlusPlus11)
return false;
@@ -5085,6 +5196,8 @@ static bool defaultedSpecialMemberIsConstexpr(Sema &S, CXXRecordDecl *ClassDecl,
bool Ctor = true;
switch (CSM) {
case Sema::CXXDefaultConstructor:
+ if (Inherited)
+ break;
// 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.
@@ -5119,7 +5232,10 @@ static bool defaultedSpecialMemberIsConstexpr(Sema &S, CXXRecordDecl *ClassDecl,
// will be initialized (if the constructor isn't deleted), we just don't know
// which one.
if (Ctor && ClassDecl->isUnion())
- return true;
+ return CSM == Sema::CXXDefaultConstructor
+ ? ClassDecl->hasInClassInitializer() ||
+ !ClassDecl->hasVariantMembers()
+ : true;
// -- the class shall not have any virtual base classes;
if (Ctor && ClassDecl->getNumVBases())
@@ -5139,7 +5255,8 @@ static bool defaultedSpecialMemberIsConstexpr(Sema &S, CXXRecordDecl *ClassDecl,
if (!BaseType) continue;
CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(BaseType->getDecl());
- if (!specialMemberIsConstexpr(S, BaseClassDecl, CSM, 0, ConstArg))
+ if (!specialMemberIsConstexpr(S, BaseClassDecl, CSM, 0, ConstArg,
+ InheritedCtor, Inherited))
return false;
}
@@ -5153,6 +5270,8 @@ static bool defaultedSpecialMemberIsConstexpr(Sema &S, CXXRecordDecl *ClassDecl,
for (const auto *F : ClassDecl->fields()) {
if (F->isInvalidDecl())
continue;
+ if (CSM == Sema::CXXDefaultConstructor && F->hasInClassInitializer())
+ continue;
QualType BaseType = S.Context.getBaseElementType(F->getType());
if (const RecordType *RecordTy = BaseType->getAs<RecordType>()) {
CXXRecordDecl *FieldRecDecl = cast<CXXRecordDecl>(RecordTy->getDecl());
@@ -5160,6 +5279,8 @@ static bool defaultedSpecialMemberIsConstexpr(Sema &S, CXXRecordDecl *ClassDecl,
BaseType.getCVRQualifiers(),
ConstArg && !F->isMutable()))
return false;
+ } else if (CSM == Sema::CXXDefaultConstructor) {
+ return false;
}
}
@@ -5187,7 +5308,8 @@ computeImplicitExceptionSpec(Sema &S, SourceLocation Loc, CXXMethodDecl *MD) {
}
assert(cast<CXXConstructorDecl>(MD)->getInheritedConstructor() &&
"only special members have implicit exception specs");
- return S.ComputeInheritingCtorExceptionSpec(cast<CXXConstructorDecl>(MD));
+ return S.ComputeInheritingCtorExceptionSpec(Loc,
+ cast<CXXConstructorDecl>(MD));
}
static FunctionProtoType::ExtProtoInfo getImplicitMethodEPI(Sema &S,
@@ -5384,7 +5506,7 @@ void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) {
// [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;
- ShouldDeleteSpecialMember(MD, CSM, /*Diagnose*/true);
+ ShouldDeleteSpecialMember(MD, CSM, nullptr, /*Diagnose*/true);
HadError = true;
}
}
@@ -5445,6 +5567,7 @@ struct SpecialMemberDeletionInfo {
Sema &S;
CXXMethodDecl *MD;
Sema::CXXSpecialMember CSM;
+ Sema::InheritedConstructorInfo *ICI;
bool Diagnose;
// Properties of the special member, computed for convenience.
@@ -5454,11 +5577,11 @@ struct SpecialMemberDeletionInfo {
bool AllFieldsAreConst;
SpecialMemberDeletionInfo(Sema &S, CXXMethodDecl *MD,
- Sema::CXXSpecialMember CSM, bool Diagnose)
- : S(S), MD(MD), CSM(CSM), Diagnose(Diagnose),
- IsConstructor(false), IsAssignment(false), IsMove(false),
- ConstArg(false), Loc(MD->getLocation()),
- AllFieldsAreConst(true) {
+ 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) {
switch (CSM) {
case Sema::CXXDefaultConstructor:
case Sema::CXXCopyConstructor:
@@ -5490,6 +5613,10 @@ struct SpecialMemberDeletionInfo {
bool inUnion() const { return MD->getParent()->isUnion(); }
+ Sema::CXXSpecialMember getEffectiveCSM() {
+ return ICI ? Sema::CXXInvalid : CSM;
+ }
+
/// Look up the corresponding special member in the given class.
Sema::SpecialMemberOverloadResult *lookupIn(CXXRecordDecl *Class,
unsigned Quals, bool IsMutable) {
@@ -5566,13 +5693,13 @@ bool SpecialMemberDeletionInfo::shouldDeleteForSubobjectCall(
if (Field) {
S.Diag(Field->getLocation(),
diag::note_deleted_special_member_class_subobject)
- << CSM << MD->getParent() << /*IsField*/true
+ << getEffectiveCSM() << MD->getParent() << /*IsField*/true
<< Field << DiagKind << IsDtorCallInCtor;
} else {
CXXBaseSpecifier *Base = Subobj.get<CXXBaseSpecifier*>();
S.Diag(Base->getLocStart(),
diag::note_deleted_special_member_class_subobject)
- << CSM << MD->getParent() << /*IsField*/false
+ << getEffectiveCSM() << MD->getParent() << /*IsField*/false
<< Base->getType() << DiagKind << IsDtorCallInCtor;
}
@@ -5631,7 +5758,29 @@ bool SpecialMemberDeletionInfo::shouldDeleteForBase(CXXBaseSpecifier *Base) {
CXXRecordDecl *BaseClass = Base->getType()->getAsCXXRecordDecl();
// If program is correct, BaseClass cannot be null, but if it is, the error
// must be reported elsewhere.
- return BaseClass && shouldDeleteForClassSubobject(BaseClass, Base, 0);
+ if (!BaseClass)
+ 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();
+ }
+ }
+ return shouldDeleteForClassSubobject(BaseClass, Base, 0);
}
/// Check whether we should delete a special member function due to the class
@@ -5646,7 +5795,7 @@ bool SpecialMemberDeletionInfo::shouldDeleteForField(FieldDecl *FD) {
if (FieldType->isReferenceType() && !FD->hasInClassInitializer()) {
if (Diagnose)
S.Diag(FD->getLocation(), diag::note_deleted_default_ctor_uninit_field)
- << MD->getParent() << FD << FieldType << /*Reference*/0;
+ << !!ICI << MD->getParent() << FD << FieldType << /*Reference*/0;
return true;
}
// C++11 [class.ctor]p5: any non-variant non-static data member of
@@ -5658,7 +5807,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 << FD->getType() << /*Const*/1;
+ << !!ICI << MD->getParent() << FD << FD->getType() << /*Const*/1;
return true;
}
@@ -5717,7 +5866,7 @@ bool SpecialMemberDeletionInfo::shouldDeleteForField(FieldDecl *FD) {
if (Diagnose)
S.Diag(FieldRecord->getLocation(),
diag::note_deleted_default_ctor_all_const)
- << MD->getParent() << /*anonymous union*/1;
+ << !!ICI << MD->getParent() << /*anonymous union*/1;
return true;
}
@@ -5745,7 +5894,7 @@ bool SpecialMemberDeletionInfo::shouldDeleteForAllConstMembers() {
if (Diagnose)
S.Diag(MD->getParent()->getLocation(),
diag::note_deleted_default_ctor_all_const)
- << MD->getParent() << /*not anonymous union*/0;
+ << !!ICI << MD->getParent() << /*not anonymous union*/0;
return true;
}
return false;
@@ -5755,6 +5904,7 @@ bool SpecialMemberDeletionInfo::shouldDeleteForAllConstMembers() {
/// deleted, as specified in C++11 [class.ctor]p5, C++11 [class.copy]p11,
/// C++11 [class.copy]p23, and C++11 [class.dtor]p5.
bool Sema::ShouldDeleteSpecialMember(CXXMethodDecl *MD, CXXSpecialMember CSM,
+ InheritedConstructorInfo *ICI,
bool Diagnose) {
if (MD->isInvalidDecl())
return false;
@@ -5844,7 +5994,7 @@ bool Sema::ShouldDeleteSpecialMember(CXXMethodDecl *MD, CXXSpecialMember CSM,
}
}
- SpecialMemberDeletionInfo SMI(*this, MD, CSM, Diagnose);
+ SpecialMemberDeletionInfo SMI(*this, MD, CSM, ICI, Diagnose);
for (auto &BI : RD->bases())
if (!BI.isVirtual() &&
@@ -6452,27 +6602,33 @@ void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc,
/// [special]p1). This routine can only be executed just before the
/// definition of the class is complete.
void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
- if (!ClassDecl->hasUserDeclaredConstructor())
+ if (ClassDecl->needsImplicitDefaultConstructor()) {
++ASTContext::NumImplicitDefaultConstructors;
- if (!ClassDecl->hasUserDeclaredCopyConstructor()) {
+ if (ClassDecl->hasInheritedConstructor())
+ DeclareImplicitDefaultConstructor(ClassDecl);
+ }
+
+ if (ClassDecl->needsImplicitCopyConstructor()) {
++ASTContext::NumImplicitCopyConstructors;
// If the properties or semantics of the copy constructor couldn't be
// determined while the class was being declared, force a declaration
// of it now.
- if (ClassDecl->needsOverloadResolutionForCopyConstructor())
+ if (ClassDecl->needsOverloadResolutionForCopyConstructor() ||
+ ClassDecl->hasInheritedConstructor())
DeclareImplicitCopyConstructor(ClassDecl);
}
if (getLangOpts().CPlusPlus11 && ClassDecl->needsImplicitMoveConstructor()) {
++ASTContext::NumImplicitMoveConstructors;
- if (ClassDecl->needsOverloadResolutionForMoveConstructor())
+ if (ClassDecl->needsOverloadResolutionForMoveConstructor() ||
+ ClassDecl->hasInheritedConstructor())
DeclareImplicitMoveConstructor(ClassDecl);
}
- if (!ClassDecl->hasUserDeclaredCopyAssignment()) {
+ if (ClassDecl->needsImplicitCopyAssignment()) {
++ASTContext::NumImplicitCopyAssignmentOperators;
// If we have a dynamic class, then the copy assignment operator may be
@@ -6480,7 +6636,8 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
// it shows up in the right place in the vtable and that we diagnose
// problems with the implicit exception specification.
if (ClassDecl->isDynamicClass() ||
- ClassDecl->needsOverloadResolutionForCopyAssignment())
+ ClassDecl->needsOverloadResolutionForCopyAssignment() ||
+ ClassDecl->hasInheritedAssignment())
DeclareImplicitCopyAssignment(ClassDecl);
}
@@ -6489,11 +6646,12 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
// Likewise for the move assignment operator.
if (ClassDecl->isDynamicClass() ||
- ClassDecl->needsOverloadResolutionForMoveAssignment())
+ ClassDecl->needsOverloadResolutionForMoveAssignment() ||
+ ClassDecl->hasInheritedAssignment())
DeclareImplicitMoveAssignment(ClassDecl);
}
- if (!ClassDecl->hasUserDeclaredDestructor()) {
+ if (ClassDecl->needsImplicitDestructor()) {
++ASTContext::NumImplicitDestructors;
// If we have a dynamic class, then the destructor may be virtual, so we
@@ -7738,7 +7896,7 @@ bool Sema::CheckUsingShadowDecl(UsingDecl *Using, NamedDecl *Orig,
// function will silently decide not to build a shadow decl, which
// will pre-empt further diagnostics.
//
- // We don't need to do this in C++0x because we do the check once on
+ // We don't need to do this in C++11 because we do the check once on
// the qualifier.
//
// FIXME: diagnose the following if we care enough:
@@ -7796,6 +7954,12 @@ bool Sema::CheckUsingShadowDecl(UsingDecl *Using, NamedDecl *Orig,
for (LookupResult::iterator I = Previous.begin(), E = Previous.end();
I != E; ++I) {
NamedDecl *D = (*I)->getUnderlyingDecl();
+ // We can have UsingDecls in our Previous results because we use the same
+ // LookupResult for checking whether the UsingDecl itself is a valid
+ // redeclaration.
+ if (isa<UsingDecl>(D))
+ continue;
+
if (IsEquivalentForUsingDecl(Context, D, Target)) {
if (UsingShadowDecl *Shadow = dyn_cast<UsingShadowDecl>(*I))
PrevShadow = Shadow;
@@ -7863,12 +8027,21 @@ bool Sema::CheckUsingShadowDecl(UsingDecl *Using, NamedDecl *Orig,
return true;
}
+/// Determine whether a direct base class is a virtual base class.
+static bool isVirtualDirectBase(CXXRecordDecl *Derived, CXXRecordDecl *Base) {
+ if (!Derived->getNumVBases())
+ return false;
+ for (auto &B : Derived->bases())
+ if (B.getType()->getAsCXXRecordDecl() == Base)
+ return B.isVirtual();
+ llvm_unreachable("not a direct base class");
+}
+
/// Builds a shadow declaration corresponding to a 'using' declaration.
UsingShadowDecl *Sema::BuildUsingShadowDecl(Scope *S,
UsingDecl *UD,
NamedDecl *Orig,
UsingShadowDecl *PrevDecl) {
-
// If we resolved to another shadow declaration, just coalesce them.
NamedDecl *Target = Orig;
if (isa<UsingShadowDecl>(Target)) {
@@ -7876,9 +8049,21 @@ UsingShadowDecl *Sema::BuildUsingShadowDecl(Scope *S,
assert(!isa<UsingShadowDecl>(Target) && "nested shadow declaration");
}
- UsingShadowDecl *Shadow
- = UsingShadowDecl::Create(Context, CurContext,
- UD->getLocation(), UD, Target);
+ NamedDecl *NonTemplateTarget = Target;
+ if (auto *TargetTD = dyn_cast<TemplateDecl>(Target))
+ NonTemplateTarget = TargetTD->getTemplatedDecl();
+
+ UsingShadowDecl *Shadow;
+ if (isa<CXXConstructorDecl>(NonTemplateTarget)) {
+ bool IsVirtualBase =
+ isVirtualDirectBase(cast<CXXRecordDecl>(CurContext),
+ UD->getQualifier()->getAsRecordDecl());
+ Shadow = ConstructorUsingShadowDecl::Create(
+ Context, CurContext, UD->getLocation(), UD, Orig, IsVirtualBase);
+ } else {
+ Shadow = UsingShadowDecl::Create(Context, CurContext, UD->getLocation(), UD,
+ Target);
+ }
UD->addShadowDecl(Shadow);
Shadow->setAccess(UD->getAccess());
@@ -7980,6 +8165,9 @@ public:
if (Candidate.WillReplaceSpecifier() && !Candidate.getCorrectionSpecifier())
return false;
+ // FIXME: Don't correct to a name that CheckUsingDeclRedeclaration would
+ // reject.
+
if (RequireMemberOf) {
auto *FoundRecord = dyn_cast<CXXRecordDecl>(ND);
if (FoundRecord && FoundRecord->isInjectedClassName()) {
@@ -8060,8 +8248,17 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS,
return nullptr;
}
+ // For an inheriting constructor declaration, the name of the using
+ // declaration is the name of a constructor in this class, not in the
+ // base class.
+ DeclarationNameInfo UsingName = NameInfo;
+ if (UsingName.getName().getNameKind() == DeclarationName::CXXConstructorName)
+ if (auto *RD = dyn_cast<CXXRecordDecl>(CurContext))
+ UsingName.setName(Context.DeclarationNames.getCXXConstructorName(
+ Context.getCanonicalType(Context.getRecordType(RD))));
+
// Do the redeclaration lookup in the current scope.
- LookupResult Previous(*this, NameInfo, LookupUsingDeclName,
+ LookupResult Previous(*this, UsingName, LookupUsingDeclName,
ForRedeclaration);
Previous.setHideTags(false);
if (S) {
@@ -8118,8 +8315,8 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS,
auto Build = [&](bool Invalid) {
UsingDecl *UD =
- UsingDecl::Create(Context, CurContext, UsingLoc, QualifierLoc, NameInfo,
- HasTypenameKeyword);
+ UsingDecl::Create(Context, CurContext, UsingLoc, QualifierLoc,
+ UsingName, HasTypenameKeyword);
UD->setAccess(AS);
CurContext->addDecl(UD);
UD->setInvalidDecl(Invalid);
@@ -8174,6 +8371,9 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS,
// If we corrected to an inheriting constructor, handle it as one.
auto *RD = dyn_cast<CXXRecordDecl>(ND);
if (RD && RD->isInjectedClassName()) {
+ // The parent of the injected class name is the class itself.
+ RD = cast<CXXRecordDecl>(RD->getParent());
+
// Fix up the information we'll use to build the using declaration.
if (Corrected.WillReplaceSpecifier()) {
NestedNameSpecifierLocBuilder Builder;
@@ -8182,13 +8382,19 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS,
QualifierLoc = Builder.getWithLocInContext(Context);
}
- NameInfo.setName(Context.DeclarationNames.getCXXConstructorName(
- Context.getCanonicalType(Context.getRecordType(RD))));
- NameInfo.setNamedTypeInfo(nullptr);
+ // In this case, the name we introduce is the name of a derived class
+ // constructor.
+ auto *CurClass = cast<CXXRecordDecl>(CurContext);
+ UsingName.setName(Context.DeclarationNames.getCXXConstructorName(
+ Context.getCanonicalType(Context.getRecordType(CurClass))));
+ UsingName.setNamedTypeInfo(nullptr);
for (auto *Ctor : LookupConstructors(RD))
R.addDecl(Ctor);
+ R.resolveKind();
} else {
- // FIXME: Pick up all the declarations if we found an overloaded function.
+ // FIXME: Pick up all the declarations if we found an overloaded
+ // function.
+ UsingName.setName(ND->getDeclName());
R.addDecl(ND);
}
} else {
@@ -8221,7 +8427,7 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS,
}
}
- // C++0x N2914 [namespace.udecl]p6:
+ // C++14 [namespace.udecl]p6:
// A using-declaration shall not name a namespace.
if (R.getAsSingle<NamespaceDecl>()) {
Diag(IdentLoc, diag::err_using_decl_can_not_refer_to_namespace)
@@ -8229,19 +8435,28 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS,
return BuildInvalid();
}
+ // C++14 [namespace.udecl]p7:
+ // A using-declaration shall not name a scoped enumerator.
+ if (auto *ED = R.getAsSingle<EnumConstantDecl>()) {
+ if (cast<EnumDecl>(ED->getDeclContext())->isScoped()) {
+ Diag(IdentLoc, diag::err_using_decl_can_not_refer_to_scoped_enum)
+ << SS.getRange();
+ return BuildInvalid();
+ }
+ }
+
UsingDecl *UD = BuildValid();
- // The normal rules do not apply to inheriting constructor declarations.
- if (NameInfo.getName().getNameKind() == DeclarationName::CXXConstructorName) {
+ // Some additional rules apply to inheriting constructors.
+ if (UsingName.getName().getNameKind() ==
+ DeclarationName::CXXConstructorName) {
// Suppress access diagnostics; the access check is instead performed at the
// point of use for an inheriting constructor.
R.suppressDiagnostics();
- CheckInheritingConstructorUsingDecl(UD);
- return UD;
+ if (CheckInheritingConstructorUsingDecl(UD))
+ return UD;
}
- // Otherwise, look up the target name.
-
for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) {
UsingShadowDecl *PrevDecl = nullptr;
if (!CheckUsingShadowDecl(UD, *I, Previous, PrevDecl))
@@ -8353,8 +8568,10 @@ bool Sema::CheckUsingDeclQualifier(SourceLocation UsingLoc,
// If we weren't able to compute a valid scope, it must be a
// dependent class scope.
- if (!NamedContext || NamedContext->isRecord()) {
- auto *RD = dyn_cast_or_null<CXXRecordDecl>(NamedContext);
+ if (!NamedContext || NamedContext->getRedeclContext()->isRecord()) {
+ auto *RD = NamedContext
+ ? cast<CXXRecordDecl>(NamedContext->getRedeclContext())
+ : nullptr;
if (RD && RequireCompleteDeclContext(const_cast<CXXScopeSpec&>(SS), RD))
RD = nullptr;
@@ -8403,6 +8620,20 @@ bool Sema::CheckUsingDeclQualifier(SourceLocation UsingLoc,
Diag(UsingLoc, diag::note_using_decl_class_member_workaround)
<< 2 // reference declaration
<< FixIt;
+ } else if (R.getAsSingle<EnumConstantDecl>()) {
+ // Don't provide a fixit outside C++11 mode; we don't want to suggest
+ // repeating the type of the enumeration here, and we can't do so if
+ // the type is anonymous.
+ FixItHint FixIt;
+ if (getLangOpts().CPlusPlus11) {
+ // Convert 'using X::Y;' to 'auto &Y = X::Y;'.
+ FixIt = FixItHint::CreateReplacement(
+ UsingLoc, "constexpr auto " + NameInfo.getName().getAsString() + " = ");
+ }
+
+ Diag(UsingLoc, diag::note_using_decl_class_member_workaround)
+ << (getLangOpts().CPlusPlus11 ? 4 : 3) // const[expr] variable
+ << FixIt;
}
return true;
}
@@ -8438,7 +8669,7 @@ bool Sema::CheckUsingDeclQualifier(SourceLocation UsingLoc,
return true;
if (getLangOpts().CPlusPlus11) {
- // C++0x [namespace.udecl]p3:
+ // C++11 [namespace.udecl]p3:
// In a using-declaration used as a member-declaration, the
// nested-name-specifier shall name a base class of the class
// being defined.
@@ -8579,6 +8810,10 @@ Decl *Sema::ActOnAliasDeclaration(Scope *S,
}
TemplateParameterList *TemplateParams = TemplateParamLists[0];
+ // Check that we can declare a template here.
+ if (CheckTemplateDeclScope(S, TemplateParams))
+ return nullptr;
+
// Only consider previous declarations in the same scope.
FilterLookupForScope(Previous, CurContext, S, /*ConsiderLinkage*/false,
/*ExplicitInstantiationOrSpecialization*/false);
@@ -8650,9 +8885,7 @@ Decl *Sema::ActOnAliasDeclaration(Scope *S,
NewND = NewTD;
}
- if (!Redeclaration)
- PushOnScopeChains(NewND, S);
-
+ PushOnScopeChains(NewND, S);
ActOnDocumentableDecl(NewND);
return NewND;
}
@@ -8796,7 +9029,8 @@ Sema::ComputeDefaultedDefaultCtorExceptionSpec(SourceLocation Loc,
}
Sema::ImplicitExceptionSpecification
-Sema::ComputeInheritingCtorExceptionSpec(CXXConstructorDecl *CD) {
+Sema::ComputeInheritingCtorExceptionSpec(SourceLocation Loc,
+ CXXConstructorDecl *CD) {
CXXRecordDecl *ClassDecl = CD->getParent();
// C++ [except.spec]p14:
@@ -8805,36 +9039,26 @@ Sema::ComputeInheritingCtorExceptionSpec(CXXConstructorDecl *CD) {
if (ClassDecl->isInvalidDecl())
return ExceptSpec;
- // Inherited constructor.
- const CXXConstructorDecl *InheritedCD = CD->getInheritedConstructor();
- const CXXRecordDecl *InheritedDecl = InheritedCD->getParent();
- // FIXME: Copying or moving the parameters could add extra exceptions to the
- // set, as could the default arguments for the inherited constructor. This
- // will be addressed when we implement the resolution of core issue 1351.
- ExceptSpec.CalledDecl(CD->getLocStart(), InheritedCD);
+ auto Inherited = CD->getInheritedConstructor();
+ InheritedConstructorInfo ICI(*this, Loc, Inherited.getShadowDecl());
- // 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());
- if (BaseClassDecl == InheritedDecl)
+ // 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;
- CXXConstructorDecl *Constructor = LookupDefaultConstructor(BaseClassDecl);
- 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());
- if (BaseClassDecl == InheritedDecl)
+ CXXRecordDecl *BaseClass = B.getType()->getAsCXXRecordDecl();
+ if (!BaseClass)
continue;
- CXXConstructorDecl *Constructor = LookupDefaultConstructor(BaseClassDecl);
+
+ CXXConstructorDecl *Constructor =
+ ICI.findConstructorForBase(BaseClass, Inherited.getConstructor())
+ .first;
+ if (!Constructor)
+ Constructor = LookupDefaultConstructor(BaseClass);
if (Constructor)
ExceptSpec.CalledDecl(B.getLocStart(), Constructor);
}
@@ -8862,10 +9086,11 @@ namespace {
struct DeclaringSpecialMember {
Sema &S;
Sema::SpecialMemberDecl D;
+ Sema::ContextRAII SavedContext;
bool WasAlreadyBeingDeclared;
DeclaringSpecialMember(Sema &S, CXXRecordDecl *RD, Sema::CXXSpecialMember CSM)
- : S(S), D(RD, CSM) {
+ : 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
@@ -8887,6 +9112,21 @@ struct DeclaringSpecialMember {
};
}
+void Sema::CheckImplicitSpecialMemberDeclaration(Scope *S, FunctionDecl *FD) {
+ // Look up any existing declarations, but don't trigger declaration of all
+ // implicit special members with this name.
+ DeclarationName Name = FD->getDeclName();
+ LookupResult R(*this, Name, SourceLocation(), LookupOrdinaryName,
+ ForRedeclaration);
+ for (auto *D : FD->getParent()->lookup(Name))
+ if (auto *Acceptable = R.getAcceptableDecl(D))
+ R.addDecl(Acceptable);
+ R.resolveKind();
+ R.suppressDiagnostics();
+
+ CheckFunctionDeclaration(S, FD, R, /*IsExplicitSpecialization*/false);
+}
+
CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor(
CXXRecordDecl *ClassDecl) {
// C++ [class.ctor]p5:
@@ -8935,13 +9175,16 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor(
// constructors is easy to compute.
DefaultCon->setTrivial(ClassDecl->hasTrivialDefaultConstructor());
- if (ShouldDeleteSpecialMember(DefaultCon, CXXDefaultConstructor))
- SetDeclDeleted(DefaultCon, ClassLoc);
-
// Note that we have declared this constructor.
++ASTContext::NumImplicitDefaultConstructorsDeclared;
- if (Scope *S = getScopeForContext(ClassDecl))
+ Scope *S = getScopeForContext(ClassDecl);
+ CheckImplicitSpecialMemberDeclaration(S, DefaultCon);
+
+ if (ShouldDeleteSpecialMember(DefaultCon, CXXDefaultConstructor))
+ SetDeclDeleted(DefaultCon, ClassLoc);
+
+ if (S)
PushOnScopeChains(DefaultCon, S, false);
ClassDecl->addDecl(DefaultCon);
@@ -8993,325 +9236,167 @@ void Sema::ActOnFinishDelayedMemberInitializers(Decl *D) {
CheckDelayedMemberExceptionSpecs();
}
-namespace {
-/// Information on inheriting constructors to declare.
-class InheritingConstructorInfo {
-public:
- InheritingConstructorInfo(Sema &SemaRef, CXXRecordDecl *Derived)
- : SemaRef(SemaRef), Derived(Derived) {
- // Mark the constructors that we already have in the derived class.
- //
- // C++11 [class.inhctor]p3: [...] a constructor is implicitly declared [...]
- // unless there is a user-declared constructor with the same signature in
- // the class where the using-declaration appears.
- visitAll(Derived, &InheritingConstructorInfo::noteDeclaredInDerived);
- }
+/// Find or create the fake constructor we synthesize to model constructing an
+/// object of a derived class via a constructor of a base class.
+CXXConstructorDecl *
+Sema::findInheritingConstructor(SourceLocation Loc,
+ CXXConstructorDecl *BaseCtor,
+ ConstructorUsingShadowDecl *Shadow) {
+ CXXRecordDecl *Derived = Shadow->getParent();
+ SourceLocation UsingLoc = Shadow->getLocation();
+
+ // FIXME: Add a new kind of DeclarationName for an inherited constructor.
+ // For now we use the name of the base class constructor as a member of the
+ // derived class to indicate a (fake) inherited constructor name.
+ DeclarationName Name = BaseCtor->getDeclName();
+
+ // Check to see if we already have a fake constructor for this inherited
+ // constructor call.
+ for (NamedDecl *Ctor : Derived->lookup(Name))
+ if (declaresSameEntity(cast<CXXConstructorDecl>(Ctor)
+ ->getInheritedConstructor()
+ .getConstructor(),
+ BaseCtor))
+ return cast<CXXConstructorDecl>(Ctor);
+
+ DeclarationNameInfo NameInfo(Name, UsingLoc);
+ TypeSourceInfo *TInfo =
+ Context.getTrivialTypeSourceInfo(BaseCtor->getType(), UsingLoc);
+ FunctionProtoTypeLoc ProtoLoc =
+ TInfo->getTypeLoc().IgnoreParens().castAs<FunctionProtoTypeLoc>();
+
+ // Check the inherited constructor is valid and find the list of base classes
+ // from which it was inherited.
+ InheritedConstructorInfo ICI(*this, Loc, Shadow);
+
+ bool Constexpr =
+ BaseCtor->isConstexpr() &&
+ defaultedSpecialMemberIsConstexpr(*this, Derived, CXXDefaultConstructor,
+ false, BaseCtor, &ICI);
+
+ CXXConstructorDecl *DerivedCtor = CXXConstructorDecl::Create(
+ Context, Derived, UsingLoc, NameInfo, TInfo->getType(), TInfo,
+ BaseCtor->isExplicit(), /*Inline=*/true,
+ /*ImplicitlyDeclared=*/true, Constexpr,
+ InheritedConstructor(Shadow, BaseCtor));
+ if (Shadow->isInvalidDecl())
+ DerivedCtor->setInvalidDecl();
+
+ // Build an unevaluated exception specification for this fake constructor.
+ const FunctionProtoType *FPT = TInfo->getType()->castAs<FunctionProtoType>();
+ FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
+ EPI.ExceptionSpec.Type = EST_Unevaluated;
+ EPI.ExceptionSpec.SourceDecl = DerivedCtor;
+ DerivedCtor->setType(Context.getFunctionType(FPT->getReturnType(),
+ FPT->getParamTypes(), EPI));
- void inheritAll(CXXRecordDecl *RD) {
- visitAll(RD, &InheritingConstructorInfo::inherit);
+ // Build the parameter declarations.
+ SmallVector<ParmVarDecl *, 16> ParamDecls;
+ for (unsigned I = 0, N = FPT->getNumParams(); I != N; ++I) {
+ TypeSourceInfo *TInfo =
+ Context.getTrivialTypeSourceInfo(FPT->getParamType(I), UsingLoc);
+ ParmVarDecl *PD = ParmVarDecl::Create(
+ Context, DerivedCtor, UsingLoc, UsingLoc, /*IdentifierInfo=*/nullptr,
+ FPT->getParamType(I), TInfo, SC_None, /*DefaultArg=*/nullptr);
+ PD->setScopeInfo(0, I);
+ PD->setImplicit();
+ // Ensure attributes are propagated onto parameters (this matters for
+ // format, pass_object_size, ...).
+ mergeDeclAttributes(PD, BaseCtor->getParamDecl(I));
+ ParamDecls.push_back(PD);
+ ProtoLoc.setParam(I, PD);
}
-private:
- /// Information about an inheriting constructor.
- struct InheritingConstructor {
- InheritingConstructor()
- : DeclaredInDerived(false), BaseCtor(nullptr), DerivedCtor(nullptr) {}
-
- /// If \c true, a constructor with this signature is already declared
- /// in the derived class.
- bool DeclaredInDerived;
-
- /// The constructor which is inherited.
- const CXXConstructorDecl *BaseCtor;
-
- /// The derived constructor we declared.
- CXXConstructorDecl *DerivedCtor;
- };
-
- /// Inheriting constructors with a given canonical type. There can be at
- /// most one such non-template constructor, and any number of templated
- /// constructors.
- struct InheritingConstructorsForType {
- InheritingConstructor NonTemplate;
- SmallVector<std::pair<TemplateParameterList *, InheritingConstructor>, 4>
- Templates;
-
- InheritingConstructor &getEntry(Sema &S, const CXXConstructorDecl *Ctor) {
- if (FunctionTemplateDecl *FTD = Ctor->getDescribedFunctionTemplate()) {
- TemplateParameterList *ParamList = FTD->getTemplateParameters();
- for (unsigned I = 0, N = Templates.size(); I != N; ++I)
- if (S.TemplateParameterListsAreEqual(ParamList, Templates[I].first,
- false, S.TPL_TemplateMatch))
- return Templates[I].second;
- Templates.push_back(std::make_pair(ParamList, InheritingConstructor()));
- return Templates.back().second;
- }
+ // Set up the new constructor.
+ assert(!BaseCtor->isDeleted() && "should not use deleted constructor");
+ DerivedCtor->setAccess(BaseCtor->getAccess());
+ DerivedCtor->setParams(ParamDecls);
+ Derived->addDecl(DerivedCtor);
- return NonTemplate;
- }
- };
+ if (ShouldDeleteSpecialMember(DerivedCtor, CXXDefaultConstructor, &ICI))
+ SetDeclDeleted(DerivedCtor, UsingLoc);
- /// Get or create the inheriting constructor record for a constructor.
- InheritingConstructor &getEntry(const CXXConstructorDecl *Ctor,
- QualType CtorType) {
- return Map[CtorType.getCanonicalType()->castAs<FunctionProtoType>()]
- .getEntry(SemaRef, Ctor);
- }
+ return DerivedCtor;
+}
- typedef void (InheritingConstructorInfo::*VisitFn)(const CXXConstructorDecl*);
+void Sema::NoteDeletedInheritingConstructor(CXXConstructorDecl *Ctor) {
+ InheritedConstructorInfo ICI(*this, Ctor->getLocation(),
+ Ctor->getInheritedConstructor().getShadowDecl());
+ ShouldDeleteSpecialMember(Ctor, CXXDefaultConstructor, &ICI,
+ /*Diagnose*/true);
+}
- /// Process all constructors for a class.
- void visitAll(const CXXRecordDecl *RD, VisitFn Callback) {
- for (const auto *Ctor : RD->ctors())
- (this->*Callback)(Ctor);
- for (CXXRecordDecl::specific_decl_iterator<FunctionTemplateDecl>
- I(RD->decls_begin()), E(RD->decls_end());
- I != E; ++I) {
- const FunctionDecl *FD = (*I)->getTemplatedDecl();
- if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(FD))
- (this->*Callback)(CD);
- }
- }
+void Sema::DefineInheritingConstructor(SourceLocation CurrentLocation,
+ CXXConstructorDecl *Constructor) {
+ CXXRecordDecl *ClassDecl = Constructor->getParent();
+ assert(Constructor->getInheritedConstructor() &&
+ !Constructor->doesThisDeclarationHaveABody() &&
+ !Constructor->isDeleted());
+ if (Constructor->isInvalidDecl())
+ return;
- /// Note that a constructor (or constructor template) was declared in Derived.
- void noteDeclaredInDerived(const CXXConstructorDecl *Ctor) {
- getEntry(Ctor, Ctor->getType()).DeclaredInDerived = true;
- }
+ ConstructorUsingShadowDecl *Shadow =
+ Constructor->getInheritedConstructor().getShadowDecl();
+ CXXConstructorDecl *InheritedCtor =
+ Constructor->getInheritedConstructor().getConstructor();
- /// Inherit a single constructor.
- void inherit(const CXXConstructorDecl *Ctor) {
- const FunctionProtoType *CtorType =
- Ctor->getType()->castAs<FunctionProtoType>();
- ArrayRef<QualType> ArgTypes = CtorType->getParamTypes();
- FunctionProtoType::ExtProtoInfo EPI = CtorType->getExtProtoInfo();
+ // [class.inhctor.init]p1:
+ // initialization proceeds as if a defaulted default constructor is used to
+ // initialize the D object and each base class subobject from which the
+ // constructor was inherited
- SourceLocation UsingLoc = getUsingLoc(Ctor->getParent());
+ InheritedConstructorInfo ICI(*this, CurrentLocation, Shadow);
+ CXXRecordDecl *RD = Shadow->getParent();
+ SourceLocation InitLoc = Shadow->getLocation();
- // Core issue (no number yet): the ellipsis is always discarded.
- if (EPI.Variadic) {
- SemaRef.Diag(UsingLoc, diag::warn_using_decl_constructor_ellipsis);
- SemaRef.Diag(Ctor->getLocation(),
- diag::note_using_decl_constructor_ellipsis);
- EPI.Variadic = false;
- }
+ // Initializations are performed "as if by a defaulted default constructor",
+ // so enter the appropriate scope.
+ SynthesizedFunctionScope Scope(*this, Constructor);
+ DiagnosticErrorTrap Trap(Diags);
- // Declare a constructor for each number of parameters.
- //
- // C++11 [class.inhctor]p1:
- // The candidate set of inherited constructors from the class X named in
- // the using-declaration consists of [... modulo defects ...] for each
- // constructor or constructor template of X, the set of constructors or
- // constructor templates that results from omitting any ellipsis parameter
- // specification and successively omitting parameters with a default
- // argument from the end of the parameter-type-list
- unsigned MinParams = minParamsToInherit(Ctor);
- unsigned Params = Ctor->getNumParams();
- if (Params >= MinParams) {
- do
- declareCtor(UsingLoc, Ctor,
- SemaRef.Context.getFunctionType(
- Ctor->getReturnType(), ArgTypes.slice(0, Params), EPI));
- while (Params > MinParams &&
- Ctor->getParamDecl(--Params)->hasDefaultArg());
- }
- }
-
- /// Find the using-declaration which specified that we should inherit the
- /// constructors of \p Base.
- SourceLocation getUsingLoc(const CXXRecordDecl *Base) {
- // No fancy lookup required; just look for the base constructor name
- // directly within the derived class.
- ASTContext &Context = SemaRef.Context;
- DeclarationName Name = Context.DeclarationNames.getCXXConstructorName(
- Context.getCanonicalType(Context.getRecordType(Base)));
- DeclContext::lookup_result Decls = Derived->lookup(Name);
- return Decls.empty() ? Derived->getLocation() : Decls[0]->getLocation();
- }
-
- unsigned minParamsToInherit(const CXXConstructorDecl *Ctor) {
- // C++11 [class.inhctor]p3:
- // [F]or each constructor template in the candidate set of inherited
- // constructors, a constructor template is implicitly declared
- if (Ctor->getDescribedFunctionTemplate())
- return 0;
-
- // For each non-template constructor in the candidate set of inherited
- // constructors other than a constructor having no parameters or a
- // copy/move constructor having a single parameter, a constructor is
- // implicitly declared [...]
- if (Ctor->getNumParams() == 0)
- return 1;
- if (Ctor->isCopyOrMoveConstructor())
- return 2;
-
- // Per discussion on core reflector, never inherit a constructor which
- // would become a default, copy, or move constructor of Derived either.
- const ParmVarDecl *PD = Ctor->getParamDecl(0);
- const ReferenceType *RT = PD->getType()->getAs<ReferenceType>();
- return (RT && RT->getPointeeCXXRecordDecl() == Derived) ? 2 : 1;
- }
-
- /// Declare a single inheriting constructor, inheriting the specified
- /// constructor, with the given type.
- void declareCtor(SourceLocation UsingLoc, const CXXConstructorDecl *BaseCtor,
- QualType DerivedType) {
- InheritingConstructor &Entry = getEntry(BaseCtor, DerivedType);
-
- // C++11 [class.inhctor]p3:
- // ... a constructor is implicitly declared with the same constructor
- // characteristics unless there is a user-declared constructor with
- // the same signature in the class where the using-declaration appears
- if (Entry.DeclaredInDerived)
- return;
+ // Build explicit initializers for all base classes from which the
+ // constructor was inherited.
+ SmallVector<CXXCtorInitializer*, 8> Inits;
+ for (bool VBase : {false, true}) {
+ for (CXXBaseSpecifier &B : VBase ? RD->vbases() : RD->bases()) {
+ if (B.isVirtual() != VBase)
+ continue;
- // C++11 [class.inhctor]p7:
- // If two using-declarations declare inheriting constructors with the
- // same signature, the program is ill-formed
- if (Entry.DerivedCtor) {
- if (BaseCtor->getParent() != Entry.BaseCtor->getParent()) {
- // Only diagnose this once per constructor.
- if (Entry.DerivedCtor->isInvalidDecl())
- return;
- Entry.DerivedCtor->setInvalidDecl();
-
- SemaRef.Diag(UsingLoc, diag::err_using_decl_constructor_conflict);
- SemaRef.Diag(BaseCtor->getLocation(),
- diag::note_using_decl_constructor_conflict_current_ctor);
- SemaRef.Diag(Entry.BaseCtor->getLocation(),
- diag::note_using_decl_constructor_conflict_previous_ctor);
- SemaRef.Diag(Entry.DerivedCtor->getLocation(),
- diag::note_using_decl_constructor_conflict_previous_using);
- } else {
- // Core issue (no number): if the same inheriting constructor is
- // produced by multiple base class constructors from the same base
- // class, the inheriting constructor is defined as deleted.
- SemaRef.SetDeclDeleted(Entry.DerivedCtor, UsingLoc);
- }
+ auto *BaseRD = B.getType()->getAsCXXRecordDecl();
+ if (!BaseRD)
+ continue;
- return;
- }
+ auto BaseCtor = ICI.findConstructorForBase(BaseRD, InheritedCtor);
+ if (!BaseCtor.first)
+ continue;
- ASTContext &Context = SemaRef.Context;
- DeclarationName Name = Context.DeclarationNames.getCXXConstructorName(
- Context.getCanonicalType(Context.getRecordType(Derived)));
- DeclarationNameInfo NameInfo(Name, UsingLoc);
+ MarkFunctionReferenced(CurrentLocation, BaseCtor.first);
+ ExprResult Init = new (Context) CXXInheritedCtorInitExpr(
+ InitLoc, B.getType(), BaseCtor.first, VBase, BaseCtor.second);
- TemplateParameterList *TemplateParams = nullptr;
- if (const FunctionTemplateDecl *FTD =
- BaseCtor->getDescribedFunctionTemplate()) {
- TemplateParams = FTD->getTemplateParameters();
- // We're reusing template parameters from a different DeclContext. This
- // is questionable at best, but works out because the template depth in
- // both places is guaranteed to be 0.
- // FIXME: Rebuild the template parameters in the new context, and
- // transform the function type to refer to them.
+ auto *TInfo = Context.getTrivialTypeSourceInfo(B.getType(), InitLoc);
+ Inits.push_back(new (Context) CXXCtorInitializer(
+ Context, TInfo, VBase, InitLoc, Init.get(), InitLoc,
+ SourceLocation()));
}
-
- // Build type source info pointing at the using-declaration. This is
- // required by template instantiation.
- TypeSourceInfo *TInfo =
- Context.getTrivialTypeSourceInfo(DerivedType, UsingLoc);
- FunctionProtoTypeLoc ProtoLoc =
- TInfo->getTypeLoc().IgnoreParens().castAs<FunctionProtoTypeLoc>();
-
- CXXConstructorDecl *DerivedCtor = CXXConstructorDecl::Create(
- Context, Derived, UsingLoc, NameInfo, DerivedType,
- TInfo, BaseCtor->isExplicit(), /*Inline=*/true,
- /*ImplicitlyDeclared=*/true, /*Constexpr=*/BaseCtor->isConstexpr());
-
- // Build an unevaluated exception specification for this constructor.
- const FunctionProtoType *FPT = DerivedType->castAs<FunctionProtoType>();
- FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
- EPI.ExceptionSpec.Type = EST_Unevaluated;
- EPI.ExceptionSpec.SourceDecl = DerivedCtor;
- DerivedCtor->setType(Context.getFunctionType(FPT->getReturnType(),
- FPT->getParamTypes(), EPI));
-
- // Build the parameter declarations.
- SmallVector<ParmVarDecl *, 16> ParamDecls;
- for (unsigned I = 0, N = FPT->getNumParams(); I != N; ++I) {
- TypeSourceInfo *TInfo =
- Context.getTrivialTypeSourceInfo(FPT->getParamType(I), UsingLoc);
- ParmVarDecl *PD = ParmVarDecl::Create(
- Context, DerivedCtor, UsingLoc, UsingLoc, /*IdentifierInfo=*/nullptr,
- FPT->getParamType(I), TInfo, SC_None, /*DefaultArg=*/nullptr);
- PD->setScopeInfo(0, I);
- PD->setImplicit();
- ParamDecls.push_back(PD);
- ProtoLoc.setParam(I, PD);
- }
-
- // Set up the new constructor.
- DerivedCtor->setAccess(BaseCtor->getAccess());
- DerivedCtor->setParams(ParamDecls);
- DerivedCtor->setInheritedConstructor(BaseCtor);
- if (BaseCtor->isDeleted())
- SemaRef.SetDeclDeleted(DerivedCtor, UsingLoc);
-
- // If this is a constructor template, build the template declaration.
- if (TemplateParams) {
- FunctionTemplateDecl *DerivedTemplate =
- FunctionTemplateDecl::Create(SemaRef.Context, Derived, UsingLoc, Name,
- TemplateParams, DerivedCtor);
- DerivedTemplate->setAccess(BaseCtor->getAccess());
- DerivedCtor->setDescribedFunctionTemplate(DerivedTemplate);
- Derived->addDecl(DerivedTemplate);
- } else {
- Derived->addDecl(DerivedCtor);
- }
-
- Entry.BaseCtor = BaseCtor;
- Entry.DerivedCtor = DerivedCtor;
}
- Sema &SemaRef;
- CXXRecordDecl *Derived;
- typedef llvm::DenseMap<const Type *, InheritingConstructorsForType> MapType;
- MapType Map;
-};
-}
-
-void Sema::DeclareInheritingConstructors(CXXRecordDecl *ClassDecl) {
- // Defer declaring the inheriting constructors until the class is
- // instantiated.
- if (ClassDecl->isDependentContext())
- return;
-
- // Find base classes from which we might inherit constructors.
- SmallVector<CXXRecordDecl*, 4> InheritedBases;
- for (const auto &BaseIt : ClassDecl->bases())
- if (BaseIt.getInheritConstructors())
- InheritedBases.push_back(BaseIt.getType()->getAsCXXRecordDecl());
-
- // Go no further if we're not inheriting any constructors.
- if (InheritedBases.empty())
- return;
-
- // Declare the inherited constructors.
- InheritingConstructorInfo ICI(*this, ClassDecl);
- for (unsigned I = 0, N = InheritedBases.size(); I != N; ++I)
- ICI.inheritAll(InheritedBases[I]);
-}
+ // We now proceed as if for a defaulted default constructor, with the relevant
+ // initializers replaced.
-void Sema::DefineInheritingConstructor(SourceLocation CurrentLocation,
- CXXConstructorDecl *Constructor) {
- CXXRecordDecl *ClassDecl = Constructor->getParent();
- assert(Constructor->getInheritedConstructor() &&
- !Constructor->doesThisDeclarationHaveABody() &&
- !Constructor->isDeleted());
-
- SynthesizedFunctionScope Scope(*this, Constructor);
- DiagnosticErrorTrap Trap(Diags);
- if (SetCtorInitializers(Constructor, /*AnyErrors=*/false) ||
- Trap.hasErrorOccurred()) {
- Diag(CurrentLocation, diag::note_inhctor_synthesized_at)
- << Context.getTagDeclType(ClassDecl);
+ bool HadError = SetCtorInitializers(Constructor, /*AnyErrors*/false, Inits);
+ if (HadError || Trap.hasErrorOccurred()) {
+ Diag(CurrentLocation, diag::note_inhctor_synthesized_at) << RD;
Constructor->setInvalidDecl();
return;
}
- SourceLocation Loc = Constructor->getLocation();
- Constructor->setBody(new (Context) CompoundStmt(Loc));
+ // The exception specification is needed because we are defining the
+ // function.
+ ResolveExceptionSpec(CurrentLocation,
+ Constructor->getType()->castAs<FunctionProtoType>());
+
+ Constructor->setBody(new (Context) CompoundStmt(InitLoc));
Constructor->markUsed(Context);
MarkVTableUsed(CurrentLocation, ClassDecl);
@@ -9319,8 +9404,9 @@ void Sema::DefineInheritingConstructor(SourceLocation CurrentLocation,
if (ASTMutationListener *L = getASTMutationListener()) {
L->CompletedImplicitDefinition(Constructor);
}
-}
+ DiagnoseUninitializedFields(*this, Constructor);
+}
Sema::ImplicitExceptionSpecification
Sema::ComputeDefaultedDtorExceptionSpec(CXXMethodDecl *MD) {
@@ -9397,20 +9483,21 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) {
FunctionProtoType::ExtProtoInfo EPI = getImplicitMethodEPI(*this, Destructor);
Destructor->setType(Context.getFunctionType(Context.VoidTy, None, EPI));
- AddOverriddenMethods(ClassDecl, Destructor);
-
// We don't need to use SpecialMemberIsTrivial here; triviality for
// destructors is easy to compute.
Destructor->setTrivial(ClassDecl->hasTrivialDestructor());
- if (ShouldDeleteSpecialMember(Destructor, CXXDestructor))
- SetDeclDeleted(Destructor, ClassLoc);
-
// Note that we have declared this destructor.
++ASTContext::NumImplicitDestructorsDeclared;
+ Scope *S = getScopeForContext(ClassDecl);
+ CheckImplicitSpecialMemberDeclaration(S, Destructor);
+
+ if (ShouldDeleteSpecialMember(Destructor, CXXDestructor))
+ SetDeclDeleted(Destructor, ClassLoc);
+
// Introduce this destructor into its scope.
- if (Scope *S = getScopeForContext(ClassDecl))
+ if (S)
PushOnScopeChains(Destructor, S, false);
ClassDecl->addDecl(Destructor);
@@ -9533,6 +9620,10 @@ void Sema::ActOnFinishCXXNonNestedClass(Decl *D) {
if (RD && Context.getTargetInfo().getCXXABI().isMicrosoft())
getDefaultArgExprsForConstructors(*this, RD);
+ referenceDLLExportedClassMethods();
+}
+
+void Sema::referenceDLLExportedClassMethods() {
if (!DelayedDllExportClasses.empty()) {
// Calling ReferenceDllExportedMethods might cause the current function to
// be called again, so use a local copy of DelayedDllExportClasses.
@@ -9969,10 +10060,10 @@ buildSingleCopyAssignRecursively(Sema &S, SourceLocation Loc, QualType T,
SizeType, VK_LValue, OK_Ordinary, Loc);
// Construct the loop that copies all elements of this array.
- return S.ActOnForStmt(Loc, Loc, InitStmt,
- S.MakeFullExpr(Comparison),
- nullptr, S.MakeFullDiscardedValueExpr(Increment),
- Loc, Copy.get());
+ return S.ActOnForStmt(
+ Loc, Loc, InitStmt,
+ S.ActOnCondition(nullptr, Loc, Comparison, Sema::ConditionKind::Boolean),
+ S.MakeFullDiscardedValueExpr(Increment), Loc, Copy.get());
}
static StmtResult
@@ -10107,20 +10198,21 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) {
nullptr);
CopyAssignment->setParams(FromParam);
- AddOverriddenMethods(ClassDecl, CopyAssignment);
-
CopyAssignment->setTrivial(
ClassDecl->needsOverloadResolutionForCopyAssignment()
? SpecialMemberIsTrivial(CopyAssignment, CXXCopyAssignment)
: ClassDecl->hasTrivialCopyAssignment());
- if (ShouldDeleteSpecialMember(CopyAssignment, CXXCopyAssignment))
- SetDeclDeleted(CopyAssignment, ClassLoc);
-
// Note that we have added this copy-assignment operator.
++ASTContext::NumImplicitCopyAssignmentOperatorsDeclared;
- if (Scope *S = getScopeForContext(ClassDecl))
+ Scope *S = getScopeForContext(ClassDecl);
+ CheckImplicitSpecialMemberDeclaration(S, CopyAssignment);
+
+ if (ShouldDeleteSpecialMember(CopyAssignment, CXXCopyAssignment))
+ SetDeclDeleted(CopyAssignment, ClassLoc);
+
+ if (S)
PushOnScopeChains(CopyAssignment, S, false);
ClassDecl->addDecl(CopyAssignment);
@@ -10498,22 +10590,23 @@ CXXMethodDecl *Sema::DeclareImplicitMoveAssignment(CXXRecordDecl *ClassDecl) {
nullptr);
MoveAssignment->setParams(FromParam);
- AddOverriddenMethods(ClassDecl, MoveAssignment);
-
MoveAssignment->setTrivial(
ClassDecl->needsOverloadResolutionForMoveAssignment()
? SpecialMemberIsTrivial(MoveAssignment, CXXMoveAssignment)
: ClassDecl->hasTrivialMoveAssignment());
+ // Note that we have added this copy-assignment operator.
+ ++ASTContext::NumImplicitMoveAssignmentOperatorsDeclared;
+
+ Scope *S = getScopeForContext(ClassDecl);
+ CheckImplicitSpecialMemberDeclaration(S, MoveAssignment);
+
if (ShouldDeleteSpecialMember(MoveAssignment, CXXMoveAssignment)) {
ClassDecl->setImplicitMoveAssignmentIsDeleted();
SetDeclDeleted(MoveAssignment, ClassLoc);
}
- // Note that we have added this copy-assignment operator.
- ++ASTContext::NumImplicitMoveAssignmentOperatorsDeclared;
-
- if (Scope *S = getScopeForContext(ClassDecl))
+ if (S)
PushOnScopeChains(MoveAssignment, S, false);
ClassDecl->addDecl(MoveAssignment);
@@ -10939,13 +11032,16 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor(
? SpecialMemberIsTrivial(CopyConstructor, CXXCopyConstructor)
: ClassDecl->hasTrivialCopyConstructor());
- if (ShouldDeleteSpecialMember(CopyConstructor, CXXCopyConstructor))
- SetDeclDeleted(CopyConstructor, ClassLoc);
-
// Note that we have declared this constructor.
++ASTContext::NumImplicitCopyConstructorsDeclared;
- if (Scope *S = getScopeForContext(ClassDecl))
+ Scope *S = getScopeForContext(ClassDecl);
+ CheckImplicitSpecialMemberDeclaration(S, CopyConstructor);
+
+ if (ShouldDeleteSpecialMember(CopyConstructor, CXXCopyConstructor))
+ SetDeclDeleted(CopyConstructor, ClassLoc);
+
+ if (S)
PushOnScopeChains(CopyConstructor, S, false);
ClassDecl->addDecl(CopyConstructor);
@@ -11116,15 +11212,18 @@ CXXConstructorDecl *Sema::DeclareImplicitMoveConstructor(
? SpecialMemberIsTrivial(MoveConstructor, CXXMoveConstructor)
: ClassDecl->hasTrivialMoveConstructor());
+ // Note that we have declared this constructor.
+ ++ASTContext::NumImplicitMoveConstructorsDeclared;
+
+ Scope *S = getScopeForContext(ClassDecl);
+ CheckImplicitSpecialMemberDeclaration(S, MoveConstructor);
+
if (ShouldDeleteSpecialMember(MoveConstructor, CXXMoveConstructor)) {
ClassDecl->setImplicitMoveConstructorIsDeleted();
SetDeclDeleted(MoveConstructor, ClassLoc);
}
- // Note that we have declared this constructor.
- ++ASTContext::NumImplicitMoveConstructorsDeclared;
-
- if (Scope *S = getScopeForContext(ClassDecl))
+ if (S)
PushOnScopeChains(MoveConstructor, S, false);
ClassDecl->addDecl(MoveConstructor);
@@ -11329,6 +11428,7 @@ static bool hasOneRealArgument(MultiExprArg Args) {
ExprResult
Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
+ NamedDecl *FoundDecl,
CXXConstructorDecl *Constructor,
MultiExprArg ExprArgs,
bool HadMultipleCandidates,
@@ -11349,24 +11449,51 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
// with the same cv-unqualified type, the copy/move operation
// can be omitted by constructing the temporary object
// directly into the target of the omitted copy/move
- if (ConstructKind == CXXConstructExpr::CK_Complete &&
+ if (ConstructKind == CXXConstructExpr::CK_Complete && Constructor &&
Constructor->isCopyOrMoveConstructor() && hasOneRealArgument(ExprArgs)) {
Expr *SubExpr = ExprArgs[0];
- Elidable = SubExpr->isTemporaryObject(Context, Constructor->getParent());
+ Elidable = SubExpr->isTemporaryObject(
+ Context, cast<CXXRecordDecl>(FoundDecl->getDeclContext()));
}
- return BuildCXXConstructExpr(ConstructLoc, DeclInitType, Constructor,
+ return BuildCXXConstructExpr(ConstructLoc, DeclInitType,
+ FoundDecl, Constructor,
Elidable, ExprArgs, HadMultipleCandidates,
IsListInitialization,
IsStdInitListInitialization, RequiresZeroInit,
ConstructKind, ParenRange);
}
+ExprResult
+Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
+ NamedDecl *FoundDecl,
+ CXXConstructorDecl *Constructor,
+ bool Elidable,
+ MultiExprArg ExprArgs,
+ bool HadMultipleCandidates,
+ bool IsListInitialization,
+ bool IsStdInitListInitialization,
+ bool RequiresZeroInit,
+ unsigned ConstructKind,
+ SourceRange ParenRange) {
+ if (auto *Shadow = dyn_cast<ConstructorUsingShadowDecl>(FoundDecl)) {
+ Constructor = findInheritingConstructor(ConstructLoc, Constructor, Shadow);
+ if (DiagnoseUseOfDecl(Constructor, ConstructLoc))
+ return ExprError();
+ }
+
+ return BuildCXXConstructExpr(
+ ConstructLoc, DeclInitType, Constructor, Elidable, ExprArgs,
+ HadMultipleCandidates, IsListInitialization, IsStdInitListInitialization,
+ RequiresZeroInit, ConstructKind, ParenRange);
+}
+
/// BuildCXXConstructExpr - Creates a complete call to a constructor,
/// including handling of its default argument expressions.
ExprResult
Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
- CXXConstructorDecl *Constructor, bool Elidable,
+ CXXConstructorDecl *Constructor,
+ bool Elidable,
MultiExprArg ExprArgs,
bool HadMultipleCandidates,
bool IsListInitialization,
@@ -11374,11 +11501,16 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
bool RequiresZeroInit,
unsigned ConstructKind,
SourceRange ParenRange) {
+ assert(declaresSameEntity(
+ Constructor->getParent(),
+ DeclInitType->getBaseElementTypeUnsafe()->getAsCXXRecordDecl()) &&
+ "given constructor for wrong type");
MarkFunctionReferenced(ConstructLoc, Constructor);
+
return CXXConstructExpr::Create(
- Context, DeclInitType, ConstructLoc, Constructor, Elidable, ExprArgs,
- HadMultipleCandidates, IsListInitialization, IsStdInitListInitialization,
- RequiresZeroInit,
+ Context, DeclInitType, ConstructLoc, Constructor, Elidable,
+ ExprArgs, HadMultipleCandidates, IsListInitialization,
+ IsStdInitListInitialization, RequiresZeroInit,
static_cast<CXXConstructExpr::ConstructionKind>(ConstructKind),
ParenRange);
}
@@ -11398,8 +11530,19 @@ ExprResult Sema::BuildCXXDefaultInitExpr(SourceLocation Loc, FieldDecl *Field) {
CXXRecordDecl *ClassPattern = ParentRD->getTemplateInstantiationPattern();
DeclContext::lookup_result Lookup =
ClassPattern->lookup(Field->getDeclName());
- assert(Lookup.size() == 1);
- FieldDecl *Pattern = cast<FieldDecl>(Lookup[0]);
+
+ // Lookup can return at most two results: the pattern for the field, or the
+ // injected class name of the parent record. No other member can have the
+ // same name as the field.
+ assert(!Lookup.empty() && Lookup.size() <= 2 &&
+ "more than two lookup results for field name");
+ FieldDecl *Pattern = dyn_cast<FieldDecl>(Lookup[0]);
+ if (!Pattern) {
+ assert(isa<CXXRecordDecl>(Lookup[0]) &&
+ "cannot have other non-field member with same name");
+ Pattern = cast<FieldDecl>(Lookup[1]);
+ }
+
if (InstantiateInClassInitializer(Loc, Field, Pattern,
getTemplateInstantiationArgs(Field)))
return ExprError();
@@ -11660,7 +11803,7 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) {
diag::err_operator_overload_static) << FnDecl->getDeclName();
} else {
bool ClassOrEnumParam = false;
- for (auto Param : FnDecl->params()) {
+ for (auto Param : FnDecl->parameters()) {
QualType ParamType = Param->getType().getNonReferenceType();
if (ParamType->isDependentType() || ParamType->isRecordType() ||
ParamType->isEnumeralType()) {
@@ -11682,7 +11825,7 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) {
// Only the function-call operator allows default arguments
// (C++ [over.call]p1).
if (Op != OO_Call) {
- for (auto Param : FnDecl->params()) {
+ for (auto Param : FnDecl->parameters()) {
if (Param->hasDefaultArg())
return Diag(Param->getLocation(),
diag::err_operator_overload_default_arg)
@@ -11765,6 +11908,49 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) {
return false;
}
+static bool
+checkLiteralOperatorTemplateParameterList(Sema &SemaRef,
+ FunctionTemplateDecl *TpDecl) {
+ TemplateParameterList *TemplateParams = TpDecl->getTemplateParameters();
+
+ // Must have one or two template parameters.
+ if (TemplateParams->size() == 1) {
+ NonTypeTemplateParmDecl *PmDecl =
+ dyn_cast<NonTypeTemplateParmDecl>(TemplateParams->getParam(0));
+
+ // The template parameter must be a char parameter pack.
+ if (PmDecl && PmDecl->isTemplateParameterPack() &&
+ SemaRef.Context.hasSameType(PmDecl->getType(), SemaRef.Context.CharTy))
+ return false;
+
+ } else if (TemplateParams->size() == 2) {
+ TemplateTypeParmDecl *PmType =
+ dyn_cast<TemplateTypeParmDecl>(TemplateParams->getParam(0));
+ NonTypeTemplateParmDecl *PmArgs =
+ dyn_cast<NonTypeTemplateParmDecl>(TemplateParams->getParam(1));
+
+ // The second template parameter must be a parameter pack with the
+ // first template parameter as its type.
+ if (PmType && PmArgs && !PmType->isTemplateParameterPack() &&
+ PmArgs->isTemplateParameterPack()) {
+ const TemplateTypeParmType *TArgs =
+ PmArgs->getType()->getAs<TemplateTypeParmType>();
+ if (TArgs && TArgs->getDepth() == PmType->getDepth() &&
+ TArgs->getIndex() == PmType->getIndex()) {
+ if (SemaRef.ActiveTemplateInstantiations.empty())
+ SemaRef.Diag(TpDecl->getLocation(),
+ diag::ext_string_literal_operator_template);
+ return false;
+ }
+ }
+ }
+
+ SemaRef.Diag(TpDecl->getTemplateParameters()->getSourceRange().getBegin(),
+ diag::err_literal_operator_template)
+ << TpDecl->getTemplateParameters()->getSourceRange();
+ return true;
+}
+
/// CheckLiteralOperatorDeclaration - Check whether the declaration
/// of this literal operator function is well-formed. If so, returns
/// false; otherwise, emits appropriate diagnostics and returns true.
@@ -11780,10 +11966,9 @@ bool Sema::CheckLiteralOperatorDeclaration(FunctionDecl *FnDecl) {
return true;
}
- bool Valid = false;
-
// This might be the definition of a literal operator template.
FunctionTemplateDecl *TpDecl = FnDecl->getDescribedFunctionTemplate();
+
// This might be a specialization of a literal operator template.
if (!TpDecl)
TpDecl = FnDecl->getPrimaryTemplate();
@@ -11792,104 +11977,120 @@ bool Sema::CheckLiteralOperatorDeclaration(FunctionDecl *FnDecl) {
// template <class T, T...> type operator "" name() are the only valid
// template signatures, and the only valid signatures with no parameters.
if (TpDecl) {
- if (FnDecl->param_size() == 0) {
- // Must have one or two template parameters
- TemplateParameterList *Params = TpDecl->getTemplateParameters();
- if (Params->size() == 1) {
- NonTypeTemplateParmDecl *PmDecl =
- dyn_cast<NonTypeTemplateParmDecl>(Params->getParam(0));
-
- // The template parameter must be a char parameter pack.
- if (PmDecl && PmDecl->isTemplateParameterPack() &&
- Context.hasSameType(PmDecl->getType(), Context.CharTy))
- Valid = true;
- } else if (Params->size() == 2) {
- TemplateTypeParmDecl *PmType =
- dyn_cast<TemplateTypeParmDecl>(Params->getParam(0));
- NonTypeTemplateParmDecl *PmArgs =
- dyn_cast<NonTypeTemplateParmDecl>(Params->getParam(1));
-
- // The second template parameter must be a parameter pack with the
- // first template parameter as its type.
- if (PmType && PmArgs &&
- !PmType->isTemplateParameterPack() &&
- PmArgs->isTemplateParameterPack()) {
- const TemplateTypeParmType *TArgs =
- PmArgs->getType()->getAs<TemplateTypeParmType>();
- if (TArgs && TArgs->getDepth() == PmType->getDepth() &&
- TArgs->getIndex() == PmType->getIndex()) {
- Valid = true;
- if (ActiveTemplateInstantiations.empty())
- Diag(FnDecl->getLocation(),
- diag::ext_string_literal_operator_template);
- }
- }
+ if (FnDecl->param_size() != 0) {
+ Diag(FnDecl->getLocation(),
+ diag::err_literal_operator_template_with_params);
+ return true;
+ }
+
+ if (checkLiteralOperatorTemplateParameterList(*this, TpDecl))
+ return true;
+
+ } else if (FnDecl->param_size() == 1) {
+ const ParmVarDecl *Param = FnDecl->getParamDecl(0);
+
+ QualType ParamType = Param->getType().getUnqualifiedType();
+
+ // Only unsigned long long int, long double, any character type, and const
+ // char * are allowed as the only parameters.
+ if (ParamType->isSpecificBuiltinType(BuiltinType::ULongLong) ||
+ ParamType->isSpecificBuiltinType(BuiltinType::LongDouble) ||
+ Context.hasSameType(ParamType, Context.CharTy) ||
+ Context.hasSameType(ParamType, Context.WideCharTy) ||
+ Context.hasSameType(ParamType, Context.Char16Ty) ||
+ Context.hasSameType(ParamType, Context.Char32Ty)) {
+ } else if (const PointerType *Ptr = ParamType->getAs<PointerType>()) {
+ QualType InnerType = Ptr->getPointeeType();
+
+ // Pointer parameter must be a const char *.
+ if (!(Context.hasSameType(InnerType.getUnqualifiedType(),
+ Context.CharTy) &&
+ InnerType.isConstQualified() && !InnerType.isVolatileQualified())) {
+ Diag(Param->getSourceRange().getBegin(),
+ diag::err_literal_operator_param)
+ << ParamType << "'const char *'" << Param->getSourceRange();
+ return true;
}
+
+ } else if (ParamType->isRealFloatingType()) {
+ Diag(Param->getSourceRange().getBegin(), diag::err_literal_operator_param)
+ << ParamType << Context.LongDoubleTy << Param->getSourceRange();
+ return true;
+
+ } else if (ParamType->isIntegerType()) {
+ Diag(Param->getSourceRange().getBegin(), diag::err_literal_operator_param)
+ << ParamType << Context.UnsignedLongLongTy << Param->getSourceRange();
+ return true;
+
+ } else {
+ Diag(Param->getSourceRange().getBegin(),
+ diag::err_literal_operator_invalid_param)
+ << ParamType << Param->getSourceRange();
+ return true;
}
- } else if (FnDecl->param_size()) {
- // Check the first parameter
+
+ } else if (FnDecl->param_size() == 2) {
FunctionDecl::param_iterator Param = FnDecl->param_begin();
- QualType T = (*Param)->getType().getUnqualifiedType();
-
- // unsigned long long int, long double, and any character type are allowed
- // as the only parameters.
- if (Context.hasSameType(T, Context.UnsignedLongLongTy) ||
- Context.hasSameType(T, Context.LongDoubleTy) ||
- Context.hasSameType(T, Context.CharTy) ||
- Context.hasSameType(T, Context.WideCharTy) ||
- Context.hasSameType(T, Context.Char16Ty) ||
- Context.hasSameType(T, Context.Char32Ty)) {
- if (++Param == FnDecl->param_end())
- Valid = true;
- goto FinishedParams;
- }
-
- // Otherwise it must be a pointer to const; let's strip those qualifiers.
- const PointerType *PT = T->getAs<PointerType>();
- if (!PT)
- goto FinishedParams;
- T = PT->getPointeeType();
- if (!T.isConstQualified() || T.isVolatileQualified())
- goto FinishedParams;
- T = T.getUnqualifiedType();
-
- // Move on to the second parameter;
- ++Param;
+ // First, verify that the first parameter is correct.
- // If there is no second parameter, the first must be a const char *
- if (Param == FnDecl->param_end()) {
- if (Context.hasSameType(T, Context.CharTy))
- Valid = true;
- goto FinishedParams;
+ QualType FirstParamType = (*Param)->getType().getUnqualifiedType();
+
+ // Two parameter function must have a pointer to const as a
+ // first parameter; let's strip those qualifiers.
+ const PointerType *PT = FirstParamType->getAs<PointerType>();
+
+ if (!PT) {
+ Diag((*Param)->getSourceRange().getBegin(),
+ diag::err_literal_operator_param)
+ << FirstParamType << "'const char *'" << (*Param)->getSourceRange();
+ return true;
+ }
+
+ QualType PointeeType = PT->getPointeeType();
+ // First parameter must be const
+ if (!PointeeType.isConstQualified() || PointeeType.isVolatileQualified()) {
+ Diag((*Param)->getSourceRange().getBegin(),
+ diag::err_literal_operator_param)
+ << FirstParamType << "'const char *'" << (*Param)->getSourceRange();
+ return true;
}
- // const char *, const wchar_t*, const char16_t*, and const char32_t*
+ QualType InnerType = PointeeType.getUnqualifiedType();
+ // Only const char *, const wchar_t*, const char16_t*, and const char32_t*
// are allowed as the first parameter to a two-parameter function
- if (!(Context.hasSameType(T, Context.CharTy) ||
- Context.hasSameType(T, Context.WideCharTy) ||
- Context.hasSameType(T, Context.Char16Ty) ||
- Context.hasSameType(T, Context.Char32Ty)))
- goto FinishedParams;
-
- // The second and final parameter must be an std::size_t
- T = (*Param)->getType().getUnqualifiedType();
- if (Context.hasSameType(T, Context.getSizeType()) &&
- ++Param == FnDecl->param_end())
- Valid = true;
- }
-
- // FIXME: This diagnostic is absolutely terrible.
-FinishedParams:
- if (!Valid) {
- Diag(FnDecl->getLocation(), diag::err_literal_operator_params)
- << FnDecl->getDeclName();
+ if (!(Context.hasSameType(InnerType, Context.CharTy) ||
+ Context.hasSameType(InnerType, Context.WideCharTy) ||
+ Context.hasSameType(InnerType, Context.Char16Ty) ||
+ Context.hasSameType(InnerType, Context.Char32Ty))) {
+ Diag((*Param)->getSourceRange().getBegin(),
+ diag::err_literal_operator_param)
+ << FirstParamType << "'const char *'" << (*Param)->getSourceRange();
+ return true;
+ }
+
+ // Move on to the second and final parameter.
+ ++Param;
+
+ // The second parameter must be a std::size_t.
+ QualType SecondParamType = (*Param)->getType().getUnqualifiedType();
+ if (!Context.hasSameType(SecondParamType, Context.getSizeType())) {
+ Diag((*Param)->getSourceRange().getBegin(),
+ diag::err_literal_operator_param)
+ << SecondParamType << Context.getSizeType()
+ << (*Param)->getSourceRange();
+ return true;
+ }
+ } else {
+ Diag(FnDecl->getLocation(), diag::err_literal_operator_bad_param_count);
return true;
}
+ // Parameters are good.
+
// A parameter-declaration-clause containing a default argument is not
// equivalent to any of the permitted forms.
- for (auto Param : FnDecl->params()) {
+ for (auto Param : FnDecl->parameters()) {
if (Param->hasDefaultArg()) {
Diag(Param->getDefaultArgRange().getBegin(),
diag::err_literal_operator_default_argument)
@@ -12003,6 +12204,11 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S,
Invalid = true;
}
+ if (ExDeclType->isVariablyModifiedType()) {
+ Diag(Loc, diag::err_catch_variably_modified) << ExDeclType;
+ Invalid = true;
+ }
+
QualType BaseType = ExDeclType;
int Mode = 0; // 0 for direct type, 1 for pointer, 2 for reference
unsigned DK = diag::err_catch_incomplete;
@@ -12468,10 +12674,9 @@ Decl *Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS,
// friend a member of an arbitrary specialization of your template).
Decl *D;
- if (unsigned NumTempParamLists = TempParams.size())
+ if (!TempParams.empty())
D = FriendTemplateDecl::Create(Context, CurContext, Loc,
- NumTempParamLists,
- TempParams.data(),
+ TempParams,
TSI,
DS.getFriendSpecLoc());
else
@@ -12894,44 +13099,20 @@ void Sema::SetDeclDefaulted(Decl *Dcl, SourceLocation DefaultLoc) {
// the record is complete.
const FunctionDecl *Primary = MD;
if (const FunctionDecl *Pattern = MD->getTemplateInstantiationPattern())
- // Find the uninstantiated declaration that actually had the '= default'
- // on it.
- Pattern->isDefined(Primary);
+ // Ask the template instantiation pattern that actually had the
+ // '= default' on it.
+ Primary = Pattern;
// If the method was defaulted on its first declaration, we will have
// already performed the checking in CheckCompletedCXXClass. Such a
// declaration doesn't trigger an implicit definition.
- if (Primary == Primary->getCanonicalDecl())
+ if (Primary->getCanonicalDecl()->isDefaulted())
return;
CheckExplicitlyDefaultedSpecialMember(MD);
- if (MD->isInvalidDecl())
- return;
-
- switch (Member) {
- case CXXDefaultConstructor:
- DefineImplicitDefaultConstructor(DefaultLoc,
- cast<CXXConstructorDecl>(MD));
- break;
- case CXXCopyConstructor:
- DefineImplicitCopyConstructor(DefaultLoc, cast<CXXConstructorDecl>(MD));
- break;
- case CXXCopyAssignment:
- DefineImplicitCopyAssignment(DefaultLoc, MD);
- break;
- case CXXDestructor:
- DefineImplicitDestructor(DefaultLoc, cast<CXXDestructorDecl>(MD));
- break;
- case CXXMoveConstructor:
- DefineImplicitMoveConstructor(DefaultLoc, cast<CXXConstructorDecl>(MD));
- break;
- case CXXMoveAssignment:
- DefineImplicitMoveAssignment(DefaultLoc, MD);
- break;
- case CXXInvalid:
- llvm_unreachable("Invalid special member.");
- }
+ if (!MD->isInvalidDecl())
+ DefineImplicitSpecialMember(*this, MD, DefaultLoc);
} else {
Diag(DefaultLoc, diag::err_default_special_members);
}
@@ -13020,19 +13201,20 @@ bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New,
return true;
}
- // C++ [class.virtual]p6:
- // If the return type of D::f differs from the return type of B::f, the
- // class type in the return type of D::f shall be complete at the point of
- // declaration of D::f or shall be the class type D.
- if (const RecordType *RT = NewClassTy->getAs<RecordType>()) {
- if (!RT->isBeingDefined() &&
- RequireCompleteType(New->getLocation(), NewClassTy,
- diag::err_covariant_return_incomplete,
- New->getDeclName()))
- return true;
- }
-
if (!Context.hasSameUnqualifiedType(NewClassTy, OldClassTy)) {
+ // C++14 [class.virtual]p8:
+ // If the class type in the covariant return type of D::f differs from
+ // that of B::f, the class type in the return type of D::f shall be
+ // complete at the point of declaration of D::f or shall be the class
+ // type D.
+ if (const RecordType *RT = NewClassTy->getAs<RecordType>()) {
+ if (!RT->isBeingDefined() &&
+ RequireCompleteType(New->getLocation(), NewClassTy,
+ diag::err_covariant_return_incomplete,
+ New->getDeclName()))
+ return true;
+ }
+
// Check if the new class derives from the old class.
if (!IsDerivedFrom(New->getLocation(), NewClassTy, OldClassTy)) {
Diag(New->getLocation(), diag::err_covariant_return_not_derived)
@@ -13069,7 +13251,7 @@ bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New,
Diag(Old->getLocation(), diag::note_overridden_virtual_function)
<< Old->getReturnTypeSourceRange();
return true;
- };
+ }
// The new class type must have the same or less qualifiers as the old type.
@@ -13081,7 +13263,7 @@ bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New,
Diag(Old->getLocation(), diag::note_overridden_virtual_function)
<< Old->getReturnTypeSourceRange();
return true;
- };
+ }
return false;
}
@@ -13240,14 +13422,19 @@ void Sema::MarkVTableUsed(SourceLocation Loc, CXXRecordDecl *Class,
// checks (i.e. operator delete() lookup) when the vtable is marked used, as
// the deleting destructor is emitted with the vtable, not with the
// destructor definition as in the Itanium ABI.
- // If it has a definition, we do the check at that point instead.
- if (Context.getTargetInfo().getCXXABI().isMicrosoft() &&
- Class->hasUserDeclaredDestructor() &&
- !Class->getDestructor()->isDefined() &&
- !Class->getDestructor()->isDeleted()) {
+ if (Context.getTargetInfo().getCXXABI().isMicrosoft()) {
CXXDestructorDecl *DD = Class->getDestructor();
- ContextRAII SavedContext(*this, DD);
- CheckDestructor(DD);
+ if (DD && DD->isVirtual() && !DD->isDeleted()) {
+ if (Class->hasUserDeclaredDestructor() && !DD->isDefined()) {
+ // If this is an out-of-line declaration, marking it referenced will
+ // not do anything. Manually call CheckDestructor to look up operator
+ // delete().
+ ContextRAII SavedContext(*this, DD);
+ CheckDestructor(DD);
+ } else {
+ MarkFunctionReferenced(Loc, Class->getDestructor());
+ }
+ }
}
}
@@ -13785,6 +13972,9 @@ MSPropertyDecl *Sema::HandleMSProperty(Scope *S, RecordDecl *Record,
DiagnoseFunctionSpecifiers(D.getDeclSpec());
+ if (D.getDeclSpec().isInlineSpecified())
+ Diag(D.getDeclSpec().getInlineSpecLoc(), diag::err_inline_non_function)
+ << getLangOpts().CPlusPlus1z;
if (DeclSpec::TSCS TSCS = D.getDeclSpec().getThreadStorageClassSpec())
Diag(D.getDeclSpec().getThreadStorageClassSpecLoc(),
diag::err_invalid_thread)