Implement support for C++11 in-class initialization of non-static data members.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@132878 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 17b7c9d..9094aba 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -3536,7 +3536,8 @@
SourceLocation(), 0,
FieldTypes[i], /*TInfo=*/0,
/*BitWidth=*/0,
- /*Mutable=*/false);
+ /*Mutable=*/false,
+ /*HasInit=*/false);
Field->setAccess(AS_public);
CFConstantStringTypeDecl->addDecl(Field);
}
@@ -3577,7 +3578,8 @@
SourceLocation(), 0,
FieldTypes[i], /*TInfo=*/0,
/*BitWidth=*/0,
- /*Mutable=*/false);
+ /*Mutable=*/false,
+ /*HasInit=*/false);
Field->setAccess(AS_public);
NSConstantStringTypeDecl->addDecl(Field);
}
@@ -3616,7 +3618,8 @@
SourceLocation(), 0,
FieldTypes[i], /*TInfo=*/0,
/*BitWidth=*/0,
- /*Mutable=*/false);
+ /*Mutable=*/false,
+ /*HasInit=*/false);
Field->setAccess(AS_public);
ObjCFastEnumerationStateTypeDecl->addDecl(Field);
}
@@ -3653,7 +3656,8 @@
&Idents.get(FieldNames[i]),
FieldTypes[i], /*TInfo=*/0,
/*BitWidth=*/0,
- /*Mutable=*/false);
+ /*Mutable=*/false,
+ /*HasInit=*/false);
Field->setAccess(AS_public);
T->addDecl(Field);
}
@@ -3701,7 +3705,8 @@
&Idents.get(FieldNames[i]),
FieldTypes[i], /*TInfo=*/0,
/*BitWidth=*/0,
- /*Mutable=*/false);
+ /*Mutable=*/false,
+ /*HasInit=*/false);
Field->setAccess(AS_public);
T->addDecl(Field);
}
@@ -3786,7 +3791,8 @@
SourceLocation(),
&Idents.get(FieldNames[i]),
FieldTypes[i], /*TInfo=*/0,
- /*BitWidth=*/0, /*Mutable=*/false);
+ /*BitWidth=*/0, /*Mutable=*/false,
+ /*HasInit=*/false);
Field->setAccess(AS_public);
T->addDecl(Field);
}
diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp
index fcca95c..100e604 100644
--- a/lib/AST/ASTImporter.cpp
+++ b/lib/AST/ASTImporter.cpp
@@ -2512,9 +2512,12 @@
FieldDecl *ToField = FieldDecl::Create(Importer.getToContext(), DC,
Importer.Import(D->getInnerLocStart()),
Loc, Name.getAsIdentifierInfo(),
- T, TInfo, BitWidth, D->isMutable());
+ T, TInfo, BitWidth, D->isMutable(),
+ D->hasInClassInitializer());
ToField->setAccess(D->getAccess());
ToField->setLexicalDeclContext(LexicalDC);
+ if (ToField->hasInClassInitializer())
+ ToField->setInClassInitializer(D->getInClassInitializer());
Importer.Imported(D, ToField);
LexicalDC->addDecl(ToField);
return ToField;
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index 1cad64e..12357c0 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -2077,9 +2077,10 @@
FieldDecl *FieldDecl::Create(const ASTContext &C, DeclContext *DC,
SourceLocation StartLoc, SourceLocation IdLoc,
IdentifierInfo *Id, QualType T,
- TypeSourceInfo *TInfo, Expr *BW, bool Mutable) {
+ TypeSourceInfo *TInfo, Expr *BW, bool Mutable,
+ bool HasInit) {
return new (C) FieldDecl(Decl::Field, DC, StartLoc, IdLoc, Id, T, TInfo,
- BW, Mutable);
+ BW, Mutable, HasInit);
}
bool FieldDecl::isAnonymousStructOrUnion() const {
@@ -2124,10 +2125,17 @@
SourceRange FieldDecl::getSourceRange() const {
if (isBitField())
- return SourceRange(getInnerLocStart(), BitWidth->getLocEnd());
+ return SourceRange(getInnerLocStart(), getBitWidth()->getLocEnd());
return DeclaratorDecl::getSourceRange();
}
+void FieldDecl::setInClassInitializer(Expr *Init) {
+ assert(!InitializerOrBitWidth.getPointer() &&
+ "bit width or initializer already set");
+ InitializerOrBitWidth.setPointer(Init);
+ InitializerOrBitWidth.setInt(0);
+}
+
//===----------------------------------------------------------------------===//
// TagDecl Implementation
//===----------------------------------------------------------------------===//
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index 9e82a1a..08ac2a5 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -715,6 +715,22 @@
if (!hasNonLiteralTypeFieldsOrBases() && !T->isLiteralType())
data().HasNonLiteralTypeFieldsOrBases = true;
+ if (Field->hasInClassInitializer()) {
+ // C++0x [class]p5:
+ // A default constructor is trivial if [...] no non-static data member
+ // of its class has a brace-or-equal-initializer.
+ data().HasTrivialDefaultConstructor = false;
+
+ // C++0x [dcl.init.aggr]p1:
+ // An aggregate is a [...] class with [...] no
+ // brace-or-equal-initializers for non-static data members.
+ data().Aggregate = false;
+
+ // C++0x [class]p10:
+ // A POD struct is [...] a trivial class.
+ data().PlainOldData = false;
+ }
+
if (const RecordType *RecordTy = T->getAs<RecordType>()) {
CXXRecordDecl* FieldRec = cast<CXXRecordDecl>(RecordTy->getDecl());
if (FieldRec->getDefinition()) {
@@ -1345,11 +1361,21 @@
SourceLocation CXXCtorInitializer::getSourceLocation() const {
if (isAnyMemberInitializer() || isDelegatingInitializer())
return getMemberLocation();
+
+ if (isInClassMemberInitializer())
+ return getAnyMember()->getLocation();
return getBaseClassLoc().getLocalSourceRange().getBegin();
}
SourceRange CXXCtorInitializer::getSourceRange() const {
+ if (isInClassMemberInitializer()) {
+ FieldDecl *D = getAnyMember();
+ if (Expr *I = D->getInClassInitializer())
+ return I->getSourceRange();
+ return SourceRange();
+ }
+
return SourceRange(getSourceLocation(), getRParenLoc());
}
diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp
index 49f2723..de1b610 100644
--- a/lib/AST/DeclPrinter.cpp
+++ b/lib/AST/DeclPrinter.cpp
@@ -450,62 +450,67 @@
if (D->hasAttr<NoReturnAttr>())
Proto += " __attribute((noreturn))";
if (CXXConstructorDecl *CDecl = dyn_cast<CXXConstructorDecl>(D)) {
- if (CDecl->getNumCtorInitializers() > 0) {
- Proto += " : ";
- Out << Proto;
- Proto.clear();
- for (CXXConstructorDecl::init_const_iterator B = CDecl->init_begin(),
- E = CDecl->init_end();
- B != E; ++B) {
- CXXCtorInitializer * BMInitializer = (*B);
- if (B != CDecl->init_begin())
- Out << ", ";
- if (BMInitializer->isAnyMemberInitializer()) {
- FieldDecl *FD = BMInitializer->getAnyMember();
- Out << FD;
- } else {
- Out << QualType(BMInitializer->getBaseClass(),
- 0).getAsString(Policy);
- }
+ bool HasInitializerList = false;
+ for (CXXConstructorDecl::init_const_iterator B = CDecl->init_begin(),
+ E = CDecl->init_end();
+ B != E; ++B) {
+ CXXCtorInitializer * BMInitializer = (*B);
+ if (BMInitializer->isInClassMemberInitializer())
+ continue;
+
+ if (!HasInitializerList) {
+ Proto += " : ";
+ Out << Proto;
+ Proto.clear();
+ HasInitializerList = true;
+ } else
+ Out << ", ";
+
+ if (BMInitializer->isAnyMemberInitializer()) {
+ FieldDecl *FD = BMInitializer->getAnyMember();
+ Out << FD;
+ } else {
+ Out << QualType(BMInitializer->getBaseClass(),
+ 0).getAsString(Policy);
+ }
+
+ Out << "(";
+ if (!BMInitializer->getInit()) {
+ // Nothing to print
+ } else {
+ Expr *Init = BMInitializer->getInit();
+ if (ExprWithCleanups *Tmp = dyn_cast<ExprWithCleanups>(Init))
+ Init = Tmp->getSubExpr();
- Out << "(";
- if (!BMInitializer->getInit()) {
- // Nothing to print
- } else {
- Expr *Init = BMInitializer->getInit();
- if (ExprWithCleanups *Tmp = dyn_cast<ExprWithCleanups>(Init))
- Init = Tmp->getSubExpr();
-
- Init = Init->IgnoreParens();
-
- Expr *SimpleInit = 0;
- Expr **Args = 0;
- unsigned NumArgs = 0;
- if (ParenListExpr *ParenList = dyn_cast<ParenListExpr>(Init)) {
- Args = ParenList->getExprs();
- NumArgs = ParenList->getNumExprs();
- } else if (CXXConstructExpr *Construct
- = dyn_cast<CXXConstructExpr>(Init)) {
- Args = Construct->getArgs();
- NumArgs = Construct->getNumArgs();
- } else
- SimpleInit = Init;
-
- if (SimpleInit)
- SimpleInit->printPretty(Out, Context, 0, Policy, Indentation);
- else {
- for (unsigned I = 0; I != NumArgs; ++I) {
- if (isa<CXXDefaultArgExpr>(Args[I]))
- break;
-
- if (I)
- Out << ", ";
- Args[I]->printPretty(Out, Context, 0, Policy, Indentation);
- }
+ Init = Init->IgnoreParens();
+
+ Expr *SimpleInit = 0;
+ Expr **Args = 0;
+ unsigned NumArgs = 0;
+ if (ParenListExpr *ParenList = dyn_cast<ParenListExpr>(Init)) {
+ Args = ParenList->getExprs();
+ NumArgs = ParenList->getNumExprs();
+ } else if (CXXConstructExpr *Construct
+ = dyn_cast<CXXConstructExpr>(Init)) {
+ Args = Construct->getArgs();
+ NumArgs = Construct->getNumArgs();
+ } else
+ SimpleInit = Init;
+
+ if (SimpleInit)
+ SimpleInit->printPretty(Out, Context, 0, Policy, Indentation);
+ else {
+ for (unsigned I = 0; I != NumArgs; ++I) {
+ if (isa<CXXDefaultArgExpr>(Args[I]))
+ break;
+
+ if (I)
+ Out << ", ";
+ Args[I]->printPretty(Out, Context, 0, Policy, Indentation);
}
}
- Out << ")";
}
+ Out << ")";
}
}
else
@@ -553,6 +558,12 @@
Out << " : ";
D->getBitWidth()->printPretty(Out, Context, 0, Policy, Indentation);
}
+
+ Expr *Init = D->getInClassInitializer();
+ if (!Policy.SuppressInitializers && Init) {
+ Out << " = ";
+ Init->printPretty(Out, Context, 0, Policy, Indentation);
+ }
}
void DeclPrinter::VisitLabelDecl(LabelDecl *D) {
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index 012701d..9872139 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -22,6 +22,7 @@
#include "clang/AST/StmtVisitor.h"
#include "clang/Lex/LiteralSupport.h"
#include "clang/Lex/Lexer.h"
+#include "clang/Sema/SemaDiagnostic.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
@@ -1653,7 +1654,8 @@
return R;
}
-static Expr::CanThrowResult CanCalleeThrow(ASTContext &Ctx, const Decl *D,
+static Expr::CanThrowResult CanCalleeThrow(ASTContext &Ctx, const Expr *E,
+ const Decl *D,
bool NullThrows = true) {
if (!D)
return NullThrows ? Expr::CT_Can : Expr::CT_Cannot;
@@ -1683,6 +1685,15 @@
if (!FT)
return Expr::CT_Can;
+ if (FT->getExceptionSpecType() == EST_Delayed) {
+ assert(isa<CXXConstructorDecl>(D) &&
+ "only constructor exception specs can be unknown");
+ Ctx.getDiagnostics().Report(E->getLocStart(),
+ diag::err_exception_spec_unknown)
+ << E->getSourceRange();
+ return Expr::CT_Can;
+ }
+
return FT->isNothrow(Ctx) ? Expr::CT_Cannot : Expr::CT_Can;
}
@@ -1757,7 +1768,7 @@
else if (isa<CXXPseudoDestructorExpr>(CE->getCallee()->IgnoreParens()))
CT = CT_Cannot;
else
- CT = CanCalleeThrow(C, CE->getCalleeDecl());
+ CT = CanCalleeThrow(C, this, CE->getCalleeDecl());
if (CT == CT_Can)
return CT;
return MergeCanThrow(CT, CanSubExprsThrow(C, this));
@@ -1765,7 +1776,7 @@
case CXXConstructExprClass:
case CXXTemporaryObjectExprClass: {
- CanThrowResult CT = CanCalleeThrow(C,
+ CanThrowResult CT = CanCalleeThrow(C, this,
cast<CXXConstructExpr>(this)->getConstructor());
if (CT == CT_Can)
return CT;
@@ -1778,8 +1789,8 @@
CT = CT_Dependent;
else
CT = MergeCanThrow(
- CanCalleeThrow(C, cast<CXXNewExpr>(this)->getOperatorNew()),
- CanCalleeThrow(C, cast<CXXNewExpr>(this)->getConstructor(),
+ CanCalleeThrow(C, this, cast<CXXNewExpr>(this)->getOperatorNew()),
+ CanCalleeThrow(C, this, cast<CXXNewExpr>(this)->getConstructor(),
/*NullThrows*/false));
if (CT == CT_Can)
return CT;
@@ -1792,10 +1803,11 @@
if (DTy.isNull() || DTy->isDependentType()) {
CT = CT_Dependent;
} else {
- CT = CanCalleeThrow(C, cast<CXXDeleteExpr>(this)->getOperatorDelete());
+ CT = CanCalleeThrow(C, this,
+ cast<CXXDeleteExpr>(this)->getOperatorDelete());
if (const RecordType *RT = DTy->getAs<RecordType>()) {
const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
- CT = MergeCanThrow(CT, CanCalleeThrow(C, RD->getDestructor()));
+ CT = MergeCanThrow(CT, CanCalleeThrow(C, this, RD->getDestructor()));
}
if (CT == CT_Can)
return CT;
@@ -1805,7 +1817,7 @@
case CXXBindTemporaryExprClass: {
// The bound temporary has to be destroyed again, which might throw.
- CanThrowResult CT = CanCalleeThrow(C,
+ CanThrowResult CT = CanCalleeThrow(C, this,
cast<CXXBindTemporaryExpr>(this)->getTemporary()->getDestructor());
if (CT == CT_Can)
return CT;
diff --git a/lib/AST/Mangle.cpp b/lib/AST/Mangle.cpp
index 3a0b909..c3f3b11 100644
--- a/lib/AST/Mangle.cpp
+++ b/lib/AST/Mangle.cpp
@@ -48,6 +48,11 @@
const DeclContext *ExpectedDC = BD->getDeclContext();
while (isa<BlockDecl>(ExpectedDC) || isa<EnumDecl>(ExpectedDC))
ExpectedDC = ExpectedDC->getParent();
+ // In-class initializers for non-static data members are lexically defined
+ // within the class, but are mangled as if they were specified as constructor
+ // member initializers.
+ if (isa<CXXRecordDecl>(ExpectedDC) && DC != ExpectedDC)
+ DC = DC->getParent();
assert(DC == ExpectedDC && "Given decl context did not match expected!");
#endif
}