Do defaulted constructors properly.
Explictly defaultedness is correctly reflected on the AST, but there are
no changes to how that affects the definition of functions or much else
really.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@130974 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 2a63c91..0bf984d 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -2919,7 +2919,8 @@
Decl *Sema::HandleDeclarator(Scope *S, Declarator &D,
MultiTemplateParamsArg TemplateParamLists,
- bool IsFunctionDefinition) {
+ bool IsFunctionDefinition,
+ SourceLocation DefLoc) {
// TODO: consider using NameInfo for diagnostic.
DeclarationNameInfo NameInfo = GetNameForDeclarator(D);
DeclarationName Name = NameInfo.getName();
@@ -2962,7 +2963,6 @@
<< D.getCXXScopeSpec().getRange();
return 0;
}
-
bool IsDependentContext = DC->isDependentContext();
if (!IsDependentContext &&
@@ -3121,6 +3121,9 @@
bool Redeclaration = false;
if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef) {
+ if (DefLoc.isValid())
+ Diag(DefLoc, diag::err_default_special_members);
+
if (TemplateParamLists.size()) {
Diag(D.getIdentifierLoc(), diag::err_template_typedef);
return 0;
@@ -3130,8 +3133,9 @@
} else if (R->isFunctionType()) {
New = ActOnFunctionDeclarator(S, D, DC, R, TInfo, Previous,
move(TemplateParamLists),
- IsFunctionDefinition, Redeclaration);
+ IsFunctionDefinition, Redeclaration, DefLoc);
} else {
+ assert(!DefLoc.isValid() && "We should have caught this in a caller");
New = ActOnVariableDeclarator(S, D, DC, R, TInfo, Previous,
move(TemplateParamLists),
Redeclaration);
@@ -4003,7 +4007,8 @@
QualType R, TypeSourceInfo *TInfo,
LookupResult &Previous,
MultiTemplateParamsArg TemplateParamLists,
- bool IsFunctionDefinition, bool &Redeclaration) {
+ bool IsFunctionDefinition, bool &Redeclaration,
+ SourceLocation DefLoc) {
assert(R.getTypePtr()->isFunctionType());
// TODO: consider using NameInfo for diagnostic.
@@ -4060,6 +4065,8 @@
bool isFunctionTemplateSpecialization = false;
if (!getLangOptions().CPlusPlus) {
+ assert(!DefLoc.isValid() && "Defaulted functions are a C++ feature");
+
// Determine whether the function was written with a
// prototype. This true when:
// - there is a prototype in the declarator, or
@@ -4104,12 +4111,25 @@
R = CheckConstructorDeclarator(D, R, SC);
// Create the new declaration
- NewFD = CXXConstructorDecl::Create(Context,
+ CXXConstructorDecl *NewCD = CXXConstructorDecl::Create(
+ Context,
cast<CXXRecordDecl>(DC),
D.getSourceRange().getBegin(),
NameInfo, R, TInfo,
isExplicit, isInline,
/*isImplicitlyDeclared=*/false);
+
+ NewFD = NewCD;
+
+ if (DefLoc.isValid()) {
+ if (NewCD->isDefaultConstructor() ||
+ NewCD->isCopyOrMoveConstructor()) {
+ NewFD->setDefaulted();
+ NewFD->setExplicitlyDefaulted();
+ } else {
+ Diag(DefLoc, diag::err_default_special_members);
+ }
+ }
} else if (Name.getNameKind() == DeclarationName::CXXDestructorName) {
// This is a C++ destructor declaration.
if (DC->isRecord()) {
@@ -4122,6 +4142,11 @@
isInline,
/*isImplicitlyDeclared=*/false);
isVirtualOkay = true;
+
+ if (DefLoc.isValid()) {
+ NewFD->setDefaulted();
+ NewFD->setExplicitlyDefaulted();
+ }
} else {
Diag(D.getIdentifierLoc(), diag::err_destructor_not_member);
@@ -4140,6 +4165,9 @@
return 0;
}
+ if (DefLoc.isValid())
+ Diag(DefLoc, diag::err_default_special_members);
+
CheckConversionDeclarator(D, R, SC);
NewFD = CXXConversionDecl::Create(Context, cast<CXXRecordDecl>(DC),
D.getSourceRange().getBegin(),
@@ -4178,14 +4206,29 @@
isStatic = true;
// This is a C++ method declaration.
- NewFD = CXXMethodDecl::Create(Context, cast<CXXRecordDecl>(DC),
- D.getSourceRange().getBegin(),
- NameInfo, R, TInfo,
- isStatic, SCAsWritten, isInline,
- SourceLocation());
+ CXXMethodDecl *NewMD = CXXMethodDecl::Create(
+ Context, cast<CXXRecordDecl>(DC),
+ D.getSourceRange().getBegin(),
+ NameInfo, R, TInfo,
+ isStatic, SCAsWritten, isInline,
+ SourceLocation());
+ NewFD = NewMD;
isVirtualOkay = !isStatic;
+
+ if (DefLoc.isValid()) {
+ if (NewMD->isCopyAssignmentOperator() /* ||
+ NewMD->isMoveAssignmentOperator() */) {
+ NewFD->setDefaulted();
+ NewFD->setExplicitlyDefaulted();
+ } else {
+ Diag(DefLoc, diag::err_default_special_members);
+ }
+ }
} else {
+ if (DefLoc.isValid())
+ Diag(DefLoc, diag::err_default_special_members);
+
// Determine whether the function was written with a
// prototype. This true when:
// - we're in C++ (where every function has a prototype),
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 525cb81..ca5fdd1 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -963,7 +963,7 @@
MultiTemplateParamsArg TemplateParameterLists,
ExprTy *BW, const VirtSpecifiers &VS,
ExprTy *InitExpr, bool IsDefinition,
- bool Deleted) {
+ bool Deleted, SourceLocation DefLoc) {
const DeclSpec &DS = D.getDeclSpec();
DeclarationNameInfo NameInfo = GetNameForDeclarator(D);
DeclarationName Name = NameInfo.getName();
@@ -1028,6 +1028,8 @@
if (isInstField) {
CXXScopeSpec &SS = D.getCXXScopeSpec();
+ if (DefLoc.isValid())
+ Diag(DefLoc, diag::err_default_special_members);
if (SS.isSet() && !SS.isInvalid()) {
// The user provided a superfluous scope specifier inside a class
@@ -1053,7 +1055,8 @@
AS);
assert(Member && "HandleField never returns null");
} else {
- Member = HandleDeclarator(S, D, move(TemplateParameterLists), IsDefinition);
+ Member = HandleDeclarator(S, D, move(TemplateParameterLists), IsDefinition,
+ DefLoc);
if (!Member) {
return 0;
}