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/include/clang/AST/Decl.h b/include/clang/AST/Decl.h
index ef49205..2cf2618 100644
--- a/include/clang/AST/Decl.h
+++ b/include/clang/AST/Decl.h
@@ -1365,6 +1365,8 @@
bool HasWrittenPrototype : 1;
bool IsDeleted : 1;
bool IsTrivial : 1; // sunk from CXXMethodDecl
+ bool IsDefaulted : 1; // sunk from CXXMethoDecl
+ bool IsExplicitlyDefaulted : 1; //sunk from CXXMethodDecl
bool HasImplicitReturnZero : 1;
bool IsLateTemplateParsed : 1;
@@ -1566,6 +1568,16 @@
bool isTrivial() const { return IsTrivial; }
void setTrivial(bool IT) { IsTrivial = IT; }
+ /// Whether this function is defaulted per C++0x. Only valid for
+ /// special member functions.
+ bool isDefaulted() const { return IsDefaulted; }
+ void setDefaulted(bool D = true) { IsDefaulted = D; }
+
+ /// Whether this function is explicitly defaulted per C++0x. Only valid
+ /// for special member functions.
+ bool isExplicitlyDefaulted() const { return IsExplicitlyDefaulted; }
+ void setExplicitlyDefaulted(bool ED = true) { IsExplicitlyDefaulted = ED; }
+
/// Whether falling off this function implicitly returns null/zero.
/// If a more specific implicit return value is required, front-ends
/// should synthesize the appropriate return statements.
diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h
index 88f473e..25a75b9 100644
--- a/include/clang/AST/DeclCXX.h
+++ b/include/clang/AST/DeclCXX.h
@@ -1189,6 +1189,12 @@
CXXMethodDecl *getCanonicalDecl() {
return cast<CXXMethodDecl>(FunctionDecl::getCanonicalDecl());
}
+
+ /// isUserProvided - True if it is either an implicit constructor or
+ /// if it was defaulted or deleted on first declaration.
+ bool isUserProvided() const {
+ return getCanonicalDecl()->isDeleted() || getCanonicalDecl()->isDefaulted();
+ }
///
void addOverriddenMethod(const CXXMethodDecl *MD);
diff --git a/include/clang/Basic/DiagnosticCommonKinds.td b/include/clang/Basic/DiagnosticCommonKinds.td
index 0b0bca0..166f81a 100644
--- a/include/clang/Basic/DiagnosticCommonKinds.td
+++ b/include/clang/Basic/DiagnosticCommonKinds.td
@@ -52,6 +52,10 @@
def err_expected_namespace_name : Error<"expected namespace name">;
def ext_variadic_templates : ExtWarn<
"variadic templates are a C++0x extension">, InGroup<CXX0x>;
+def err_default_special_members : Error<
+ "Only special member functions may be defaulted">;
+def err_friends_define_only_namespace_scope : Error<
+ "Cannot define a function with non-namespace scope in a friend declaration">;
// Sema && Lex
def ext_longlong : Extension<
diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td
index e2d7f4c..3a8a708 100644
--- a/include/clang/Basic/DiagnosticParseKinds.td
+++ b/include/clang/Basic/DiagnosticParseKinds.td
@@ -434,6 +434,9 @@
def warn_deleted_function_accepted_as_extension: ExtWarn<
"deleted function definition accepted as a C++0x extension">, InGroup<CXX0x>;
+def warn_defaulted_function_accepted_as_extension: ExtWarn<
+ "defaulted function definition accepted as a C++0x extension">,
+ InGroup<CXX0x>;
// C++0x alias-declaration
def ext_alias_declaration : ExtWarn<
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index 69e14f3..1ce7f6a 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -935,7 +935,8 @@
Decl *HandleDeclarator(Scope *S, Declarator &D,
MultiTemplateParamsArg TemplateParameterLists,
- bool IsFunctionDefinition);
+ bool IsFunctionDefinition,
+ SourceLocation DefLoc = SourceLocation());
void RegisterLocallyScopedExternCDecl(NamedDecl *ND,
const LookupResult &Previous,
Scope *S);
@@ -963,7 +964,8 @@
LookupResult &Previous,
MultiTemplateParamsArg TemplateParamLists,
bool IsFunctionDefinition,
- bool &Redeclaration);
+ bool &Redeclaration,
+ SourceLocation DefLoc = SourceLocation());
bool AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD);
void DiagnoseHiddenVirtualMethods(CXXRecordDecl *DC, CXXMethodDecl *MD);
void CheckFunctionDeclaration(Scope *S,
@@ -3063,7 +3065,8 @@
MultiTemplateParamsArg TemplateParameterLists,
Expr *BitfieldWidth, const VirtSpecifiers &VS,
Expr *Init, bool IsDefinition,
- bool Deleted = false);
+ bool Deleted = false,
+ SourceLocation DefLoc = SourceLocation());
MemInitResult ActOnMemInitializer(Decl *ConstructorD,
Scope *S,
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index a20e90b..a4c3239 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -966,6 +966,10 @@
Diag(DelLoc, diag::warn_deleted_function_accepted_as_extension);
Actions.SetDeclDeleted(ThisDecl, DelLoc);
+ } else if (Tok.is(tok::kw_default)) {
+ SourceLocation DefLoc = ConsumeToken();
+
+ Diag(DefLoc, diag::err_default_special_members);
} else {
if (getLang().CPlusPlus && D.getCXXScopeSpec().isSet()) {
EnterScope(0);
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp
index 7247c07..d263f96 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -1648,6 +1648,7 @@
ExprResult BitfieldSize;
ExprResult Init;
bool Deleted = false;
+ SourceLocation DefLoc;
while (1) {
// member-declarator:
@@ -1679,6 +1680,10 @@
Diag(Tok, diag::warn_deleted_function_accepted_as_extension);
ConsumeToken();
Deleted = true;
+ } else if (Tok.is(tok::kw_default)) {
+ if (!getLang().CPlusPlus0x)
+ Diag(Tok, diag::warn_defaulted_function_accepted_as_extension);
+ DefLoc = ConsumeToken();
} else {
Init = ParseInitializer();
if (Init.isInvalid())
@@ -1706,6 +1711,9 @@
Decl *ThisDecl = 0;
if (DS.isFriendSpecified()) {
+ if (DefLoc.isValid())
+ Diag(DefLoc, diag::err_default_special_members);
+
// TODO: handle initializers, bitfields, 'delete'
ThisDecl = Actions.ActOnFriendFunctionDecl(getCurScope(), DeclaratorInfo,
/*IsDefinition*/ false,
@@ -1717,7 +1725,7 @@
BitfieldSize.release(),
VS, Init.release(),
/*IsDefinition*/Deleted,
- Deleted);
+ Deleted, DefLoc);
}
if (ThisDecl)
DeclsInGroup.push_back(ThisDecl);
@@ -1744,6 +1752,7 @@
BitfieldSize = 0;
Init = 0;
Deleted = false;
+ DefLoc = SourceLocation();
// Attributes are only allowed on the second declarator.
MaybeParseGNUAttributes(DeclaratorInfo);
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;
}