aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSean Hunt <scshunt@csclub.uwaterloo.ca>2011-05-06 01:42:00 +0000
committerSean Hunt <scshunt@csclub.uwaterloo.ca>2011-05-06 01:42:00 +0000
commitfe2695eec167b28578825576863228f86b392f24 (patch)
tree74e67eb09b681ca0d1d28c1b4637dc5faa2055d9
parent5f802e51406664ca9b6e0d57fc7ce37ea97a1c65 (diff)
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
-rw-r--r--include/clang/AST/Decl.h12
-rw-r--r--include/clang/AST/DeclCXX.h6
-rw-r--r--include/clang/Basic/DiagnosticCommonKinds.td4
-rw-r--r--include/clang/Basic/DiagnosticParseKinds.td3
-rw-r--r--include/clang/Sema/Sema.h9
-rw-r--r--lib/Parse/ParseDecl.cpp4
-rw-r--r--lib/Parse/ParseDeclCXX.cpp11
-rw-r--r--lib/Sema/SemaDecl.cpp63
-rw-r--r--lib/Sema/SemaDeclCXX.cpp7
9 files changed, 103 insertions, 16 deletions
diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h
index ef49205203..2cf2618491 100644
--- a/include/clang/AST/Decl.h
+++ b/include/clang/AST/Decl.h
@@ -1365,6 +1365,8 @@ private:
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 @@ public:
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 88f473eb48..25a75b9ea0 100644
--- a/include/clang/AST/DeclCXX.h
+++ b/include/clang/AST/DeclCXX.h
@@ -1189,6 +1189,12 @@ public:
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 0b0bca0395..166f81a5ff 100644
--- a/include/clang/Basic/DiagnosticCommonKinds.td
+++ b/include/clang/Basic/DiagnosticCommonKinds.td
@@ -52,6 +52,10 @@ def err_invalid_storage_class_in_func_decl : Error<
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 e2d7f4ce9a..3a8a708afa 100644
--- a/include/clang/Basic/DiagnosticParseKinds.td
+++ b/include/clang/Basic/DiagnosticParseKinds.td
@@ -434,6 +434,9 @@ def err_missing_whitespace_digraph : Error<
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 69e14f3c0b..1ce7f6af5b 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -935,7 +935,8 @@ public:
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 @@ public:
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 @@ public:
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 a20e90bd0e..a4c323979d 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -966,6 +966,10 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D,
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 7247c0724e..d263f96e26 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -1648,6 +1648,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
ExprResult BitfieldSize;
ExprResult Init;
bool Deleted = false;
+ SourceLocation DefLoc;
while (1) {
// member-declarator:
@@ -1679,6 +1680,10 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
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 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
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 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
BitfieldSize.release(),
VS, Init.release(),
/*IsDefinition*/Deleted,
- Deleted);
+ Deleted, DefLoc);
}
if (ThisDecl)
DeclsInGroup.push_back(ThisDecl);
@@ -1744,6 +1752,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
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 2a63c91135..0bf984d40a 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -2919,7 +2919,8 @@ bool Sema::DiagnoseClassNameShadow(DeclContext *DC,
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 @@ Decl *Sema::HandleDeclarator(Scope *S, Declarator &D,
<< D.getCXXScopeSpec().getRange();
return 0;
}
-
bool IsDependentContext = DC->isDependentContext();
if (!IsDependentContext &&
@@ -3121,6 +3121,9 @@ Decl *Sema::HandleDeclarator(Scope *S, Declarator &D,
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 @@ Decl *Sema::HandleDeclarator(Scope *S, Declarator &D,
} 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 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
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 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
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 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
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 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
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 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
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 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
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 525cb81c80..ca5fdd1fdd 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -963,7 +963,7 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
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 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
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 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
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;
}