aboutsummaryrefslogtreecommitdiff
path: root/lib
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 /lib
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
Diffstat (limited to 'lib')
-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
4 files changed, 72 insertions, 13 deletions
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;
}