[cfe-commits] r132878 - in /cfe/trunk: include/clang/AST/ include/clang/Basic/ include/clang/Parse/ include/clang/Sema/ lib/AST/ lib/CodeGen/ lib/Parse/ lib/Rewrite/ lib/Sema/ lib/Serialization/ test/CXX/class/class.mem/ test/CXX/dcl.dcl/dcl.spec/dcl.type/ test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/ test/CXX/dcl.decl/dcl.init/ test/CXX/dcl.decl/dcl.init/dcl.init.aggr/ test/CXX/except/except.spec/ test/CXX/expr/expr.prim/ test/CXX/special/class.ctor/ test/CXX/special/class.init/class.base.init/ test/CodeGenCXX/ t...
Richard Smith
richard-llvm at metafoo.co.uk
Sat Jun 11 10:19:42 PDT 2011
Author: rsmith
Date: Sat Jun 11 12:19:42 2011
New Revision: 132878
URL: http://llvm.org/viewvc/llvm-project?rev=132878&view=rev
Log:
Implement support for C++11 in-class initialization of non-static data members.
Added:
cfe/trunk/test/CXX/class/class.mem/p5-0x.cpp
cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.aggr/p1-0x.cpp
cfe/trunk/test/CXX/dcl.decl/dcl.init/p14-0x.cpp
cfe/trunk/test/CXX/expr/expr.prim/p12-0x.cpp
cfe/trunk/test/CXX/expr/expr.prim/p4-0x.cpp
cfe/trunk/test/CXX/special/class.ctor/p5-0x.cpp
cfe/trunk/test/CXX/special/class.init/class.base.init/p8-0x.cpp
cfe/trunk/test/CXX/special/class.init/class.base.init/p9-0x.cpp
cfe/trunk/test/CodeGenCXX/member-init-ctor.cpp
cfe/trunk/test/PCH/cxx-member-init.cpp
cfe/trunk/test/Parser/cxx0x-member-initializers.cpp
cfe/trunk/test/SemaCXX/implicit-exception-spec.cpp
cfe/trunk/test/SemaCXX/member-init.cpp
Modified:
cfe/trunk/include/clang/AST/Decl.h
cfe/trunk/include/clang/AST/DeclCXX.h
cfe/trunk/include/clang/AST/DeclObjC.h
cfe/trunk/include/clang/AST/Type.h
cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
cfe/trunk/include/clang/Basic/ExceptionSpecificationType.h
cfe/trunk/include/clang/Parse/Parser.h
cfe/trunk/include/clang/Sema/DeclSpec.h
cfe/trunk/include/clang/Sema/Scope.h
cfe/trunk/include/clang/Sema/Sema.h
cfe/trunk/lib/AST/ASTContext.cpp
cfe/trunk/lib/AST/ASTImporter.cpp
cfe/trunk/lib/AST/Decl.cpp
cfe/trunk/lib/AST/DeclCXX.cpp
cfe/trunk/lib/AST/DeclPrinter.cpp
cfe/trunk/lib/AST/Expr.cpp
cfe/trunk/lib/AST/Mangle.cpp
cfe/trunk/lib/CodeGen/CGBlocks.cpp
cfe/trunk/lib/CodeGen/CGClass.cpp
cfe/trunk/lib/CodeGen/CGObjCMac.cpp
cfe/trunk/lib/Parse/ParseCXXInlineMethods.cpp
cfe/trunk/lib/Parse/ParseDeclCXX.cpp
cfe/trunk/lib/Parse/Parser.cpp
cfe/trunk/lib/Rewrite/RewriteObjC.cpp
cfe/trunk/lib/Sema/SemaDecl.cpp
cfe/trunk/lib/Sema/SemaDeclCXX.cpp
cfe/trunk/lib/Sema/SemaExceptionSpec.cpp
cfe/trunk/lib/Sema/SemaExpr.cpp
cfe/trunk/lib/Sema/SemaExprCXX.cpp
cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
cfe/trunk/lib/Sema/SemaType.cpp
cfe/trunk/lib/Sema/TreeTransform.h
cfe/trunk/lib/Serialization/ASTReaderDecl.cpp
cfe/trunk/lib/Serialization/ASTWriterDecl.cpp
cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p4.cpp
cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp
cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.type/p3-0x.cpp
cfe/trunk/test/CXX/except/except.spec/p14.cpp
cfe/trunk/test/CodeGenObjCXX/blocks.mm
cfe/trunk/test/SemaCXX/PR9572.cpp
cfe/trunk/test/SemaCXX/class.cpp
cfe/trunk/test/SemaCXX/type-traits.cpp
Modified: cfe/trunk/include/clang/AST/Decl.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Decl.h?rev=132878&r1=132877&r2=132878&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Decl.h (original)
+++ cfe/trunk/include/clang/AST/Decl.h Sat Jun 11 12:19:42 2011
@@ -1953,20 +1953,33 @@
bool Mutable : 1;
mutable unsigned CachedFieldIndex : 31;
- Expr *BitWidth;
+ /// \brief A pointer to either the in-class initializer for this field (if
+ /// the boolean value is false), or the bit width expression for this bit
+ /// field (if the boolean value is true).
+ ///
+ /// We can safely combine these two because in-class initializers are not
+ /// permitted for bit-fields.
+ ///
+ /// If the boolean is false and the initializer is null, then this field has
+ /// an in-class initializer which has not yet been parsed and attached.
+ llvm::PointerIntPair<Expr *, 1, bool> InitializerOrBitWidth;
protected:
FieldDecl(Kind DK, DeclContext *DC, SourceLocation StartLoc,
SourceLocation IdLoc, IdentifierInfo *Id,
- QualType T, TypeSourceInfo *TInfo, Expr *BW, bool Mutable)
+ QualType T, TypeSourceInfo *TInfo, Expr *BW, bool Mutable,
+ bool HasInit)
: DeclaratorDecl(DK, DC, IdLoc, Id, T, TInfo, StartLoc),
- Mutable(Mutable), CachedFieldIndex(0), BitWidth(BW) {
+ Mutable(Mutable), CachedFieldIndex(0),
+ InitializerOrBitWidth(BW, !HasInit) {
+ assert(!(BW && HasInit) && "got initializer for bitfield");
}
public:
static 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);
/// getFieldIndex - Returns the index of this field within its record,
/// as appropriate for passing to ASTRecordLayout::getFieldOffset.
@@ -1979,10 +1992,12 @@
void setMutable(bool M) { Mutable = M; }
/// isBitfield - Determines whether this field is a bitfield.
- bool isBitField() const { return BitWidth != NULL; }
+ bool isBitField() const {
+ return InitializerOrBitWidth.getInt() && InitializerOrBitWidth.getPointer();
+ }
/// @brief Determines whether this is an unnamed bitfield.
- bool isUnnamedBitfield() const { return BitWidth != NULL && !getDeclName(); }
+ bool isUnnamedBitfield() const { return isBitField() && !getDeclName(); }
/// isAnonymousStructOrUnion - Determines whether this field is a
/// representative for an anonymous struct or union. Such fields are
@@ -1990,8 +2005,37 @@
/// store the data for the anonymous union or struct.
bool isAnonymousStructOrUnion() const;
- Expr *getBitWidth() const { return BitWidth; }
- void setBitWidth(Expr *BW) { BitWidth = BW; }
+ Expr *getBitWidth() const {
+ return isBitField() ? InitializerOrBitWidth.getPointer() : 0;
+ }
+ void setBitWidth(Expr *BW) {
+ assert(!InitializerOrBitWidth.getPointer() &&
+ "bit width or initializer already set");
+ InitializerOrBitWidth.setPointer(BW);
+ InitializerOrBitWidth.setInt(1);
+ }
+
+ /// hasInClassInitializer - Determine whether this member has a C++0x in-class
+ /// initializer.
+ bool hasInClassInitializer() const {
+ return !InitializerOrBitWidth.getInt();
+ }
+ /// getInClassInitializer - Get the C++0x in-class initializer for this
+ /// member, or null if one has not been set. If a valid declaration has an
+ /// in-class initializer, but this returns null, then we have not parsed and
+ /// attached it yet.
+ Expr *getInClassInitializer() const {
+ return hasInClassInitializer() ? InitializerOrBitWidth.getPointer() : 0;
+ }
+ /// setInClassInitializer - Set the C++0x in-class initializer for this member.
+ void setInClassInitializer(Expr *Init);
+ /// removeInClassInitializer - Remove the C++0x in-class initializer from this
+ /// member.
+ void removeInClassInitializer() {
+ assert(!InitializerOrBitWidth.getInt() && "no initializer to remove");
+ InitializerOrBitWidth.setPointer(0);
+ InitializerOrBitWidth.setInt(1);
+ }
/// getParent - Returns the parent of this field declaration, which
/// is the struct in which this method is defined.
Modified: cfe/trunk/include/clang/AST/DeclCXX.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclCXX.h?rev=132878&r1=132877&r2=132878&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclCXX.h (original)
+++ cfe/trunk/include/clang/AST/DeclCXX.h Sat Jun 11 12:19:42 2011
@@ -1378,6 +1378,8 @@
/// \brief The argument used to initialize the base or member, which may
/// end up constructing an object (when multiple arguments are involved).
+ /// If 0, this is a field initializer, and the in-class member initializer
+ /// will be used.
Stmt *Init;
/// LParenLoc - Location of the left paren of the ctor-initializer.
@@ -1452,6 +1454,13 @@
return Initializee.is<IndirectFieldDecl*>();
}
+ /// isInClassMemberInitializer - Returns true when this initializer is an
+ /// implicit ctor initializer generated for a field with an initializer
+ /// defined on the member declaration.
+ bool isInClassMemberInitializer() const {
+ return !Init;
+ }
+
/// isDelegatingInitializer - Returns true when this initializer is creating
/// a delegating constructor.
bool isDelegatingInitializer() const {
@@ -1580,7 +1589,14 @@
reinterpret_cast<VarDecl **>(this + 1)[I] = Index;
}
- Expr *getInit() const { return static_cast<Expr *>(Init); }
+ /// \brief Get the initializer. This is 0 if this is an in-class initializer
+ /// for a non-static data member which has not yet been parsed.
+ Expr *getInit() const {
+ if (!Init)
+ return getAnyMember()->getInClassInitializer();
+
+ return static_cast<Expr*>(Init);
+ }
};
/// CXXConstructorDecl - Represents a C++ constructor within a
Modified: cfe/trunk/include/clang/AST/DeclObjC.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclObjC.h?rev=132878&r1=132877&r2=132878&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclObjC.h (original)
+++ cfe/trunk/include/clang/AST/DeclObjC.h Sat Jun 11 12:19:42 2011
@@ -724,7 +724,7 @@
QualType T, TypeSourceInfo *TInfo, AccessControl ac, Expr *BW,
bool synthesized)
: FieldDecl(ObjCIvar, DC, StartLoc, IdLoc, Id, T, TInfo, BW,
- /*Mutable=*/false),
+ /*Mutable=*/false, /*HasInit=*/false),
NextIvar(0), DeclAccess(ac), Synthesized(synthesized) {}
public:
@@ -779,7 +779,7 @@
QualType T, Expr *BW)
: FieldDecl(ObjCAtDefsField, DC, StartLoc, IdLoc, Id, T,
/*TInfo=*/0, // FIXME: Do ObjCAtDefs have declarators ?
- BW, /*Mutable=*/false) {}
+ BW, /*Mutable=*/false, /*HasInit=*/false) {}
public:
static ObjCAtDefsFieldDecl *Create(ASTContext &C, DeclContext *DC,
Modified: cfe/trunk/include/clang/AST/Type.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Type.h?rev=132878&r1=132877&r2=132878&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Type.h (original)
+++ cfe/trunk/include/clang/AST/Type.h Sat Jun 11 12:19:42 2011
@@ -2604,6 +2604,7 @@
}
bool isNothrow(ASTContext &Ctx) const {
ExceptionSpecificationType EST = getExceptionSpecType();
+ assert(EST != EST_Delayed);
if (EST == EST_DynamicNone || EST == EST_BasicNoexcept)
return true;
if (EST != EST_ComputedNoexcept)
Modified: cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td?rev=132878&r1=132877&r2=132878&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td Sat Jun 11 12:19:42 2011
@@ -193,6 +193,8 @@
"reference qualifiers on functions are a C++0x extension">, InGroup<CXX0x>;
def ext_inline_namespace : ExtWarn<
"inline namespaces are a C++0x feature">, InGroup<CXX0x>;
+def err_generalized_initializer_lists : Error<
+ "generalized initializer lists are a C++0x extension unsupported in Clang">;
def ext_generalized_initializer_lists : ExtWarn<
"generalized initializer lists are a C++0x extension unsupported in Clang">,
InGroup<CXX0x>;
@@ -444,6 +446,15 @@
"defaulted function definition accepted as a C++0x extension">,
InGroup<CXX0x>;
+// C++0x in-class member initialization
+def warn_nonstatic_member_init_accepted_as_extension: ExtWarn<
+ "in-class initialization of non-static data member accepted as a C++0x extension">,
+ InGroup<CXX0x>;
+def err_bitfield_member_init: Error<
+ "bitfield member cannot have an in-class initializer">;
+def err_incomplete_array_member_init: Error<
+ "array bound cannot be deduced from an in-class initializer">;
+
// C++0x alias-declaration
def ext_alias_declaration : ExtWarn<
"alias declarations accepted as a C++0x extension">, InGroup<CXX0x>;
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=132878&r1=132877&r2=132878&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Sat Jun 11 12:19:42 2011
@@ -589,6 +589,8 @@
"%0 is missing exception specification '%1'">;
def err_noexcept_needs_constant_expression : Error<
"argument to noexcept specifier must be a constant expression">;
+def err_exception_spec_unknown : Error<
+ "exception specification is not available until end of class definition">;
// C++ access checking
def err_class_redeclared_with_different_access : Error<
@@ -973,8 +975,8 @@
def err_new_array_of_auto : Error<
"cannot allocate array of 'auto'">;
def err_auto_not_allowed : Error<
- "'auto' not allowed %select{in function prototype|in struct member"
- "|in union member|in class member|in exception declaration"
+ "'auto' not allowed %select{in function prototype|in non-static struct member"
+ "|in non-static union member|in non-static class member|in exception declaration"
"|in template parameter|in block literal|in template argument"
"|in typedef|in type alias|in function return type|here}0">;
def err_auto_var_requires_init : Error<
Modified: cfe/trunk/include/clang/Basic/ExceptionSpecificationType.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/ExceptionSpecificationType.h?rev=132878&r1=132877&r2=132878&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/ExceptionSpecificationType.h (original)
+++ cfe/trunk/include/clang/Basic/ExceptionSpecificationType.h Sat Jun 11 12:19:42 2011
@@ -18,12 +18,13 @@
/// \brief The various types of exception specifications that exist in C++0x.
enum ExceptionSpecificationType {
- EST_None, ///< no exception specification
- EST_DynamicNone, ///< throw()
- EST_Dynamic, ///< throw(T1, T2)
- EST_MSAny, ///< Microsoft throw(...) extension
- EST_BasicNoexcept, ///< noexcept
- EST_ComputedNoexcept ///< noexcept(expression)
+ EST_None, ///< no exception specification
+ EST_DynamicNone, ///< throw()
+ EST_Dynamic, ///< throw(T1, T2)
+ EST_MSAny, ///< Microsoft throw(...) extension
+ EST_BasicNoexcept, ///< noexcept
+ EST_ComputedNoexcept, ///< noexcept(expression)
+ EST_Delayed ///< not known yet
};
inline bool isDynamicExceptionSpec(ExceptionSpecificationType ESpecType) {
Modified: cfe/trunk/include/clang/Parse/Parser.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=132878&r1=132877&r2=132878&view=diff
==============================================================================
--- cfe/trunk/include/clang/Parse/Parser.h (original)
+++ cfe/trunk/include/clang/Parse/Parser.h Sat Jun 11 12:19:42 2011
@@ -580,6 +580,18 @@
/// ExitScope - Pop a scope off the scope stack.
void ExitScope();
+ /// \brief RAII object used to modify the scope flags for the current scope.
+ class ParseScopeFlags {
+ Scope *CurScope;
+ unsigned OldFlags;
+ ParseScopeFlags(const ParseScopeFlags &); // do not implement
+ void operator=(const ParseScopeFlags &); // do not implement
+
+ public:
+ ParseScopeFlags(Parser *Self, unsigned ScopeFlags, bool ManageFlags = true);
+ ~ParseScopeFlags();
+ };
+
//===--------------------------------------------------------------------===//
// Diagnostic Emission and Error recovery.
@@ -621,8 +633,8 @@
/// - function bodies
/// - default arguments
/// - exception-specifications (TODO: C++0x)
- /// - and brace-or-equal-initializers (TODO: C++0x)
- /// for non-static data members (including such things in nested classes)."
+ /// - and brace-or-equal-initializers for non-static data members
+ /// (including such things in nested classes)."
/// LateParsedDeclarations build the tree of those elements so they can
/// be parsed after parsing the top-level class.
class LateParsedDeclaration {
@@ -630,6 +642,7 @@
virtual ~LateParsedDeclaration();
virtual void ParseLexedMethodDeclarations();
+ virtual void ParseLexedMemberInitializers();
virtual void ParseLexedMethodDefs();
};
@@ -641,6 +654,7 @@
virtual ~LateParsedClass();
virtual void ParseLexedMethodDeclarations();
+ virtual void ParseLexedMemberInitializers();
virtual void ParseLexedMethodDefs();
private:
@@ -714,6 +728,25 @@
llvm::SmallVector<LateParsedDefaultArgument, 8> DefaultArgs;
};
+ /// LateParsedMemberInitializer - An initializer for a non-static class data
+ /// member whose parsing must to be delayed until the class is completely
+ /// defined (C++11 [class.mem]p2).
+ struct LateParsedMemberInitializer : public LateParsedDeclaration {
+ LateParsedMemberInitializer(Parser *P, Decl *FD)
+ : Self(P), Field(FD) { }
+
+ virtual void ParseLexedMemberInitializers();
+
+ Parser *Self;
+
+ /// Field - The field declaration.
+ Decl *Field;
+
+ /// CachedTokens - The sequence of tokens that comprises the initializer,
+ /// including any leading '='.
+ CachedTokens Toks;
+ };
+
/// LateParsedDeclarationsContainer - During parsing of a top (non-nested)
/// C++ class, its method declarations that contain parts that won't be
/// parsed until after the definition is completed (C++ [class.mem]p2),
@@ -974,10 +1007,13 @@
Decl *ParseCXXInlineMethodDef(AccessSpecifier AS, ParsingDeclarator &D,
const ParsedTemplateInfo &TemplateInfo,
const VirtSpecifiers& VS, ExprResult& Init);
+ void ParseCXXNonStaticMemberInitializer(Decl *VarD);
void ParseLexedMethodDeclarations(ParsingClass &Class);
void ParseLexedMethodDeclaration(LateParsedMethodDeclaration &LM);
void ParseLexedMethodDefs(ParsingClass &Class);
void ParseLexedMethodDef(LexedMethod &LM);
+ void ParseLexedMemberInitializers(ParsingClass &Class);
+ void ParseLexedMemberInitializer(LateParsedMemberInitializer &MI);
bool ConsumeAndStoreUntil(tok::TokenKind T1,
CachedTokens &Toks,
bool StopAtSemi = true,
@@ -1755,6 +1791,8 @@
bool SuppressDeclarations = false);
void ParseCXXMemberSpecification(SourceLocation StartLoc, unsigned TagType,
Decl *TagDecl);
+ ExprResult ParseCXXMemberInitializer(bool IsFunction,
+ SourceLocation &EqualLoc);
void ParseCXXClassMemberDeclaration(AccessSpecifier AS,
const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo(),
ParsingDeclRAIIObject *DiagsFromTParams = 0);
Modified: cfe/trunk/include/clang/Sema/DeclSpec.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/DeclSpec.h?rev=132878&r1=132877&r2=132878&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/DeclSpec.h (original)
+++ cfe/trunk/include/clang/Sema/DeclSpec.h Sat Jun 11 12:19:42 2011
@@ -1078,8 +1078,8 @@
/// If this is an invalid location, there is no ref-qualifier.
unsigned RefQualifierLoc;
- /// \brief When ExceptionSpecType isn't EST_None, the location of the
- /// keyword introducing the spec.
+ /// \brief When ExceptionSpecType isn't EST_None or EST_Delayed, the
+ /// location of the keyword introducing the spec.
unsigned ExceptionSpecLoc;
/// ArgInfo - This is a pointer to a new[]'d array of ParamInfo objects that
@@ -1616,6 +1616,29 @@
DeclTypeInfo.erase(DeclTypeInfo.begin());
}
+ /// isArrayOfUnknownBound - This method returns true if the declarator
+ /// is a declarator for an array of unknown bound (looking through
+ /// parentheses).
+ bool isArrayOfUnknownBound() const {
+ for (unsigned i = 0, i_end = DeclTypeInfo.size(); i < i_end; ++i) {
+ switch (DeclTypeInfo[i].Kind) {
+ case DeclaratorChunk::Paren:
+ continue;
+ case DeclaratorChunk::Function:
+ case DeclaratorChunk::Pointer:
+ case DeclaratorChunk::Reference:
+ case DeclaratorChunk::BlockPointer:
+ case DeclaratorChunk::MemberPointer:
+ return false;
+ case DeclaratorChunk::Array:
+ return !DeclTypeInfo[i].Arr.NumElts;
+ }
+ llvm_unreachable("Invalid type chunk");
+ return false;
+ }
+ return false;
+ }
+
/// isFunctionDeclarator - This method returns true if the declarator
/// is a function declarator (looking through parentheses).
/// If true is returned, then the reference type parameter idx is
Modified: cfe/trunk/include/clang/Sema/Scope.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Scope.h?rev=132878&r1=132877&r2=132878&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Scope.h (original)
+++ cfe/trunk/include/clang/Sema/Scope.h Sat Jun 11 12:19:42 2011
@@ -79,7 +79,12 @@
ObjCMethodScope = 0x400,
/// SwitchScope - This is a scope that corresponds to a switch statement.
- SwitchScope = 0x800
+ SwitchScope = 0x800,
+
+ /// ThisScope - This is the scope of a struct/union/class definition,
+ /// outside of any member function definition, where 'this' is nonetheless
+ /// usable.
+ ThisScope = 0x1000
};
private:
/// The parent scope for this scope. This is null for the translation-unit
Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=132878&r1=132877&r2=132878&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Sat Jun 11 12:19:42 2011
@@ -1144,13 +1144,13 @@
Declarator &D, Expr *BitfieldWidth);
FieldDecl *HandleField(Scope *S, RecordDecl *TagD, SourceLocation DeclStart,
- Declarator &D, Expr *BitfieldWidth,
+ Declarator &D, Expr *BitfieldWidth, bool HasInit,
AccessSpecifier AS);
FieldDecl *CheckFieldDecl(DeclarationName Name, QualType T,
TypeSourceInfo *TInfo,
RecordDecl *Record, SourceLocation Loc,
- bool Mutable, Expr *BitfieldWidth,
+ bool Mutable, Expr *BitfieldWidth, bool HasInit,
SourceLocation TSSL,
AccessSpecifier AS, NamedDecl *PrevDecl,
Declarator *D = 0);
@@ -2612,6 +2612,13 @@
// Then a throw(collected exceptions)
// Finally no specification.
// throw(...) is used instead if any called function uses it.
+ //
+ // If this exception specification cannot be known yet (for instance,
+ // because this is the exception specification for a defaulted default
+ // constructor and we haven't finished parsing the deferred parts of the
+ // class yet), the C++0x standard does not specify how to behave. We
+ // record this as an 'unknown' exception specification, which overrules
+ // any other specification (even 'none', to keep this rule simple).
ExceptionSpecificationType ComputedEST;
llvm::SmallPtrSet<CanQualType, 4> ExceptionsSeen;
llvm::SmallVector<QualType, 4> Exceptions;
@@ -2644,6 +2651,15 @@
/// \brief Integrate another called method into the collected data.
void CalledDecl(CXXMethodDecl *Method);
+ /// \brief Integrate an invoked expression into the collected data.
+ void CalledExpr(Expr *E);
+
+ /// \brief Specify that the exception specification can't be detemined yet.
+ void SetDelayed() {
+ ClearExceptions();
+ ComputedEST = EST_Delayed;
+ }
+
FunctionProtoType::ExtProtoInfo getEPI() const {
FunctionProtoType::ExtProtoInfo EPI;
EPI.ExceptionSpecType = getExceptionSpecType();
@@ -2836,10 +2852,9 @@
//// ActOnCXXThis - Parse 'this' pointer.
ExprResult ActOnCXXThis(SourceLocation loc);
- /// tryCaptureCXXThis - Try to capture a 'this' pointer. Returns a
- /// pointer to an instance method whose 'this' pointer is
- /// capturable, or null if this is not possible.
- CXXMethodDecl *tryCaptureCXXThis();
+ /// getAndCaptureCurrentThisType - Try to capture a 'this' pointer. Returns
+ /// the type of the 'this' pointer, or a null type if this is not possible.
+ QualType getAndCaptureCurrentThisType();
/// ActOnCXXBoolLiteral - Parse {true,false} literals.
ExprResult ActOnCXXBoolLiteral(SourceLocation OpLoc, tok::TokenKind Kind);
@@ -3238,7 +3253,10 @@
Declarator &D,
MultiTemplateParamsArg TemplateParameterLists,
Expr *BitfieldWidth, const VirtSpecifiers &VS,
- Expr *Init, bool IsDefinition);
+ Expr *Init, bool HasDeferredInit,
+ bool IsDefinition);
+ void ActOnCXXInClassMemberInitializer(Decl *VarDecl, SourceLocation EqualLoc,
+ Expr *Init);
MemInitResult ActOnMemInitializer(Decl *ConstructorD,
Scope *S,
@@ -3342,8 +3360,9 @@
void ActOnStartDelayedMemberDeclarations(Scope *S, Decl *Record);
void ActOnStartDelayedCXXMethodDeclaration(Scope *S, Decl *Method);
void ActOnDelayedCXXMethodParameter(Scope *S, Decl *Param);
- void ActOnFinishDelayedCXXMethodDeclaration(Scope *S, Decl *Method);
void ActOnFinishDelayedMemberDeclarations(Scope *S, Decl *Record);
+ void ActOnFinishDelayedCXXMethodDeclaration(Scope *S, Decl *Method);
+ void ActOnFinishDelayedMemberInitializers(Decl *Record);
void MarkAsLateParsedTemplate(FunctionDecl *FD, bool Flag = true);
bool IsInsideALocalClassWithinATemplateFunction();
Modified: cfe/trunk/lib/AST/ASTContext.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=132878&r1=132877&r2=132878&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ASTContext.cpp (original)
+++ cfe/trunk/lib/AST/ASTContext.cpp Sat Jun 11 12:19:42 2011
@@ -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);
}
Modified: cfe/trunk/lib/AST/ASTImporter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTImporter.cpp?rev=132878&r1=132877&r2=132878&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ASTImporter.cpp (original)
+++ cfe/trunk/lib/AST/ASTImporter.cpp Sat Jun 11 12:19:42 2011
@@ -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;
Modified: cfe/trunk/lib/AST/Decl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Decl.cpp?rev=132878&r1=132877&r2=132878&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Decl.cpp (original)
+++ cfe/trunk/lib/AST/Decl.cpp Sat Jun 11 12:19:42 2011
@@ -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
//===----------------------------------------------------------------------===//
Modified: cfe/trunk/lib/AST/DeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=132878&r1=132877&r2=132878&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclCXX.cpp (original)
+++ cfe/trunk/lib/AST/DeclCXX.cpp Sat Jun 11 12:19:42 2011
@@ -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());
}
Modified: cfe/trunk/lib/AST/DeclPrinter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclPrinter.cpp?rev=132878&r1=132877&r2=132878&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclPrinter.cpp (original)
+++ cfe/trunk/lib/AST/DeclPrinter.cpp Sat Jun 11 12:19:42 2011
@@ -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();
+
+ Init = Init->IgnoreParens();
- 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);
- }
+ 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) {
Modified: cfe/trunk/lib/AST/Expr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Expr.cpp?rev=132878&r1=132877&r2=132878&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Expr.cpp (original)
+++ cfe/trunk/lib/AST/Expr.cpp Sat Jun 11 12:19:42 2011
@@ -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;
Modified: cfe/trunk/lib/AST/Mangle.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Mangle.cpp?rev=132878&r1=132877&r2=132878&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Mangle.cpp (original)
+++ cfe/trunk/lib/AST/Mangle.cpp Sat Jun 11 12:19:42 2011
@@ -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
}
Modified: cfe/trunk/lib/CodeGen/CGBlocks.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGBlocks.cpp?rev=132878&r1=132877&r2=132878&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGBlocks.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGBlocks.cpp Sat Jun 11 12:19:42 2011
@@ -304,7 +304,11 @@
const DeclContext *DC = block->getDeclContext();
for (; isa<BlockDecl>(DC); DC = cast<BlockDecl>(DC)->getDeclContext())
;
- QualType thisType = cast<CXXMethodDecl>(DC)->getThisType(C);
+ QualType thisType;
+ if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(DC))
+ thisType = C.getPointerType(C.getRecordType(RD));
+ else
+ thisType = cast<CXXMethodDecl>(DC)->getThisType(C);
const llvm::Type *llvmType = CGM.getTypes().ConvertType(thisType);
std::pair<CharUnits,CharUnits> tinfo
Modified: cfe/trunk/lib/CodeGen/CGClass.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGClass.cpp?rev=132878&r1=132877&r2=132878&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGClass.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGClass.cpp Sat Jun 11 12:19:42 2011
@@ -520,6 +520,7 @@
FunctionArgList &Args) {
assert(MemberInit->isAnyMemberInitializer() &&
"Must have member initializer!");
+ assert(MemberInit->getInit() && "Must have initializer!");
// non-static data member initializers.
FieldDecl *Field = MemberInit->getAnyMember();
Modified: cfe/trunk/lib/CodeGen/CGObjCMac.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGObjCMac.cpp?rev=132878&r1=132877&r2=132878&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGObjCMac.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGObjCMac.cpp Sat Jun 11 12:19:42 2011
@@ -4098,9 +4098,9 @@
SourceLocation(), SourceLocation(),
&Ctx.Idents.get("_objc_super"));
RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), SourceLocation(), 0,
- Ctx.getObjCIdType(), 0, 0, false));
+ Ctx.getObjCIdType(), 0, 0, false, false));
RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), SourceLocation(), 0,
- Ctx.getObjCClassType(), 0, 0, false));
+ Ctx.getObjCClassType(), 0, 0, false, false));
RD->completeDefinition();
SuperCTy = Ctx.getTagDeclType(RD);
@@ -4559,9 +4559,9 @@
SourceLocation(), SourceLocation(),
&Ctx.Idents.get("_message_ref_t"));
RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), SourceLocation(), 0,
- Ctx.VoidPtrTy, 0, 0, false));
+ Ctx.VoidPtrTy, 0, 0, false, false));
RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), SourceLocation(), 0,
- Ctx.getObjCSelType(), 0, 0, false));
+ Ctx.getObjCSelType(), 0, 0, false, false));
RD->completeDefinition();
MessageRefCTy = Ctx.getTagDeclType(RD);
Modified: cfe/trunk/lib/Parse/ParseCXXInlineMethods.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseCXXInlineMethods.cpp?rev=132878&r1=132877&r2=132878&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseCXXInlineMethods.cpp (original)
+++ cfe/trunk/lib/Parse/ParseCXXInlineMethods.cpp Sat Jun 11 12:19:42 2011
@@ -42,6 +42,7 @@
FnD = Actions.ActOnCXXMemberDeclarator(getCurScope(), AS, D,
move(TemplateParams), 0,
VS, Init.release(),
+ /*HasInit=*/false,
/*IsDefinition*/true);
}
@@ -166,8 +167,50 @@
return FnD;
}
+/// ParseCXXNonStaticMemberInitializer - We parsed and verified that the
+/// specified Declarator is a well formed C++ non-static data member
+/// declaration. Now lex its initializer and store its tokens for parsing
+/// after the class is complete.
+void Parser::ParseCXXNonStaticMemberInitializer(Decl *VarD) {
+ assert((Tok.is(tok::l_brace) || Tok.is(tok::equal)) &&
+ "Current token not a '{' or '='!");
+
+ LateParsedMemberInitializer *MI =
+ new LateParsedMemberInitializer(this, VarD);
+ getCurrentClass().LateParsedDeclarations.push_back(MI);
+ CachedTokens &Toks = MI->Toks;
+
+ tok::TokenKind kind = Tok.getKind();
+ if (kind == tok::equal) {
+ Toks.push_back(Tok);
+ ConsumeAnyToken();
+ }
+
+ if (kind == tok::l_brace) {
+ // Begin by storing the '{' token.
+ Toks.push_back(Tok);
+ ConsumeBrace();
+
+ // Consume everything up to (and including) the matching right brace.
+ ConsumeAndStoreUntil(tok::r_brace, Toks, /*StopAtSemi=*/true);
+ } else {
+ // Consume everything up to (but excluding) the comma or semicolon.
+ ConsumeAndStoreUntil(tok::comma, Toks, /*StopAtSemi=*/true,
+ /*ConsumeFinalToken=*/false);
+ }
+
+ // Store an artificial EOF token to ensure that we don't run off the end of
+ // the initializer when we come to parse it.
+ Token Eof;
+ Eof.startToken();
+ Eof.setKind(tok::eof);
+ Eof.setLocation(Tok.getLocation());
+ Toks.push_back(Eof);
+}
+
Parser::LateParsedDeclaration::~LateParsedDeclaration() {}
void Parser::LateParsedDeclaration::ParseLexedMethodDeclarations() {}
+void Parser::LateParsedDeclaration::ParseLexedMemberInitializers() {}
void Parser::LateParsedDeclaration::ParseLexedMethodDefs() {}
Parser::LateParsedClass::LateParsedClass(Parser *P, ParsingClass *C)
@@ -181,6 +224,10 @@
Self->ParseLexedMethodDeclarations(*Class);
}
+void Parser::LateParsedClass::ParseLexedMemberInitializers() {
+ Self->ParseLexedMemberInitializers(*Class);
+}
+
void Parser::LateParsedClass::ParseLexedMethodDefs() {
Self->ParseLexedMethodDefs(*Class);
}
@@ -193,6 +240,10 @@
Self->ParseLexedMethodDef(*this);
}
+void Parser::LateParsedMemberInitializer::ParseLexedMemberInitializers() {
+ Self->ParseLexedMemberInitializer(*this);
+}
+
/// ParseLexedMethodDeclarations - We finished parsing the member
/// specification of a top (non-nested) C++ class. Now go over the
/// stack of method declarations with some parts for which parsing was
@@ -364,8 +415,70 @@
origLoc))
while (Tok.getLocation() != origLoc && Tok.isNot(tok::eof))
ConsumeAnyToken();
+ }
+}
+
+/// ParseLexedMemberInitializers - We finished parsing the member specification
+/// of a top (non-nested) C++ class. Now go over the stack of lexed data member
+/// initializers that were collected during its parsing and parse them all.
+void Parser::ParseLexedMemberInitializers(ParsingClass &Class) {
+ bool HasTemplateScope = !Class.TopLevelClass && Class.TemplateScope;
+ ParseScope ClassTemplateScope(this, Scope::TemplateParamScope,
+ HasTemplateScope);
+ if (HasTemplateScope)
+ Actions.ActOnReenterTemplateScope(getCurScope(), Class.TagOrTemplate);
+
+ // Set or update the scope flags to include Scope::ThisScope.
+ bool AlreadyHasClassScope = Class.TopLevelClass;
+ unsigned ScopeFlags = Scope::ClassScope|Scope::DeclScope|Scope::ThisScope;
+ ParseScope ClassScope(this, ScopeFlags, !AlreadyHasClassScope);
+ ParseScopeFlags ClassScopeFlags(this, ScopeFlags, AlreadyHasClassScope);
+
+ if (!AlreadyHasClassScope)
+ Actions.ActOnStartDelayedMemberDeclarations(getCurScope(),
+ Class.TagOrTemplate);
+
+ for (size_t i = 0; i < Class.LateParsedDeclarations.size(); ++i) {
+ Class.LateParsedDeclarations[i]->ParseLexedMemberInitializers();
+ }
+
+ if (!AlreadyHasClassScope)
+ Actions.ActOnFinishDelayedMemberDeclarations(getCurScope(),
+ Class.TagOrTemplate);
+
+ Actions.ActOnFinishDelayedMemberInitializers(Class.TagOrTemplate);
+}
+
+void Parser::ParseLexedMemberInitializer(LateParsedMemberInitializer &MI) {
+ if (MI.Field->isInvalidDecl())
+ return;
+ // Append the current token at the end of the new token stream so that it
+ // doesn't get lost.
+ MI.Toks.push_back(Tok);
+ PP.EnterTokenStream(MI.Toks.data(), MI.Toks.size(), true, false);
+
+ // Consume the previously pushed token.
+ ConsumeAnyToken();
+
+ SourceLocation EqualLoc;
+ ExprResult Init = ParseCXXMemberInitializer(/*IsFunction=*/false, EqualLoc);
+
+ Actions.ActOnCXXInClassMemberInitializer(MI.Field, EqualLoc, Init.release());
+
+ // The next token should be our artificial terminating EOF token.
+ if (Tok.isNot(tok::eof)) {
+ SourceLocation EndLoc = PP.getLocForEndOfToken(PrevTokLocation);
+ if (!EndLoc.isValid())
+ EndLoc = Tok.getLocation();
+ // No fixit; we can't recover as if there were a semicolon here.
+ Diag(EndLoc, diag::err_expected_semi_decl_list);
+
+ // Consume tokens until we hit the artificial EOF.
+ while (Tok.isNot(tok::eof))
+ ConsumeAnyToken();
}
+ ConsumeAnyToken();
}
/// ConsumeAndStoreUntil - Consume and store the token at the passed token
Modified: cfe/trunk/lib/Parse/ParseDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDeclCXX.cpp?rev=132878&r1=132877&r2=132878&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseDeclCXX.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDeclCXX.cpp Sat Jun 11 12:19:42 2011
@@ -1553,6 +1553,7 @@
/// member-declarator:
/// declarator virt-specifier-seq[opt] pure-specifier[opt]
/// declarator constant-initializer[opt]
+/// [C++11] declarator brace-or-equal-initializer[opt]
/// identifier[opt] ':' constant-expression
///
/// virt-specifier-seq:
@@ -1731,10 +1732,14 @@
bool IsDefinition = false;
// function-definition:
- if (Tok.is(tok::l_brace)) {
+ //
+ // In C++11, a non-function declarator followed by an open brace is a
+ // braced-init-list for an in-class member initialization, not an
+ // erroneous function definition.
+ if (Tok.is(tok::l_brace) && !getLang().CPlusPlus0x) {
IsDefinition = true;
} else if (DeclaratorInfo.isFunctionDeclarator()) {
- if (Tok.is(tok::colon) || Tok.is(tok::kw_try)) {
+ if (Tok.is(tok::l_brace) || Tok.is(tok::colon) || Tok.is(tok::kw_try)) {
IsDefinition = true;
} else if (Tok.is(tok::equal)) {
const Token &KW = NextToken();
@@ -1790,7 +1795,7 @@
while (1) {
// member-declarator:
// declarator pure-specifier[opt]
- // declarator constant-initializer[opt]
+ // declarator brace-or-equal-initializer[opt]
// identifier[opt] ':' constant-expression
if (Tok.is(tok::colon)) {
ConsumeToken();
@@ -1799,38 +1804,6 @@
SkipUntil(tok::comma, true, true);
}
- ParseOptionalCXX0XVirtSpecifierSeq(VS);
-
- // pure-specifier:
- // '= 0'
- //
- // constant-initializer:
- // '=' constant-expression
- //
- // defaulted/deleted function-definition:
- // '=' 'default' [TODO]
- // '=' 'delete'
- if (Tok.is(tok::equal)) {
- ConsumeToken();
- if (Tok.is(tok::kw_delete)) {
- if (DeclaratorInfo.isFunctionDeclarator())
- Diag(ConsumeToken(), diag::err_default_delete_in_multiple_declaration)
- << 1 /* delete */;
- else
- Diag(ConsumeToken(), diag::err_deleted_non_function);
- } else if (Tok.is(tok::kw_default)) {
- if (DeclaratorInfo.isFunctionDeclarator())
- Diag(Tok, diag::err_default_delete_in_multiple_declaration)
- << 1 /* delete */;
- else
- Diag(ConsumeToken(), diag::err_default_special_members);
- } else {
- Init = ParseInitializer();
- if (Init.isInvalid())
- SkipUntil(tok::comma, true, true);
- }
- }
-
// If a simple-asm-expr is present, parse it.
if (Tok.is(tok::kw_asm)) {
SourceLocation Loc;
@@ -1845,6 +1818,30 @@
// If attributes exist after the declarator, parse them.
MaybeParseGNUAttributes(DeclaratorInfo);
+ // FIXME: When g++ adds support for this, we'll need to check whether it
+ // goes before or after the GNU attributes and __asm__.
+ ParseOptionalCXX0XVirtSpecifierSeq(VS);
+
+ bool HasDeferredInitializer = false;
+ if (Tok.is(tok::equal) || Tok.is(tok::l_brace)) {
+ if (BitfieldSize.get()) {
+ Diag(Tok, diag::err_bitfield_member_init);
+ SkipUntil(tok::comma, true, true);
+ } else {
+ HasDeferredInitializer = !DeclaratorInfo.isFunctionDeclarator() &&
+ DeclaratorInfo.getDeclSpec().getStorageClassSpec()
+ != DeclSpec::SCS_static;
+
+ if (!HasDeferredInitializer) {
+ SourceLocation EqualLoc;
+ Init = ParseCXXMemberInitializer(
+ DeclaratorInfo.isFunctionDeclarator(), EqualLoc);
+ if (Init.isInvalid())
+ SkipUntil(tok::comma, true, true);
+ }
+ }
+ }
+
// NOTE: If Sema is the Action module and declarator is an instance field,
// this call will *not* return the created decl; It will return null.
// See Sema::ActOnCXXMemberDeclarator for details.
@@ -1860,7 +1857,9 @@
DeclaratorInfo,
move(TemplateParams),
BitfieldSize.release(),
- VS, Init.release(), false);
+ VS, Init.release(),
+ HasDeferredInitializer,
+ /*IsDefinition*/ false);
}
if (ThisDecl)
DeclsInGroup.push_back(ThisDecl);
@@ -1873,6 +1872,24 @@
DeclaratorInfo.complete(ThisDecl);
+ if (HasDeferredInitializer) {
+ if (!getLang().CPlusPlus0x)
+ Diag(Tok, diag::warn_nonstatic_member_init_accepted_as_extension);
+
+ if (DeclaratorInfo.isArrayOfUnknownBound()) {
+ // C++0x [dcl.array]p3: An array bound may also be omitted when the
+ // declarator is followed by an initializer.
+ //
+ // A brace-or-equal-initializer for a member-declarator is not an
+ // initializer in the gramamr, so this is ill-formed.
+ Diag(Tok, diag::err_incomplete_array_member_init);
+ SkipUntil(tok::comma, true, true);
+ // Avoid later warnings about a class member of incomplete type.
+ ThisDecl->setInvalidDecl();
+ } else
+ ParseCXXNonStaticMemberInitializer(ThisDecl);
+ }
+
// If we don't have a comma, it is either the end of the list (a ';')
// or an error, bail out.
if (Tok.isNot(tok::comma))
@@ -1906,6 +1923,66 @@
DeclsInGroup.size());
}
+/// ParseCXXMemberInitializer - Parse the brace-or-equal-initializer or
+/// pure-specifier. Also detect and reject any attempted defaulted/deleted
+/// function definition. The location of the '=', if any, will be placed in
+/// EqualLoc.
+///
+/// pure-specifier:
+/// '= 0'
+///
+/// brace-or-equal-initializer:
+/// '=' initializer-expression
+/// braced-init-list [TODO]
+///
+/// initializer-clause:
+/// assignment-expression
+/// braced-init-list [TODO]
+///
+/// defaulted/deleted function-definition:
+/// '=' 'default'
+/// '=' 'delete'
+///
+/// Prior to C++0x, the assignment-expression in an initializer-clause must
+/// be a constant-expression.
+ExprResult Parser::ParseCXXMemberInitializer(bool IsFunction,
+ SourceLocation &EqualLoc) {
+ assert((Tok.is(tok::equal) || Tok.is(tok::l_brace))
+ && "Data member initializer not starting with '=' or '{'");
+
+ if (Tok.is(tok::equal)) {
+ EqualLoc = ConsumeToken();
+ if (Tok.is(tok::kw_delete)) {
+ // In principle, an initializer of '= delete p;' is legal, but it will
+ // never type-check. It's better to diagnose it as an ill-formed expression
+ // than as an ill-formed deleted non-function member.
+ // An initializer of '= delete p, foo' will never be parsed, because
+ // a top-level comma always ends the initializer expression.
+ const Token &Next = NextToken();
+ if (IsFunction || Next.is(tok::semi) || Next.is(tok::comma) ||
+ Next.is(tok::eof)) {
+ if (IsFunction)
+ Diag(ConsumeToken(), diag::err_default_delete_in_multiple_declaration)
+ << 1 /* delete */;
+ else
+ Diag(ConsumeToken(), diag::err_deleted_non_function);
+ return ExprResult();
+ }
+ } else if (Tok.is(tok::kw_default)) {
+ Diag(ConsumeToken(), diag::err_default_special_members);
+ if (IsFunction)
+ Diag(Tok, diag::err_default_delete_in_multiple_declaration)
+ << 0 /* default */;
+ else
+ Diag(ConsumeToken(), diag::err_default_special_members);
+ return ExprResult();
+ }
+
+ return ParseInitializer();
+ } else
+ return ExprError(Diag(Tok, diag::err_generalized_initializer_lists));
+}
+
/// ParseCXXMemberSpecification - Parse the class definition.
///
/// member-specification:
@@ -2057,19 +2134,20 @@
LBraceLoc, RBraceLoc,
attrs.getList());
- // C++ 9.2p2: Within the class member-specification, the class is regarded as
- // complete within function bodies, default arguments,
- // exception-specifications, and constructor ctor-initializers (including
- // such things in nested classes).
+ // C++0x [class.mem]p2: Within the class member-specification, the class is
+ // regarded as complete within function bodies, default arguments, exception-
+ // specifications, and brace-or-equal-initializers for non-static data
+ // members (including such things in nested classes).
//
- // FIXME: Only function bodies and constructor ctor-initializers are
- // parsed correctly, fix the rest.
+ // FIXME: Only function bodies and brace-or-equal-initializers are currently
+ // handled. Fix the others!
if (TagDecl && NonNestedClass) {
// We are not inside a nested class. This class and its nested classes
// are complete and we can parse the delayed portions of method
// declarations and the lexed inline method definitions.
SourceLocation SavedPrevTokLocation = PrevTokLocation;
ParseLexedMethodDeclarations(getCurrentClass());
+ ParseLexedMemberInitializers(getCurrentClass());
ParseLexedMethodDefs(getCurrentClass());
PrevTokLocation = SavedPrevTokLocation;
}
Modified: cfe/trunk/lib/Parse/Parser.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/Parser.cpp?rev=132878&r1=132877&r2=132878&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/Parser.cpp (original)
+++ cfe/trunk/lib/Parse/Parser.cpp Sat Jun 11 12:19:42 2011
@@ -351,7 +351,23 @@
ScopeCache[NumCachedScopes++] = OldScope;
}
+/// Set the flags for the current scope to ScopeFlags. If ManageFlags is false,
+/// this object does nothing.
+Parser::ParseScopeFlags::ParseScopeFlags(Parser *Self, unsigned ScopeFlags,
+ bool ManageFlags)
+ : CurScope(ManageFlags ? Self->getCurScope() : 0) {
+ if (CurScope) {
+ OldFlags = CurScope->getFlags();
+ CurScope->setFlags(ScopeFlags);
+ }
+}
+/// Restore the flags for the current scope to what they were before this
+/// object overrode them.
+Parser::ParseScopeFlags::~ParseScopeFlags() {
+ if (CurScope)
+ CurScope->setFlags(OldFlags);
+}
//===----------------------------------------------------------------------===//
Modified: cfe/trunk/lib/Rewrite/RewriteObjC.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Rewrite/RewriteObjC.cpp?rev=132878&r1=132877&r2=132878&view=diff
==============================================================================
--- cfe/trunk/lib/Rewrite/RewriteObjC.cpp (original)
+++ cfe/trunk/lib/Rewrite/RewriteObjC.cpp Sat Jun 11 12:19:42 2011
@@ -2695,7 +2695,8 @@
SourceLocation(), 0,
FieldTypes[i], 0,
/*BitWidth=*/0,
- /*Mutable=*/false));
+ /*Mutable=*/false,
+ /*HasInit=*/false));
}
SuperStructDecl->completeDefinition();
@@ -2727,7 +2728,8 @@
SourceLocation(), 0,
FieldTypes[i], 0,
/*BitWidth=*/0,
- /*Mutable=*/true));
+ /*Mutable=*/true,
+ /*HasInit=*/false));
}
ConstantStringDecl->completeDefinition();
@@ -4709,7 +4711,8 @@
SourceLocation(),
&Context->Idents.get("FuncPtr"),
Context->VoidPtrTy, 0,
- /*BitWidth=*/0, /*Mutable=*/true);
+ /*BitWidth=*/0, /*Mutable=*/true,
+ /*HasInit=*/false);
MemberExpr *ME = new (Context) MemberExpr(PE, true, FD, SourceLocation(),
FD->getType(), VK_LValue,
OK_Ordinary);
@@ -4763,7 +4766,8 @@
SourceLocation(),
&Context->Idents.get("__forwarding"),
Context->VoidPtrTy, 0,
- /*BitWidth=*/0, /*Mutable=*/true);
+ /*BitWidth=*/0, /*Mutable=*/true,
+ /*HasInit=*/false);
MemberExpr *ME = new (Context) MemberExpr(DeclRefExp, isArrow,
FD, SourceLocation(),
FD->getType(), VK_LValue,
@@ -4773,7 +4777,8 @@
FD = FieldDecl::Create(*Context, 0, SourceLocation(), SourceLocation(),
&Context->Idents.get(Name),
Context->VoidPtrTy, 0,
- /*BitWidth=*/0, /*Mutable=*/true);
+ /*BitWidth=*/0, /*Mutable=*/true,
+ /*HasInit=*/false);
ME = new (Context) MemberExpr(ME, true, FD, SourceLocation(),
DeclRefExp->getType(), VK_LValue, OK_Ordinary);
Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=132878&r1=132877&r2=132878&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Sat Jun 11 12:19:42 2011
@@ -2610,7 +2610,8 @@
/*IdentifierInfo=*/0,
Context.getTypeDeclType(Record),
TInfo,
- /*BitWidth=*/0, /*Mutable=*/false);
+ /*BitWidth=*/0, /*Mutable=*/false,
+ /*HasInit=*/false);
Anon->setAccess(AS);
if (getLangOptions().CPlusPlus)
FieldCollector->Add(cast<FieldDecl>(Anon));
@@ -2700,7 +2701,8 @@
/*IdentifierInfo=*/0,
Context.getTypeDeclType(Record),
TInfo,
- /*BitWidth=*/0, /*Mutable=*/false);
+ /*BitWidth=*/0, /*Mutable=*/false,
+ /*HasInit=*/false);
Anon->setImplicit();
// Add the anonymous struct object to the current context.
@@ -7512,14 +7514,13 @@
return false;
}
-/// ActOnField - Each field of a struct/union/class is passed into this in order
+/// ActOnField - Each field of a C struct/union is passed into this in order
/// to create a FieldDecl object for it.
-Decl *Sema::ActOnField(Scope *S, Decl *TagD,
- SourceLocation DeclStart,
- Declarator &D, ExprTy *BitfieldWidth) {
+Decl *Sema::ActOnField(Scope *S, Decl *TagD, SourceLocation DeclStart,
+ Declarator &D, ExprTy *BitfieldWidth) {
FieldDecl *Res = HandleField(S, cast_or_null<RecordDecl>(TagD),
DeclStart, D, static_cast<Expr*>(BitfieldWidth),
- AS_public);
+ /*HasInit=*/false, AS_public);
return Res;
}
@@ -7527,7 +7528,7 @@
///
FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record,
SourceLocation DeclStart,
- Declarator &D, Expr *BitWidth,
+ Declarator &D, Expr *BitWidth, bool HasInit,
AccessSpecifier AS) {
IdentifierInfo *II = D.getIdentifier();
SourceLocation Loc = DeclStart;
@@ -7576,8 +7577,8 @@
= (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_mutable);
SourceLocation TSSL = D.getSourceRange().getBegin();
FieldDecl *NewFD
- = CheckFieldDecl(II, T, TInfo, Record, Loc, Mutable, BitWidth, TSSL,
- AS, PrevDecl, &D);
+ = CheckFieldDecl(II, T, TInfo, Record, Loc, Mutable, BitWidth, HasInit,
+ TSSL, AS, PrevDecl, &D);
if (NewFD->isInvalidDecl())
Record->setInvalidDecl();
@@ -7606,7 +7607,7 @@
FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T,
TypeSourceInfo *TInfo,
RecordDecl *Record, SourceLocation Loc,
- bool Mutable, Expr *BitWidth,
+ bool Mutable, Expr *BitWidth, bool HasInit,
SourceLocation TSSL,
AccessSpecifier AS, NamedDecl *PrevDecl,
Declarator *D) {
@@ -7686,7 +7687,7 @@
}
FieldDecl *NewFD = FieldDecl::Create(Context, Record, TSSL, Loc, II, T, TInfo,
- BitWidth, Mutable);
+ BitWidth, Mutable, HasInit);
if (InvalidDecl)
NewFD->setInvalidDecl();
@@ -8289,16 +8290,17 @@
// Now that the record is complete, do any delayed exception spec checks
// we were missing.
- if (!DelayedDestructorExceptionSpecChecks.empty()) {
+ while (!DelayedDestructorExceptionSpecChecks.empty()) {
const CXXDestructorDecl *Dtor =
DelayedDestructorExceptionSpecChecks.back().first;
- if (Dtor->getParent() == Record) {
- assert(!Dtor->getParent()->isDependentType() &&
- "Should not ever add destructors of templates into the list.");
- CheckOverridingFunctionExceptionSpec(Dtor,
- DelayedDestructorExceptionSpecChecks.back().second);
- DelayedDestructorExceptionSpecChecks.pop_back();
- }
+ if (Dtor->getParent() != Record)
+ break;
+
+ assert(!Dtor->getParent()->isDependentType() &&
+ "Should not ever add destructors of templates into the list.");
+ CheckOverridingFunctionExceptionSpec(Dtor,
+ DelayedDestructorExceptionSpecChecks.back().second);
+ DelayedDestructorExceptionSpecChecks.pop_back();
}
} else {
Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=132878&r1=132877&r2=132878&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Sat Jun 11 12:19:42 2011
@@ -113,8 +113,8 @@
void Sema::ImplicitExceptionSpecification::CalledDecl(CXXMethodDecl *Method) {
assert(Context && "ImplicitExceptionSpecification without an ASTContext");
- // If we have an MSAny spec already, don't bother.
- if (!Method || ComputedEST == EST_MSAny)
+ // If we have an MSAny or unknown spec already, don't bother.
+ if (!Method || ComputedEST == EST_MSAny || ComputedEST == EST_Delayed)
return;
const FunctionProtoType *Proto
@@ -123,12 +123,15 @@
ExceptionSpecificationType EST = Proto->getExceptionSpecType();
// If this function can throw any exceptions, make a note of that.
- if (EST == EST_MSAny || EST == EST_None) {
+ if (EST == EST_Delayed || EST == EST_MSAny || EST == EST_None) {
ClearExceptions();
ComputedEST = EST;
return;
}
+ // FIXME: If the call to this decl is using any of its default arguments, we
+ // need to search them for potentially-throwing calls.
+
// If this function has a basic noexcept, it doesn't affect the outcome.
if (EST == EST_BasicNoexcept)
return;
@@ -175,6 +178,35 @@
Exceptions.push_back(*E);
}
+void Sema::ImplicitExceptionSpecification::CalledExpr(Expr *E) {
+ if (!E || ComputedEST == EST_MSAny || ComputedEST == EST_Delayed)
+ return;
+
+ // FIXME:
+ //
+ // C++0x [except.spec]p14:
+ // [An] implicit exception-speciï¬cation speciï¬es the type-id T if and
+ // only if T is allowed by the exception-speciï¬cation of a function directly
+ // invoked by fâs implicit deï¬nition; f shall allow all exceptions if any
+ // function it directly invokes allows all exceptions, and f shall allow no
+ // exceptions if every function it directly invokes allows no exceptions.
+ //
+ // Note in particular that if an implicit exception-specification is generated
+ // for a function containing a throw-expression, that specification can still
+ // be noexcept(true).
+ //
+ // Note also that 'directly invoked' is not defined in the standard, and there
+ // is no indication that we should only consider potentially-evaluated calls.
+ //
+ // Ultimately we should implement the intent of the standard: the exception
+ // specification should be the set of exceptions which can be thrown by the
+ // implicit definition. For now, we assume that any non-nothrow expression can
+ // throw any exception.
+
+ if (E->CanThrow(*Context))
+ ComputedEST = EST_None;
+}
+
bool
Sema::SetParamDefaultArgument(ParmVarDecl *Param, Expr *Arg,
SourceLocation EqualLoc) {
@@ -1029,13 +1061,15 @@
/// ActOnCXXMemberDeclarator - This is invoked when a C++ class member
/// declarator is parsed. 'AS' is the access specifier, 'BW' specifies the
-/// bitfield width if there is one and 'InitExpr' specifies the initializer if
-/// any.
+/// bitfield width if there is one, 'InitExpr' specifies the initializer if
+/// one has been parsed, and 'HasDeferredInit' is true if an initializer is
+/// present but parsing it has been deferred.
Decl *
Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
MultiTemplateParamsArg TemplateParameterLists,
ExprTy *BW, const VirtSpecifiers &VS,
- ExprTy *InitExpr, bool IsDefinition) {
+ ExprTy *InitExpr, bool HasDeferredInit,
+ bool IsDefinition) {
const DeclSpec &DS = D.getDeclSpec();
DeclarationNameInfo NameInfo = GetNameForDeclarator(D);
DeclarationName Name = NameInfo.getName();
@@ -1050,6 +1084,7 @@
assert(isa<CXXRecordDecl>(CurContext));
assert(!DS.isFriendSpecified());
+ assert(!Init || !HasDeferredInit);
bool isFunc = false;
if (D.isFunctionDeclarator())
@@ -1121,9 +1156,11 @@
// FIXME: Check for template parameters!
// FIXME: Check that the name is an identifier!
Member = HandleField(S, cast<CXXRecordDecl>(CurContext), Loc, D, BitWidth,
- AS);
+ HasDeferredInit, AS);
assert(Member && "HandleField never returns null");
} else {
+ assert(!HasDeferredInit);
+
Member = HandleDeclarator(S, D, move(TemplateParameterLists), IsDefinition);
if (!Member) {
return 0;
@@ -1194,6 +1231,14 @@
if (Init)
AddInitializerToDecl(Member, Init, false,
DS.getTypeSpecType() == DeclSpec::TST_auto);
+ else if (DS.getTypeSpecType() == DeclSpec::TST_auto &&
+ DS.getStorageClassSpec() == DeclSpec::SCS_static) {
+ // C++0x [dcl.spec.auto]p4: 'auto' can only be used in the type of a static
+ // data member if a brace-or-equal-initializer is provided.
+ Diag(Loc, diag::err_auto_var_requires_init)
+ << Name << cast<ValueDecl>(Member)->getType();
+ Member->setInvalidDecl();
+ }
FinalizeDeclaration(Member);
@@ -1202,6 +1247,47 @@
return Member;
}
+/// ActOnCXXInClassMemberInitializer - This is invoked after parsing an
+/// in-class initializer for a non-static C++ class member. Such parsing
+/// is deferred until the class is complete.
+void
+Sema::ActOnCXXInClassMemberInitializer(Decl *D, SourceLocation EqualLoc,
+ Expr *InitExpr) {
+ FieldDecl *FD = cast<FieldDecl>(D);
+
+ if (!InitExpr) {
+ FD->setInvalidDecl();
+ FD->removeInClassInitializer();
+ return;
+ }
+
+ ExprResult Init = InitExpr;
+ if (!FD->getType()->isDependentType() && !InitExpr->isTypeDependent()) {
+ // FIXME: if there is no EqualLoc, this is list-initialization.
+ Init = PerformCopyInitialization(
+ InitializedEntity::InitializeMember(FD), EqualLoc, InitExpr);
+ if (Init.isInvalid()) {
+ FD->setInvalidDecl();
+ return;
+ }
+
+ CheckImplicitConversions(Init.get(), EqualLoc);
+ }
+
+ // C++0x [class.base.init]p7:
+ // The initialization of each base and member constitutes a
+ // full-expression.
+ Init = MaybeCreateExprWithCleanups(Init);
+ if (Init.isInvalid()) {
+ FD->setInvalidDecl();
+ return;
+ }
+
+ InitExpr = Init.release();
+
+ FD->setInClassInitializer(InitExpr);
+}
+
/// \brief Find the direct and/or virtual base specifiers that
/// correspond to the given base type, for use in base initialization
/// within a constructor.
@@ -2073,7 +2159,7 @@
};
}
-static bool CollectFieldInitializer(BaseAndFieldInfo &Info,
+static bool CollectFieldInitializer(Sema &SemaRef, BaseAndFieldInfo &Info,
FieldDecl *Top, FieldDecl *Field) {
// Overwhelmingly common case: we have a direct initializer for this field.
@@ -2082,6 +2168,18 @@
return false;
}
+ // C++0x [class.base.init]p8: if the entity is a non-static data member that
+ // has a brace-or-equal-initializer, the entity is initialized as specified
+ // in [dcl.init].
+ if (Field->hasInClassInitializer()) {
+ Info.AllToInit.push_back(
+ new (SemaRef.Context) CXXCtorInitializer(SemaRef.Context, Field,
+ SourceLocation(),
+ SourceLocation(), 0,
+ SourceLocation()));
+ return false;
+ }
+
if (Info.IIK == IIK_Default && Field->isAnonymousStructOrUnion()) {
const RecordType *FieldClassType = Field->getType()->getAs<RecordType>();
assert(FieldClassType && "anonymous struct/union without record type");
@@ -2104,7 +2202,7 @@
// field in the class is also initialized, so exit immediately.
return false;
} else if ((*FA)->isAnonymousStructOrUnion()) {
- if (CollectFieldInitializer(Info, Top, *FA))
+ if (CollectFieldInitializer(SemaRef, Info, Top, *FA))
return true;
}
}
@@ -2119,7 +2217,7 @@
// necessary.
for (RecordDecl::field_iterator FA = FieldClassDecl->field_begin(),
EA = FieldClassDecl->field_end(); FA != EA; FA++) {
- if (CollectFieldInitializer(Info, Top, *FA))
+ if (CollectFieldInitializer(SemaRef, Info, Top, *FA))
return true;
}
}
@@ -2128,7 +2226,7 @@
// Don't try to build an implicit initializer if there were semantic
// errors in any of the initializers (and therefore we might be
// missing some that the user actually wrote).
- if (Info.AnyErrorsInInits)
+ if (Info.AnyErrorsInInits || Field->isInvalidDecl())
return false;
CXXCtorInitializer *Init = 0;
@@ -2260,7 +2358,7 @@
"Incomplete array type is not valid");
continue;
}
- if (CollectFieldInitializer(Info, *Field, *Field))
+ if (CollectFieldInitializer(*this, Info, *Field, *Field))
HadError = true;
}
@@ -2939,6 +3037,9 @@
for (RecordDecl::field_iterator F = Record->field_begin(),
FEnd = Record->field_end();
F != FEnd; ++F) {
+ if (F->hasInClassInitializer())
+ continue;
+
if (F->getType()->isReferenceType() ||
(F->getType().isConstQualified() && F->getType()->isScalarType())) {
if (!Complained) {
@@ -3066,6 +3167,11 @@
ImplicitExceptionSpecification Spec
= ComputeDefaultedDefaultCtorExceptionSpec(CD->getParent());
FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI();
+ if (EPI.ExceptionSpecType == EST_Delayed) {
+ // Exception specification depends on some deferred part of the class. We'll
+ // try again when the class's definition has been fully processed.
+ return;
+ }
const FunctionProtoType *CtorType = CD->getType()->getAs<FunctionProtoType>(),
*ExceptionType = Context.getFunctionType(
Context.VoidTy, 0, 0, EPI)->getAs<FunctionProtoType>();
@@ -3383,12 +3489,15 @@
for (CXXRecordDecl::field_iterator FI = RD->field_begin(),
FE = RD->field_end();
FI != FE; ++FI) {
+ if (FI->isInvalidDecl())
+ continue;
+
QualType FieldType = Context.getBaseElementType(FI->getType());
CXXRecordDecl *FieldRecord = FieldType->getAsCXXRecordDecl();
-
+
// -- any non-static data member with no brace-or-equal-initializer is of
// reference type
- if (FieldType->isReferenceType())
+ if (FieldType->isReferenceType() && !FI->hasInClassInitializer())
return true;
// -- X is a union and all its variant members are of const-qualified type
@@ -3413,6 +3522,7 @@
// array thereof) with no brace-or-equal-initializer does not have a
// user-provided default constructor
if (FieldType.isConstQualified() &&
+ !FI->hasInClassInitializer() &&
!FieldRecord->hasUserProvidedDefaultConstructor())
return true;
@@ -3445,18 +3555,21 @@
continue;
}
- // -- any non-static data member ... has class type M (or array thereof)
- // and either M has no default constructor or overload resolution as
- // applied to M's default constructor results in an ambiguity or in a
- // function that is deleted or inaccessible from the defaulted default
- // constructor.
- CXXConstructorDecl *FieldDefault = LookupDefaultConstructor(FieldRecord);
- if (!FieldDefault || FieldDefault->isDeleted())
- return true;
- if (CheckConstructorAccess(Loc, FieldDefault, FieldDefault->getAccess(),
- PDiag()) != AR_accessible)
- return true;
- } else if (!Union && FieldType.isConstQualified()) {
+ // -- any non-static data member with no brace-or-equal-initializer has
+ // class type M (or array thereof) and either M has no default
+ // constructor or overload resolution as applied to M's default
+ // constructor results in an ambiguity or in a function that is deleted
+ // or inaccessible from the defaulted default constructor.
+ if (!FI->hasInClassInitializer()) {
+ CXXConstructorDecl *FieldDefault = LookupDefaultConstructor(FieldRecord);
+ if (!FieldDefault || FieldDefault->isDeleted())
+ return true;
+ if (CheckConstructorAccess(Loc, FieldDefault, FieldDefault->getAccess(),
+ PDiag()) != AR_accessible)
+ return true;
+ }
+ } else if (!Union && FieldType.isConstQualified() &&
+ !FI->hasInClassInitializer()) {
// -- any non-variant non-static data member of const-qualified type (or
// array thereof) with no brace-or-equal-initializer does not have a
// user-provided default constructor
@@ -5905,7 +6018,12 @@
for (RecordDecl::field_iterator F = ClassDecl->field_begin(),
FEnd = ClassDecl->field_end();
F != FEnd; ++F) {
- if (const RecordType *RecordTy
+ if (F->hasInClassInitializer()) {
+ if (Expr *E = F->getInClassInitializer())
+ ExceptSpec.CalledExpr(E);
+ else if (!F->isInvalidDecl())
+ ExceptSpec.SetDelayed();
+ } else if (const RecordType *RecordTy
= Context.getBaseElementType(F->getType())->getAs<RecordType>()) {
CXXRecordDecl *FieldRecDecl = cast<CXXRecordDecl>(RecordTy->getDecl());
CXXConstructorDecl *Constructor = LookupDefaultConstructor(FieldRecDecl);
@@ -6001,6 +6119,59 @@
}
}
+/// Get any existing defaulted default constructor for the given class. Do not
+/// implicitly define one if it does not exist.
+static CXXConstructorDecl *getDefaultedDefaultConstructorUnsafe(Sema &Self,
+ CXXRecordDecl *D) {
+ ASTContext &Context = Self.Context;
+ QualType ClassType = Context.getTypeDeclType(D);
+ DeclarationName ConstructorName
+ = Context.DeclarationNames.getCXXConstructorName(
+ Context.getCanonicalType(ClassType.getUnqualifiedType()));
+
+ DeclContext::lookup_const_iterator Con, ConEnd;
+ for (llvm::tie(Con, ConEnd) = D->lookup(ConstructorName);
+ Con != ConEnd; ++Con) {
+ // A function template cannot be defaulted.
+ if (isa<FunctionTemplateDecl>(*Con))
+ continue;
+
+ CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(*Con);
+ if (Constructor->isDefaultConstructor())
+ return Constructor->isDefaulted() ? Constructor : 0;
+ }
+ return 0;
+}
+
+void Sema::ActOnFinishDelayedMemberInitializers(Decl *D) {
+ if (!D) return;
+ AdjustDeclIfTemplate(D);
+
+ CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(D);
+ CXXConstructorDecl *CtorDecl
+ = getDefaultedDefaultConstructorUnsafe(*this, ClassDecl);
+
+ if (!CtorDecl) return;
+
+ // Compute the exception specification for the default constructor.
+ const FunctionProtoType *CtorTy =
+ CtorDecl->getType()->castAs<FunctionProtoType>();
+ if (CtorTy->getExceptionSpecType() == EST_Delayed) {
+ ImplicitExceptionSpecification Spec =
+ ComputeDefaultedDefaultCtorExceptionSpec(ClassDecl);
+ FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI();
+ assert(EPI.ExceptionSpecType != EST_Delayed);
+
+ CtorDecl->setType(Context.getFunctionType(Context.VoidTy, 0, 0, EPI));
+ }
+
+ // If the default constructor is explicitly defaulted, checking the exception
+ // specification is deferred until now.
+ if (!CtorDecl->isInvalidDecl() && CtorDecl->isExplicitlyDefaulted() &&
+ !ClassDecl->isDependentType())
+ CheckExplicitlyDefaultedDefaultConstructor(CtorDecl);
+}
+
void Sema::DeclareInheritedConstructors(CXXRecordDecl *ClassDecl) {
// We start with an initial pass over the base classes to collect those that
// inherit constructors from. If there are none, we can forgo all further
@@ -6094,7 +6265,9 @@
// Build up a function type for this particular constructor.
// FIXME: The working paper does not consider that the exception spec
// for the inheriting constructor might be larger than that of the
- // source. This code doesn't yet, either.
+ // source. This code doesn't yet, either. When it does, this code will
+ // need to be delayed until after exception specifications and in-class
+ // member initializers are attached.
const Type *NewCtorType;
if (params == maxParams)
NewCtorType = BaseCtorType;
Modified: cfe/trunk/lib/Sema/SemaExceptionSpec.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExceptionSpec.cpp?rev=132878&r1=132877&r2=132878&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExceptionSpec.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExceptionSpec.cpp Sat Jun 11 12:19:42 2011
@@ -298,8 +298,6 @@
// - both are non-throwing, regardless of their form,
// - both have the form noexcept(constant-expression) and the constant-
// expressions are equivalent,
- // - one exception-specification is a noexcept-specification allowing all
- // exceptions and the other is of the form throw(type-id-list), or
// - both are dynamic-exception-specifications that have the same set of
// adjusted types.
//
@@ -307,8 +305,6 @@
// of the form throw(), noexcept, or noexcept(constant-expression) where the
// constant-expression yields true.
//
- // CWG 1073 Proposed resolution: Strike the third bullet above.
- //
// C++0x [except.spec]p4: If any declaration of a function has an exception-
// specifier that is not a noexcept-specification allowing all exceptions,
// all declarations [...] of that function shall have a compatible
@@ -320,6 +316,9 @@
ExceptionSpecificationType OldEST = Old->getExceptionSpecType();
ExceptionSpecificationType NewEST = New->getExceptionSpecType();
+ assert(OldEST != EST_Delayed && NewEST != EST_Delayed &&
+ "Shouldn't see unknown exception specifications here");
+
// Shortcut the case where both have no spec.
if (OldEST == EST_None && NewEST == EST_None)
return false;
@@ -506,6 +505,9 @@
ExceptionSpecificationType SubEST = Subset->getExceptionSpecType();
+ assert(SuperEST != EST_Delayed && SubEST != EST_Delayed &&
+ "Shouldn't see unknown exception specifications here");
+
// It does not. If the subset contains everything, we've failed.
if (SubEST == EST_None || SubEST == EST_MSAny) {
Diag(SubLoc, DiagID);
Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=132878&r1=132877&r2=132878&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Sat Jun 11 12:19:42 2011
@@ -1333,8 +1333,8 @@
// We've found a member of an anonymous struct/union that is
// inside a non-anonymous struct/union, so in a well-formed
// program our base object expression is "this".
- CXXMethodDecl *method = tryCaptureCXXThis();
- if (!method) {
+ QualType ThisTy = getAndCaptureCurrentThisType();
+ if (ThisTy.isNull()) {
Diag(loc, diag::err_invalid_member_use_in_static_method)
<< indirectField->getDeclName();
return ExprError();
@@ -1342,10 +1342,9 @@
// Our base object expression is "this".
baseObjectExpr =
- new (Context) CXXThisExpr(loc, method->getThisType(Context),
- /*isImplicit=*/ true);
+ new (Context) CXXThisExpr(loc, ThisTy, /*isImplicit=*/ true);
baseObjectIsPointer = true;
- baseQuals = Qualifiers::fromCVRMask(method->getTypeQualifiers());
+ baseQuals = ThisTy->castAs<PointerType>()->getPointeeType().getQualifiers();
}
// Build the implicit member references to the field of the
@@ -1492,14 +1491,23 @@
/// conservatively answer "yes", in which case some errors will simply
/// not be caught until template-instantiation.
static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef,
+ Scope *CurScope,
const LookupResult &R) {
assert(!R.empty() && (*R.begin())->isCXXClassMember());
DeclContext *DC = SemaRef.getFunctionLevelDeclContext();
+
bool isStaticContext =
(!isa<CXXMethodDecl>(DC) ||
cast<CXXMethodDecl>(DC)->isStatic());
+ // C++0x [expr.prim]p4:
+ // Otherwise, if a member-declarator declares a non-static data member
+ // of a class X, the expression this is a prvalue of type "pointer to X"
+ // within the optional brace-or-equal-initializer.
+ if (CurScope->getFlags() & Scope::ThisScope)
+ isStaticContext = false;
+
if (R.isUnresolvableResult())
return isStaticContext ? IMA_Unresolved_StaticContext : IMA_Unresolved;
@@ -1547,8 +1555,11 @@
return IMA_Error_StaticContext;
}
- CXXRecordDecl *
- contextClass = cast<CXXMethodDecl>(DC)->getParent()->getCanonicalDecl();
+ CXXRecordDecl *contextClass;
+ if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(DC))
+ contextClass = MD->getParent()->getCanonicalDecl();
+ else
+ contextClass = cast<CXXRecordDecl>(DC);
// [class.mfct.non-static]p3:
// ...is used in the body of a non-static member function of class X,
@@ -2026,7 +2037,7 @@
Sema::BuildPossibleImplicitMemberExpr(const CXXScopeSpec &SS,
LookupResult &R,
const TemplateArgumentListInfo *TemplateArgs) {
- switch (ClassifyImplicitMemberAccess(*this, R)) {
+ switch (ClassifyImplicitMemberAccess(*this, CurScope, R)) {
case IMA_Instance:
return BuildImplicitMemberExpr(SS, R, TemplateArgs, true);
@@ -2469,19 +2480,18 @@
// If this is known to be an instance access, go ahead and build an
// implicit 'this' expression now.
// 'this' expression now.
- CXXMethodDecl *method = tryCaptureCXXThis();
- assert(method && "didn't correctly pre-flight capture of 'this'");
+ QualType ThisTy = getAndCaptureCurrentThisType();
+ assert(!ThisTy.isNull() && "didn't correctly pre-flight capture of 'this'");
- QualType thisType = method->getThisType(Context);
Expr *baseExpr = 0; // null signifies implicit access
if (IsKnownInstance) {
SourceLocation Loc = R.getNameLoc();
if (SS.getRange().isValid())
Loc = SS.getRange().getBegin();
- baseExpr = new (Context) CXXThisExpr(loc, thisType, /*isImplicit=*/true);
+ baseExpr = new (Context) CXXThisExpr(loc, ThisTy, /*isImplicit=*/true);
}
- return BuildMemberReferenceExpr(baseExpr, thisType,
+ return BuildMemberReferenceExpr(baseExpr, ThisTy,
/*OpLoc*/ SourceLocation(),
/*IsArrow*/ true,
SS,
Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=132878&r1=132877&r2=132878&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Sat Jun 11 12:19:42 2011
@@ -17,6 +17,7 @@
#include "clang/Sema/Lookup.h"
#include "clang/Sema/ParsedTemplate.h"
#include "clang/Sema/ScopeInfo.h"
+#include "clang/Sema/Scope.h"
#include "clang/Sema/TemplateDeduction.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/CXXInheritance.h"
@@ -575,42 +576,54 @@
return Owned(E);
}
-CXXMethodDecl *Sema::tryCaptureCXXThis() {
+QualType Sema::getAndCaptureCurrentThisType() {
// Ignore block scopes: we can capture through them.
// Ignore nested enum scopes: we'll diagnose non-constant expressions
// where they're invalid, and other uses are legitimate.
// Don't ignore nested class scopes: you can't use 'this' in a local class.
DeclContext *DC = CurContext;
+ unsigned NumBlocks = 0;
while (true) {
- if (isa<BlockDecl>(DC)) DC = cast<BlockDecl>(DC)->getDeclContext();
- else if (isa<EnumDecl>(DC)) DC = cast<EnumDecl>(DC)->getDeclContext();
+ if (isa<BlockDecl>(DC)) {
+ DC = cast<BlockDecl>(DC)->getDeclContext();
+ ++NumBlocks;
+ } else if (isa<EnumDecl>(DC))
+ DC = cast<EnumDecl>(DC)->getDeclContext();
else break;
}
- // If we're not in an instance method, error out.
- CXXMethodDecl *method = dyn_cast<CXXMethodDecl>(DC);
- if (!method || !method->isInstance())
- return 0;
-
- // Mark that we're closing on 'this' in all the block scopes, if applicable.
- for (unsigned idx = FunctionScopes.size() - 1;
- isa<BlockScopeInfo>(FunctionScopes[idx]);
- --idx)
- cast<BlockScopeInfo>(FunctionScopes[idx])->CapturesCXXThis = true;
+ QualType ThisTy;
+ if (CXXMethodDecl *method = dyn_cast<CXXMethodDecl>(DC)) {
+ if (method && method->isInstance())
+ ThisTy = method->getThisType(Context);
+ } else if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(DC)) {
+ // C++0x [expr.prim]p4:
+ // Otherwise, if a member-declarator declares a non-static data member
+ // of a class X, the expression this is a prvalue of type "pointer to X"
+ // within the optional brace-or-equal-initializer.
+ Scope *S = getScopeForContext(DC);
+ if (!S || S->getFlags() & Scope::ThisScope)
+ ThisTy = Context.getPointerType(Context.getRecordType(RD));
+ }
+
+ // Mark that we're closing on 'this' in all the block scopes we ignored.
+ if (!ThisTy.isNull())
+ for (unsigned idx = FunctionScopes.size() - 1;
+ NumBlocks; --idx, --NumBlocks)
+ cast<BlockScopeInfo>(FunctionScopes[idx])->CapturesCXXThis = true;
- return method;
+ return ThisTy;
}
-ExprResult Sema::ActOnCXXThis(SourceLocation loc) {
+ExprResult Sema::ActOnCXXThis(SourceLocation Loc) {
/// C++ 9.3.2: In the body of a non-static member function, the keyword this
/// is a non-lvalue expression whose value is the address of the object for
/// which the function is called.
- CXXMethodDecl *method = tryCaptureCXXThis();
- if (!method) return Diag(loc, diag::err_invalid_this_use);
+ QualType ThisTy = getAndCaptureCurrentThisType();
+ if (ThisTy.isNull()) return Diag(Loc, diag::err_invalid_this_use);
- return Owned(new (Context) CXXThisExpr(loc, method->getThisType(Context),
- /*isImplicit=*/false));
+ return Owned(new (Context) CXXThisExpr(Loc, ThisTy, /*isImplicit=*/false));
}
ExprResult
@@ -2663,7 +2676,6 @@
return true;
bool FoundAssign = false;
- bool AllNoThrow = true;
DeclarationName Name = C.DeclarationNames.getCXXOperatorName(OO_Equal);
LookupResult Res(Self, DeclarationNameInfo(Name, KeyLoc),
Sema::LookupOrdinaryName);
@@ -2675,15 +2687,15 @@
FoundAssign = true;
const FunctionProtoType *CPT
= Operator->getType()->getAs<FunctionProtoType>();
- if (!CPT->isNothrow(Self.Context)) {
- AllNoThrow = false;
- break;
- }
+ if (CPT->getExceptionSpecType() == EST_Delayed)
+ return false;
+ if (!CPT->isNothrow(Self.Context))
+ return false;
}
}
}
- return FoundAssign && AllNoThrow;
+ return FoundAssign;
}
return false;
case UTT_HasNothrowCopy:
@@ -2700,7 +2712,6 @@
return true;
bool FoundConstructor = false;
- bool AllNoThrow = true;
unsigned FoundTQs;
DeclContext::lookup_const_iterator Con, ConEnd;
for (llvm::tie(Con, ConEnd) = Self.LookupConstructors(RD);
@@ -2715,16 +2726,16 @@
FoundConstructor = true;
const FunctionProtoType *CPT
= Constructor->getType()->getAs<FunctionProtoType>();
+ if (CPT->getExceptionSpecType() == EST_Delayed)
+ return false;
// FIXME: check whether evaluating default arguments can throw.
// For now, we'll be conservative and assume that they can throw.
- if (!CPT->isNothrow(Self.Context) || CPT->getNumArgs() > 1) {
- AllNoThrow = false;
- break;
- }
+ if (!CPT->isNothrow(Self.Context) || CPT->getNumArgs() > 1)
+ return false;
}
}
- return FoundConstructor && AllNoThrow;
+ return FoundConstructor;
}
return false;
case UTT_HasNothrowConstructor:
@@ -2750,6 +2761,8 @@
if (Constructor->isDefaultConstructor()) {
const FunctionProtoType *CPT
= Constructor->getType()->getAs<FunctionProtoType>();
+ if (CPT->getExceptionSpecType() == EST_Delayed)
+ return false;
// TODO: check whether evaluating default arguments can throw.
// For now, we'll be conservative and assume that they can throw.
return CPT->isNothrow(Self.Context) && CPT->getNumArgs() == 0;
Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp?rev=132878&r1=132877&r2=132878&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp Sat Jun 11 12:19:42 2011
@@ -13,6 +13,7 @@
#include "clang/Sema/SemaInternal.h"
#include "TreeTransform.h"
#include "clang/Sema/DeclSpec.h"
+#include "clang/Sema/Initialization.h"
#include "clang/Sema/Lookup.h"
#include "clang/Sema/Template.h"
#include "clang/Sema/TemplateDeduction.h"
@@ -1744,6 +1745,8 @@
TemplateDeclInstantiator Instantiator(*this, Instantiation, TemplateArgs);
llvm::SmallVector<Decl*, 4> Fields;
+ llvm::SmallVector<std::pair<FieldDecl*, FieldDecl*>, 4>
+ FieldsWithMemberInitializers;
for (RecordDecl::decl_iterator Member = Pattern->decls_begin(),
MemberEnd = Pattern->decls_end();
Member != MemberEnd; ++Member) {
@@ -1766,9 +1769,13 @@
Decl *NewMember = Instantiator.Visit(*Member);
if (NewMember) {
- if (FieldDecl *Field = dyn_cast<FieldDecl>(NewMember))
+ if (FieldDecl *Field = dyn_cast<FieldDecl>(NewMember)) {
Fields.push_back(Field);
- else if (NewMember->isInvalidDecl())
+ FieldDecl *OldField = cast<FieldDecl>(*Member);
+ if (OldField->getInClassInitializer())
+ FieldsWithMemberInitializers.push_back(std::make_pair(OldField,
+ Field));
+ } else if (NewMember->isInvalidDecl())
Invalid = true;
} else {
// FIXME: Eventually, a NULL return will mean that one of the
@@ -1782,6 +1789,43 @@
Fields.data(), Fields.size(), SourceLocation(), SourceLocation(),
0);
CheckCompletedCXXClass(Instantiation);
+
+ // Attach any in-class member initializers now the class is complete.
+ for (unsigned I = 0, N = FieldsWithMemberInitializers.size(); I != N; ++I) {
+ FieldDecl *OldField = FieldsWithMemberInitializers[I].first;
+ FieldDecl *NewField = FieldsWithMemberInitializers[I].second;
+ Expr *OldInit = OldField->getInClassInitializer();
+ ExprResult NewInit = SubstExpr(OldInit, TemplateArgs);
+
+ // If the initialization is no longer dependent, check it now.
+ if ((OldField->getType()->isDependentType() || OldInit->isTypeDependent())
+ && !NewField->getType()->isDependentType()
+ && !NewInit.get()->isTypeDependent()) {
+ // FIXME: handle list-initialization
+ SourceLocation EqualLoc = NewField->getLocation();
+ NewInit = PerformCopyInitialization(
+ InitializedEntity::InitializeMember(NewField), EqualLoc,
+ NewInit.release());
+
+ if (!NewInit.isInvalid()) {
+ CheckImplicitConversions(NewInit.get(), EqualLoc);
+
+ // C++0x [class.base.init]p7:
+ // The initialization of each base and member constitutes a
+ // full-expression.
+ NewInit = MaybeCreateExprWithCleanups(NewInit);
+ }
+ }
+
+ if (NewInit.isInvalid())
+ NewField->setInvalidDecl();
+ else
+ NewField->setInClassInitializer(NewInit.release());
+ }
+
+ if (!FieldsWithMemberInitializers.empty())
+ ActOnFinishDelayedMemberInitializers(Instantiation);
+
if (Instantiation->isInvalidDecl())
Invalid = true;
else {
Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=132878&r1=132877&r2=132878&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Sat Jun 11 12:19:42 2011
@@ -477,6 +477,7 @@
D->getLocation(),
D->isMutable(),
BitWidth,
+ D->hasInClassInitializer(),
D->getTypeSpecStartLoc(),
D->getAccess(),
0);
Modified: cfe/trunk/lib/Sema/SemaType.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=132878&r1=132877&r2=132878&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaType.cpp (original)
+++ cfe/trunk/lib/Sema/SemaType.cpp Sat Jun 11 12:19:42 2011
@@ -1593,6 +1593,8 @@
Error = 0; // Function prototype
break;
case Declarator::MemberContext:
+ if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static)
+ break;
switch (cast<TagDecl>(CurContext)->getTagKind()) {
case TTK_Enum: assert(0 && "unhandled tag kind"); break;
case TTK_Struct: Error = 1; /* Struct member */ break;
Modified: cfe/trunk/lib/Sema/TreeTransform.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/TreeTransform.h?rev=132878&r1=132877&r2=132878&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/TreeTransform.h (original)
+++ cfe/trunk/lib/Sema/TreeTransform.h Sat Jun 11 12:19:42 2011
@@ -6697,8 +6697,12 @@
ExprResult
TreeTransform<Derived>::TransformCXXThisExpr(CXXThisExpr *E) {
DeclContext *DC = getSema().getFunctionLevelDeclContext();
- CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(DC);
- QualType T = MD->getThisType(getSema().Context);
+ QualType T;
+ if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(DC))
+ T = MD->getThisType(getSema().Context);
+ else
+ T = getSema().Context.getPointerType(
+ getSema().Context.getRecordType(cast<CXXRecordDecl>(DC)));
if (!getDerived().AlwaysRebuild() && T == E->getType())
return SemaRef.Owned(E);
Modified: cfe/trunk/lib/Serialization/ASTReaderDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReaderDecl.cpp?rev=132878&r1=132877&r2=132878&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTReaderDecl.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTReaderDecl.cpp Sat Jun 11 12:19:42 2011
@@ -677,8 +677,11 @@
void ASTDeclReader::VisitFieldDecl(FieldDecl *FD) {
VisitDeclaratorDecl(FD);
FD->setMutable(Record[Idx++]);
- if (Record[Idx++])
+ int BitWidthOrInitializer = Record[Idx++];
+ if (BitWidthOrInitializer == 1)
FD->setBitWidth(Reader.ReadExpr(F));
+ else if (BitWidthOrInitializer == 2)
+ FD->setInClassInitializer(Reader.ReadExpr(F));
if (!FD->getDeclName()) {
FieldDecl *Tmpl = cast_or_null<FieldDecl>(Reader.GetDecl(Record[Idx++]));
if (Tmpl)
@@ -1649,7 +1652,7 @@
break;
case DECL_FIELD:
D = FieldDecl::Create(*Context, 0, SourceLocation(), SourceLocation(), 0,
- QualType(), 0, 0, false);
+ QualType(), 0, 0, false, false);
break;
case DECL_INDIRECTFIELD:
D = IndirectFieldDecl::Create(*Context, 0, SourceLocation(), 0, QualType(),
Modified: cfe/trunk/lib/Serialization/ASTWriterDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriterDecl.cpp?rev=132878&r1=132877&r2=132878&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTWriterDecl.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTWriterDecl.cpp Sat Jun 11 12:19:42 2011
@@ -599,9 +599,11 @@
void ASTDeclWriter::VisitFieldDecl(FieldDecl *D) {
VisitDeclaratorDecl(D);
Record.push_back(D->isMutable());
- Record.push_back(D->getBitWidth()? 1 : 0);
+ Record.push_back(D->getBitWidth()? 1 : D->hasInClassInitializer() ? 2 : 0);
if (D->getBitWidth())
Writer.AddStmt(D->getBitWidth());
+ else if (D->hasInClassInitializer())
+ Writer.AddStmt(D->getInClassInitializer());
if (!D->getDeclName())
Writer.AddDeclRef(Context.getInstantiatedFromUnnamedFieldDecl(D), Record);
@@ -612,6 +614,7 @@
!D->isReferenced() &&
D->getPCHLevel() == 0 &&
!D->getBitWidth() &&
+ !D->hasInClassInitializer() &&
!D->hasExtInfo() &&
!ObjCIvarDecl::classofKind(D->getKind()) &&
!ObjCAtDefsFieldDecl::classofKind(D->getKind()) &&
Added: cfe/trunk/test/CXX/class/class.mem/p5-0x.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/class/class.mem/p5-0x.cpp?rev=132878&view=auto
==============================================================================
--- cfe/trunk/test/CXX/class/class.mem/p5-0x.cpp (added)
+++ cfe/trunk/test/CXX/class/class.mem/p5-0x.cpp Sat Jun 11 12:19:42 2011
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
+
+int f();
+
+struct S
+{
+ int a = f(); // ok
+ int b = g(); // expected-error {{use of undeclared identifier 'g'}}
+};
Modified: cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p4.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p4.cpp?rev=132878&r1=132877&r2=132878&view=diff
==============================================================================
--- cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p4.cpp (original)
+++ cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p4.cpp Sat Jun 11 12:19:42 2011
@@ -22,14 +22,21 @@
new const auto (0);
new (auto) (0.0);
-#if 0
- // When clang supports for-range:
- for (auto i : {1,2,3}) {
+ int arr[] = {1, 2, 3};
+ for (auto i : arr) {
}
-
- // When clang supports inline initialization of members.
- class X {
- static const auto &n = 'x';
- };
-#endif
}
+
+class X {
+ static const auto n = 'x';
+
+ auto m = 0; // expected-error {{'auto' not allowed in non-static class member}}
+};
+
+struct S {
+ static const auto a; // expected-error {{declaration of variable 'a' with type 'auto const' requires an initializer}}
+ static const auto b = 0;
+ static const int c;
+};
+const int S::b;
+const auto S::c = 0;
Modified: cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp?rev=132878&r1=132877&r2=132878&view=diff
==============================================================================
--- cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp (original)
+++ cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp Sat Jun 11 12:19:42 2011
@@ -3,13 +3,13 @@
struct S {
virtual ~S();
- auto a; // expected-error{{'auto' not allowed in struct member}}
- auto *b; // expected-error{{'auto' not allowed in struct member}}
- const auto c; // expected-error{{'auto' not allowed in struct member}}
+ auto a; // expected-error{{'auto' not allowed in non-static struct member}}
+ auto *b; // expected-error{{'auto' not allowed in non-static struct member}}
+ const auto c; // expected-error{{'auto' not allowed in non-static struct member}}
void f() throw (auto); // expected-error{{'auto' not allowed here}}
- friend auto; // expected-error{{'auto' not allowed in struct member}}
+ friend auto; // expected-error{{'auto' not allowed in non-static struct member}}
operator auto(); // expected-error{{'auto' not allowed here}}
};
Modified: cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.type/p3-0x.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.type/p3-0x.cpp?rev=132878&r1=132877&r2=132878&view=diff
==============================================================================
--- cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.type/p3-0x.cpp (original)
+++ cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.type/p3-0x.cpp Sat Jun 11 12:19:42 2011
@@ -7,8 +7,8 @@
class K {
virtual ~K();
- // FIXME: the diagnostic here isn't very good
- operator struct S {} (); // expected-error 2{{}}
+ // FIXME: the diagnostic here is really bad
+ operator struct S {} (); // expected-error 2{{}} expected-note {{}}
};
void f() {
Added: cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.aggr/p1-0x.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.aggr/p1-0x.cpp?rev=132878&view=auto
==============================================================================
--- cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.aggr/p1-0x.cpp (added)
+++ cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.aggr/p1-0x.cpp Sat Jun 11 12:19:42 2011
@@ -0,0 +1,63 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
+
+// An aggregate is an array or a class...
+struct Aggr {
+private:
+ static const int n;
+ void f();
+protected:
+ struct Inner { int m; };
+public:
+ bool &br;
+};
+bool b;
+Aggr ag = { b };
+
+// with no user-provided constructors, ...
+struct NonAggr1a {
+ NonAggr1a(int, int);
+ int k;
+};
+// In C++03, this is {{non-aggregate type 'NonAggr1a'}}.
+// In C++0x, 'user-provided' is only defined for special member functions, so
+// this type is considered to be an aggregate. This is probably a langauge
+// defect.
+NonAggr1a na1a = { 42 };
+
+struct NonAggr1b {
+ NonAggr1b(const NonAggr1b &);
+ int k;
+};
+NonAggr1b na1b = { 42 }; // expected-error {{non-aggregate type 'NonAggr1b'}}
+
+// no brace-or-equal-initializers for non-static data members, ...
+struct NonAggr2 {
+ int m = { 123 };
+};
+NonAggr2 na2 = { 42 }; // expected-error {{non-aggregate type 'NonAggr2'}}
+
+// no private...
+struct NonAggr3 {
+private:
+ int n;
+};
+NonAggr3 na3 = { 42 }; // expected-error {{non-aggregate type 'NonAggr3'}}
+
+// or protected non-static data members, ...
+struct NonAggr4 {
+protected:
+ int n;
+};
+NonAggr4 na4 = { 42 }; // expected-error {{non-aggregate type 'NonAggr4'}}
+
+// no base classes, ...
+struct NonAggr5 : Aggr {
+};
+NonAggr5 na5 = { b }; // expected-error {{non-aggregate type 'NonAggr5'}}
+
+// and no virtual functions.
+struct NonAggr6 {
+ virtual void f();
+ int n;
+};
+NonAggr6 na6 = { 42 }; // expected-error {{non-aggregate type 'NonAggr6'}}
Added: cfe/trunk/test/CXX/dcl.decl/dcl.init/p14-0x.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.decl/dcl.init/p14-0x.cpp?rev=132878&view=auto
==============================================================================
--- cfe/trunk/test/CXX/dcl.decl/dcl.init/p14-0x.cpp (added)
+++ cfe/trunk/test/CXX/dcl.decl/dcl.init/p14-0x.cpp Sat Jun 11 12:19:42 2011
@@ -0,0 +1,44 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
+
+struct NoDefault {
+ NoDefault() = delete; // expected-note {{here}}
+ NoDefault(int);
+};
+struct Explicit { // expected-note {{candidate}} expected-note {{here}}
+ explicit Explicit(int);
+};
+struct NoCopy {
+ NoCopy();
+ NoCopy(const NoCopy &) = delete; // expected-note {{here}}
+};
+struct NoMove {
+ NoMove();
+ NoMove(NoMove &&) = delete; // expected-note {{here}}
+};
+class Private {
+ Private(int); // expected-note {{here}}
+public:
+ Private();
+};
+class Friend {
+ friend class S;
+ Friend(int);
+};
+
+
+class S {
+ NoDefault nd1;
+ NoDefault nd2 = 42;
+ Explicit e1; // expected-note {{here}}
+ Explicit e2 = 42; // expected-error {{no viable conversion}}
+ NoCopy nc = NoCopy(); // expected-error {{call to deleted}}
+ NoMove nm = NoMove(); // expected-error {{call to deleted}}
+ Private p = 42; // expected-error {{private constructor}}
+ Friend f = 42;
+
+ S() {} // expected-error {{call to deleted constructor of 'NoDefault'}} \
+ expected-error {{must explicitly initialize the member 'e1' which does not have a default constructor}}
+ S(int) : nd1(42), e1(42) {}
+};
+
+// FIXME: test the other forms which use copy-initialization
Modified: cfe/trunk/test/CXX/except/except.spec/p14.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/except/except.spec/p14.cpp?rev=132878&r1=132877&r2=132878&view=diff
==============================================================================
--- cfe/trunk/test/CXX/except/except.spec/p14.cpp (original)
+++ cfe/trunk/test/CXX/except/except.spec/p14.cpp Sat Jun 11 12:19:42 2011
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -verify %s
+// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -verify -std=c++0x %s
struct A { };
struct B { };
struct C { };
@@ -27,3 +27,15 @@
CA2 &(CA2::*captr3)(const CA2&) throw(A) = &CA2::operator=; // expected-error{{target exception specification is not superset of source}}
CA2 &(CA2::*captr4)(const CA2&) throw(B) = &CA2::operator=; // expected-error{{target exception specification is not superset of source}}
}
+
+// In-class member initializers.
+struct IC0 {
+ int inClassInit = 0;
+};
+struct IC1 {
+ int inClassInit = (throw B(), 0);
+};
+// FIXME: the exception specification on the default constructor is wrong:
+// we cannot currently compute the set of thrown types.
+static_assert(noexcept(IC0()), "IC0() does not throw");
+static_assert(!noexcept(IC1()), "IC1() throws");
Added: cfe/trunk/test/CXX/expr/expr.prim/p12-0x.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/expr/expr.prim/p12-0x.cpp?rev=132878&view=auto
==============================================================================
--- cfe/trunk/test/CXX/expr/expr.prim/p12-0x.cpp (added)
+++ cfe/trunk/test/CXX/expr/expr.prim/p12-0x.cpp Sat Jun 11 12:19:42 2011
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
+
+struct S {
+ int *j = &nonexistent; // expected-error {{use of undeclared identifier 'nonexistent'}}
+ int *m = &n; // ok
+
+ int n = f(); // ok
+ int f();
+};
+
+int i = sizeof(S::m); // ok
+int j = sizeof(S::m + 42); // ok
Added: cfe/trunk/test/CXX/expr/expr.prim/p4-0x.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/expr/expr.prim/p4-0x.cpp?rev=132878&view=auto
==============================================================================
--- cfe/trunk/test/CXX/expr/expr.prim/p4-0x.cpp (added)
+++ cfe/trunk/test/CXX/expr/expr.prim/p4-0x.cpp Sat Jun 11 12:19:42 2011
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
+
+struct S {
+ S *p = this; // ok
+ decltype(this) q; // expected-error {{invalid use of 'this' outside of a nonstatic member function}} \
+ expected-error {{C++ requires a type specifier for all declarations}}
+
+ int arr[sizeof(this)]; // expected-error {{invalid use of 'this' outside of a nonstatic member function}}
+ int sz = sizeof(this); // ok
+};
Added: cfe/trunk/test/CXX/special/class.ctor/p5-0x.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/special/class.ctor/p5-0x.cpp?rev=132878&view=auto
==============================================================================
--- cfe/trunk/test/CXX/special/class.ctor/p5-0x.cpp (added)
+++ cfe/trunk/test/CXX/special/class.ctor/p5-0x.cpp Sat Jun 11 12:19:42 2011
@@ -0,0 +1,173 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++0x
+
+struct DefaultedDefCtor1 {};
+struct DefaultedDefCtor2 { DefaultedDefCtor2() = default; };
+struct DeletedDefCtor { DeletedDefCtor() = delete; DeletedDefCtor(int); };
+class PrivateDefCtor { PrivateDefCtor() = default; public: PrivateDefCtor(int); };
+struct DeletedDtor { ~DeletedDtor() = delete; };
+class PrivateDtor { ~PrivateDtor() = default; };
+class Friend {
+ Friend() = default; ~Friend() = default;
+ friend struct NotDeleted6c;
+ friend struct NotDeleted7i;
+ friend struct NotDeleted7j;
+ friend struct NotDeleted7k;
+};
+struct UserProvidedDefCtor { UserProvidedDefCtor() {} };
+int n;
+
+
+// A defaulted default constructor for a class X is defined as deleted if:
+
+// - X is a union-like class that has a variant member with a non-trivial
+// default constructor,
+union Deleted1a { UserProvidedDefCtor u; }; // expected-note {{deleted here}}
+Deleted1a d1a; // expected-error {{deleted constructor}}
+// FIXME: treating this as having a deleted default constructor is probably a
+// bug in the standard.
+union Deleted1b { UserProvidedDefCtor u = UserProvidedDefCtor(); }; // expected-note {{deleted here}}
+Deleted1b d1b; // expected-error {{deleted constructor}}
+union NotDeleted1a { DefaultedDefCtor1 nu; };
+NotDeleted1a nd1a;
+// FIXME: clang implements the pre-FDIS rule, under which DefaultedDefCtor2's
+// default constructor is non-trivial.
+union NotDeleted1b { DefaultedDefCtor2 nu; }; // unexpected-note {{deleted here}}
+NotDeleted1b nd1b; // unexpected-error {{deleted constructor}}
+
+// - any non-static data member with no brace-or-equal-initializer is of
+// reference type,
+class Deleted2a { Deleted2a() = default; int &a; }; // expected-note {{deleted here}}
+Deleted2a d2a; // expected-error {{deleted constructor}}
+class NotDeleted2a { int &a = n; };
+NotDeleted2a nd2a;
+class NotDeleted2b { int &a = error; }; // expected-error {{undeclared identifier}}
+NotDeleted2b nd2b;
+
+// - any non-variant non-static data member of const qualified type (or array
+// thereof) with no brace-or-equal-initializer does not have a user-provided
+// default constructor,
+class Deleted3a { const int a; }; // expected-note {{here}} \
+ expected-warning {{does not declare any constructor}} \
+ expected-note {{will never be initialized}}
+Deleted3a d3a; // expected-error {{deleted constructor}}
+class Deleted3b { const DefaultedDefCtor1 a[42]; }; // expected-note {{here}}
+Deleted3b d3b; // expected-error {{deleted constructor}}
+// FIXME: clang implements the pre-FDIS rule, under which DefaultedDefCtor2's
+// default constructor is user-provided.
+class Deleted3c { const DefaultedDefCtor2 a; }; // desired-note {{here}}
+Deleted3c d3c; // desired-error {{deleted constructor}}
+class NotDeleted3a { const int a = 0; };
+NotDeleted3a nd3a;
+class NotDeleted3b { const DefaultedDefCtor1 a[42] = {}; };
+NotDeleted3b nd3b;
+class NotDeleted3c { const DefaultedDefCtor2 a = DefaultedDefCtor2(); };
+NotDeleted3c nd3c;
+union NotDeleted3d { const int a; int b; };
+NotDeleted3d nd3d;
+// FIXME: this class should not have a deleted default constructor.
+union NotDeleted3e { const DefaultedDefCtor1 a[42]; int b; }; // unexpected-note {{here}}
+NotDeleted3e nd3e; // unexpected-error {{deleted constructor}}
+// FIXME: clang implements the pre-FDIS rule, under which DefaultedDefCtor2 is
+// non-trivial.
+union NotDeleted3f { const DefaultedDefCtor2 a; int b; }; // unexpected-note {{here}}
+NotDeleted3f nd3f; // unexpected-error {{deleted constructor}}
+
+// - X is a union and all of its variant members are of const-qualified type (or
+// array thereof),
+union Deleted4a { const int a; const int b; const UserProvidedDefCtor c; }; // expected-note {{here}}
+Deleted4a d4a; // expected-error {{deleted constructor}}
+union Deleted4b { const int a; int b; };
+Deleted4b d4b;
+
+// - X is a non-union class and all members of any anonymous union member are of
+// const-qualified type (or array thereof),
+struct Deleted5a { union { const int a; }; union { int b; }; }; // expected-note {{here}}
+Deleted5a d5a; // expected-error {{deleted constructor}}
+struct Deleted5b { union { const int a; int b; }; union { const int c; int d; }; };
+Deleted5b d5b;
+
+// - any direct or virtual base class, or non-static data member with no
+// brace-or-equal-initializer, has class type M (or array thereof) and either
+// M has no default constructor or overload resolution as applied to M's default
+// constructor results in an ambiguity or in a function that is deleted or
+// inaccessible from the defaulted default constructor, or
+struct Deleted6a : Deleted2a {}; // expected-note {{here}}
+Deleted6a d6a; // expected-error {{deleted constructor}}
+struct Deleted6b : virtual Deleted2a {}; // expected-note {{here}}
+Deleted6b d6b; // expected-error {{deleted constructor}}
+struct Deleted6c { Deleted2a a; }; // expected-note {{here}}
+Deleted6c d6c; // expected-error {{deleted constructor}}
+struct Deleted6d { DeletedDefCtor a; }; // expected-note {{here}}
+Deleted6d d6d; // expected-error {{deleted constructor}}
+struct NotDeleted6a { DeletedDefCtor a = 0; };
+NotDeleted6a nd6a;
+struct Deleted6e { PrivateDefCtor a; }; // expected-note {{here}}
+Deleted6e d6e; // expected-error {{deleted constructor}}
+struct NotDeleted6b { PrivateDefCtor a = 0; };
+NotDeleted6b nd6b;
+struct NotDeleted6c { Friend a; };
+NotDeleted6c nd6c;
+
+// - any direct or virtual base class or non-static data member has a type with
+// a destructor that is deleted or inaccessible from the defaulted default
+// constructor.
+struct Deleted7a : DeletedDtor {}; // expected-note {{here}}
+Deleted7a d7a; // expected-error {{deleted constructor}}
+struct Deleted7b : virtual DeletedDtor {}; // expected-note {{here}}
+Deleted7b d7b; // expected-error {{deleted constructor}}
+struct Deleted7c { DeletedDtor a; }; // expected-note {{here}}
+Deleted7c d7c; // expected-error {{deleted constructor}}
+struct Deleted7d { DeletedDtor a = {}; }; // expected-note {{here}}
+Deleted7d d7d; // expected-error {{deleted constructor}}
+struct Deleted7e : PrivateDtor {}; // expected-note {{here}}
+Deleted7e d7e; // expected-error {{deleted constructor}}
+struct Deleted7f : virtual PrivateDtor {}; // expected-note {{here}}
+Deleted7f d7f; // expected-error {{deleted constructor}}
+struct Deleted7g { PrivateDtor a; }; // expected-note {{here}}
+Deleted7g d7g; // expected-error {{deleted constructor}}
+struct Deleted7h { PrivateDtor a = {}; }; // expected-note {{here}}
+Deleted7h d7h; // expected-error {{deleted constructor}}
+struct NotDeleted7i : Friend {};
+NotDeleted7i d7i;
+struct NotDeleted7j : virtual Friend {};
+NotDeleted7j d7j;
+struct NotDeleted7k { Friend a; };
+NotDeleted7k d7k;
+
+
+class Trivial { static const int n = 42; };
+static_assert(__has_trivial_constructor(Trivial), "Trivial is nontrivial");
+
+// A default constructor is trivial if it is not user-provided and if:
+class NonTrivialDefCtor1 { NonTrivialDefCtor1(); };
+static_assert(!__has_trivial_constructor(NonTrivialDefCtor1), "NonTrivialDefCtor1 is trivial");
+
+// - its class has no virtual functions (10.3) and no virtual base classes (10.1), and
+class NonTrivialDefCtor2 { virtual void f(); };
+static_assert(!__has_trivial_constructor(NonTrivialDefCtor2), "NonTrivialDefCtor2 is trivial");
+class NonTrivialDefCtor3 : virtual Trivial {};
+static_assert(!__has_trivial_constructor(NonTrivialDefCtor3), "NonTrivialDefCtor3 is trivial");
+
+// - no non-static data member of its class has a brace-or-equal-initializer, and
+class NonTrivialDefCtor4 { int m = 52; };
+static_assert(!__has_trivial_constructor(NonTrivialDefCtor4), "NonTrivialDefCtor4 is trivial");
+
+// - all the direct base classes of its class have trivial default constructors, and
+class NonTrivialDefCtor5 : NonTrivialDefCtor1 {};
+static_assert(!__has_trivial_constructor(NonTrivialDefCtor5), "NonTrivialDefCtor5 is trivial");
+
+// - for all the non-static data members of its class that are of class type (or array thereof), each such class
+// has a trivial default constructor.
+class NonTrivialDefCtor6 { NonTrivialDefCtor1 t; };
+static_assert(!__has_trivial_constructor(NonTrivialDefCtor6), "NonTrivialDefCtor5 is trivial");
+
+// Otherwise, the default constructor is non-trivial.
+class Trivial2 { Trivial2() = delete; };
+//static_assert(__has_trivial_constructor(Trivial2), "NonTrivialDefCtor2 is trivial");
+// FIXME: clang implements the pre-FDIS rule, under which this class is non-trivial.
+static_assert(!__has_trivial_constructor(Trivial2), "NonTrivialDefCtor2 is trivial");
+
+class Trivial3 { Trivial3() = default; };
+//static_assert(__has_trivial_constructor(Trivial3), "NonTrivialDefCtor3 is trivial");
+// FIXME: clang implements the pre-FDIS rule, under which this class is non-trivial.
+static_assert(!__has_trivial_constructor(Trivial3), "NonTrivialDefCtor3 is trivial");
Added: cfe/trunk/test/CXX/special/class.init/class.base.init/p8-0x.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/special/class.init/class.base.init/p8-0x.cpp?rev=132878&view=auto
==============================================================================
--- cfe/trunk/test/CXX/special/class.init/class.base.init/p8-0x.cpp (added)
+++ cfe/trunk/test/CXX/special/class.init/class.base.init/p8-0x.cpp Sat Jun 11 12:19:42 2011
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+
+int n;
+struct S {
+ int &a; // expected-note 2{{here}}
+ int &b = n;
+
+ S() {} // expected-error {{constructor for 'S' must explicitly initialize the reference member 'a'}}
+ S(int) : a(n) {} // ok
+ S(char) : b(n) {} // expected-error {{constructor for 'S' must explicitly initialize the reference member 'a'}}
+ S(double) : a(n), b(n) {} // ok
+};
+
+union U {
+ int a = 0;
+ char b = 'x';
+
+ // FIXME: these should all be rejected
+ U() {} // desired-error {{at most one member of a union may be initialized}}
+ U(int) : a(1) {} // desired-error {{at most one member of a union may be initialized}}
+ U(char) : b('y') {} // desired-error {{at most one member of a union may be initialized}}
+ U(double) : a(1), b('y') {} // desired-error {{at most one member of a union may be initialized}}
+};
Added: cfe/trunk/test/CXX/special/class.init/class.base.init/p9-0x.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/special/class.init/class.base.init/p9-0x.cpp?rev=132878&view=auto
==============================================================================
--- cfe/trunk/test/CXX/special/class.init/class.base.init/p9-0x.cpp (added)
+++ cfe/trunk/test/CXX/special/class.init/class.base.init/p9-0x.cpp Sat Jun 11 12:19:42 2011
@@ -0,0 +1,36 @@
+// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -std=c++0x %s -O1 -emit-llvm -o - | FileCheck %s
+
+struct S {
+ int n = 10;
+ int m = 2 * n;
+
+ S() {}
+ S(int a) : n(a) {}
+ S(int a, int b) : n(a), m(b) {}
+
+ struct T {
+ T *that = this;
+ };
+};
+
+template<typename T>
+struct U {
+ T *r = &q;
+ T q = 42;
+ U *p = this;
+};
+
+S a;
+// CHECK: @a = {{.*}} { i32 10, i32 20 }
+
+S b(5);
+// CHECK: @b = {{.*}} { i32 5, i32 10 }
+
+S c(3, 9);
+// CHECK: @c = {{.*}} { i32 3, i32 9 }
+
+S::T d;
+// CHECK: @d = {{.*}} { {{.*}} @d }
+
+U<S> e;
+// CHECK: @e = {{.*}} { {{.*}} { i32 42, i32 84 }, {{.*}} @e }
Added: cfe/trunk/test/CodeGenCXX/member-init-ctor.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/member-init-ctor.cpp?rev=132878&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenCXX/member-init-ctor.cpp (added)
+++ cfe/trunk/test/CodeGenCXX/member-init-ctor.cpp Sat Jun 11 12:19:42 2011
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 %s -std=c++0x -emit-llvm -o - | FileCheck %s
+
+bool b();
+struct S {
+ int n = b() ? S().n + 1 : 0;
+};
+
+S s;
+
+// CHECK: define{{.*}} void @_ZN1SC2Ev(
+// CHECK-NOT }
+// CHECK: call {{.*}} @_Z1bv()
+// CHECK-NOT }
+// CHECK: call {{.*}} @_ZN1SC1Ev(
Modified: cfe/trunk/test/CodeGenObjCXX/blocks.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjCXX/blocks.mm?rev=132878&r1=132877&r2=132878&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenObjCXX/blocks.mm (original)
+++ cfe/trunk/test/CodeGenObjCXX/blocks.mm Sat Jun 11 12:19:42 2011
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -x objective-c++ -fblocks -triple x86_64-apple-darwin %s
+// RUN: %clang_cc1 -x objective-c++ -fblocks -triple x86_64-apple-darwin %s -verify -emit-llvm -o %t
// rdar://8979379
@interface A
@@ -28,3 +28,19 @@
return bar(objectCreationBlock);
}
+// Test4
+struct S {
+ S *(^a)() = ^{ // expected-warning {{C++0x}}
+ return this;
+ };
+};
+S s;
+
+// Test5
+struct X {
+ void f() {
+ ^ {
+ struct Nested { Nested *ptr = this; }; // expected-warning {{C++0x}}
+ } ();
+ };
+};
Added: cfe/trunk/test/PCH/cxx-member-init.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/PCH/cxx-member-init.cpp?rev=132878&view=auto
==============================================================================
--- cfe/trunk/test/PCH/cxx-member-init.cpp (added)
+++ cfe/trunk/test/PCH/cxx-member-init.cpp Sat Jun 11 12:19:42 2011
@@ -0,0 +1,22 @@
+// Test this without pch.
+// RUN: %clang_cc1 -x c++ -std=c++0x -DHEADER -DSOURCE -fsyntax-only -emit-llvm -o - %s
+
+// Test with pch.
+// RUN: %clang_cc1 -x c++ -std=c++0x -DHEADER -emit-pch -o %t %s
+// RUN: %clang_cc1 -x c++ -std=c++0x -DHEADER -include-pch %t -fsyntax-only -emit-llvm -o - %s
+
+#ifdef HEADER
+int n;
+struct S {
+ int *p = &m;
+ int &m = n;
+ S *that = this;
+};
+#endif
+
+#ifdef SOURCE
+S s;
+#elif HEADER
+#undef HEADER
+#define SOURCE
+#endif
Added: cfe/trunk/test/Parser/cxx0x-member-initializers.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/cxx0x-member-initializers.cpp?rev=132878&view=auto
==============================================================================
--- cfe/trunk/test/Parser/cxx0x-member-initializers.cpp (added)
+++ cfe/trunk/test/Parser/cxx0x-member-initializers.cpp Sat Jun 11 12:19:42 2011
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
+
+// Make sure we don't run off the end of the stream when parsing a deferred
+// initializer.
+int a; // expected-note {{previous}}
+struct S {
+ int n = 4 + ; // expected-error {{expected expression}}
+} a; // expected-error {{redefinition}}
+
+// Make sure we use all of the tokens.
+struct T {
+ int a = 1 // expected-error {{expected ';' at end of declaration list}}
+ int b = 2;
+ int c = b; // expected-error {{undeclared identifier}}
+};
Modified: cfe/trunk/test/SemaCXX/PR9572.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/PR9572.cpp?rev=132878&r1=132877&r2=132878&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/PR9572.cpp (original)
+++ cfe/trunk/test/SemaCXX/PR9572.cpp Sat Jun 11 12:19:42 2011
@@ -1,13 +1,13 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
class Base {
- virtual ~Base();
+ virtual ~Base(); // expected-note {{implicitly declared private here}}
};
-struct Foo : public Base {
- const int kBlah = 3; // expected-error{{fields can only be initialized in constructors}}
+struct Foo : public Base { // expected-error {{base class 'Base' has private destructor}}
+ const int kBlah = 3; // expected-warning {{accepted as a C++0x extension}}
Foo();
};
struct Bar : public Foo {
- Bar() { }
+ Bar() { } // expected-note {{implicit default destructor for 'Foo' first required here}}
};
struct Baz {
Foo f;
Modified: cfe/trunk/test/SemaCXX/class.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/class.cpp?rev=132878&r1=132877&r2=132878&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/class.cpp (original)
+++ cfe/trunk/test/SemaCXX/class.cpp Sat Jun 11 12:19:42 2011
@@ -34,7 +34,7 @@
enum E1 { en1, en2 };
- int i = 0; // expected-error {{fields can only be initialized in constructors}}
+ int i = 0; // expected-warning {{in-class initialization of non-static data member accepted as a C++0x extension}}
static int si = 0; // expected-error {{non-const static data member must be initialized out of line}}
static const NestedC ci = 0; // expected-error {{static data member of type 'const C::NestedC' must be initialized out of line}}
static const int nci = vs; // expected-error {{in-class initializer is not a constant expression}}
Added: cfe/trunk/test/SemaCXX/implicit-exception-spec.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/implicit-exception-spec.cpp?rev=132878&view=auto
==============================================================================
--- cfe/trunk/test/SemaCXX/implicit-exception-spec.cpp (added)
+++ cfe/trunk/test/SemaCXX/implicit-exception-spec.cpp Sat Jun 11 12:19:42 2011
@@ -0,0 +1,63 @@
+// RUN: %clang_cc1 -fsyntax-only -fcxx-exceptions -verify -std=c++0x -Wall %s
+
+template<bool b> struct ExceptionIf { static int f(); };
+template<> struct ExceptionIf<false> { typedef int f; };
+
+// The exception specification of a defaulted default constructor depends on
+// the contents of in-class member initializers. However, the in-class member
+// initializers can depend on the exception specification of the constructor,
+// since the class is considered complete within them. We reject any such cases.
+namespace InClassInitializers {
+ // Noexcept::Noexcept() is implicitly declared as noexcept(false), because it
+ // directly invokes ThrowSomething(). However...
+ //
+ // If noexcept(Noexcept()) is false, then Noexcept() is a constant expression,
+ // so noexcept(Noexcept()) is true. But if noexcept(Noexcept()) is true, then
+ // Noexcept::Noexcept is not declared constexpr, therefore noexcept(Noexcept())
+ // is false.
+ bool ThrowSomething() noexcept(false);
+ struct ConstExpr {
+ bool b = noexcept(ConstExpr()) && ThrowSomething(); // expected-error {{exception specification is not available until end of class definition}}
+ };
+ // We can use it now.
+ bool w = noexcept(ConstExpr());
+
+ // Much more obviously broken: we can't parse the initializer without already
+ // knowing whether it produces a noexcept expression.
+ struct TemplateArg {
+ int n = ExceptionIf<noexcept(TemplateArg())>::f(); // expected-error {{exception specification is not available until end of class definition}}
+ };
+ bool x = noexcept(TemplateArg());
+
+ // And within a nested class.
+ struct Nested {
+ struct Inner {
+ int n = ExceptionIf<noexcept(Nested())>::f(); // expected-error {{exception specification is not available until end of class definition}}
+ } inner;
+ };
+ bool y = noexcept(Nested());
+ bool z = noexcept(Nested::Inner());
+}
+
+// FIXME:
+// The same problem arises in delayed parsing of exception specifications,
+// which clang does not yet support.
+namespace ExceptionSpecification {
+ struct Nested { // expected-note {{not complete}}
+ struct T {
+ T() noexcept(!noexcept(Nested())); // expected-error {{incomplete type}}
+ } t;
+ };
+}
+
+// FIXME:
+// The same problem arises in delayed parsing of default arguments,
+// which clang does not yet support.
+namespace DefaultArgument {
+ // FIXME: this diagnostic is completely wrong.
+ struct Default { // expected-note {{explicitly marked deleted here}}
+ struct T {
+ T(int = ExceptionIf<noexcept(Default())::f()); // expected-error {{call to deleted constructor}}
+ } t;
+ };
+}
Added: cfe/trunk/test/SemaCXX/member-init.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/member-init.cpp?rev=132878&view=auto
==============================================================================
--- cfe/trunk/test/SemaCXX/member-init.cpp (added)
+++ cfe/trunk/test/SemaCXX/member-init.cpp Sat Jun 11 12:19:42 2011
@@ -0,0 +1,50 @@
+// RUN: %clang_cc1 -fsyntax-only -fcxx-exceptions -verify -std=c++0x -Wall %s
+
+struct Bitfield {
+ int n : 3 = 7; // expected-error {{bitfield member cannot have an in-class initializer}}
+};
+
+int a;
+class NoWarning {
+ int &n = a;
+public:
+ int &GetN() { return n; }
+};
+
+bool b();
+int k;
+struct Recurse {
+ int &n = b() ? Recurse().n : k; // ok
+};
+
+struct UnknownBound {
+ int as[] = { 1, 2, 3 }; // expected-error {{array bound cannot be deduced from an in-class initializer}}
+ int bs[4] = { 4, 5, 6, 7 };
+ int cs[] = { 8, 9, 10 }; // expected-error {{array bound cannot be deduced from an in-class initializer}}
+};
+
+template<int n> struct T { static const int B; };
+template<> struct T<2> { template<int C, int D> using B = int; };
+const int C = 0, D = 0;
+struct S {
+ int as[] = { decltype(x)::B<C, D>(0) }; // expected-error {{array bound cannot be deduced from an in-class initializer}}
+ T<sizeof(as) / sizeof(int)> x; // expected-error {{requires a type specifier}}
+};
+
+struct ThrowCtor { ThrowCtor(int) noexcept(false); };
+struct NoThrowCtor { NoThrowCtor(int) noexcept(true); };
+
+struct Throw { ThrowCtor tc = 42; };
+struct NoThrow { NoThrowCtor tc = 42; };
+
+static_assert(!noexcept(Throw()), "incorrect exception specification");
+static_assert(noexcept(NoThrow()), "incorrect exception specification");
+
+struct CheckExcSpec {
+ CheckExcSpec() noexcept(true) = default;
+ int n = 0;
+};
+struct CheckExcSpecFail {
+ CheckExcSpecFail() noexcept(true) = default; // expected-error {{exception specification of explicitly defaulted default constructor does not match the calculated one}}
+ ThrowCtor tc = 123;
+};
Modified: cfe/trunk/test/SemaCXX/type-traits.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/type-traits.cpp?rev=132878&r1=132877&r2=132878&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/type-traits.cpp (original)
+++ cfe/trunk/test/SemaCXX/type-traits.cpp Sat Jun 11 12:19:42 2011
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify -std=gnu++0x %s
#define T(b) (b) ? 1 : -1
#define F(b) (b) ? -1 : 1
@@ -38,8 +38,7 @@
struct DerivesEmpty : Empty {};
struct HasCons { HasCons(int); };
struct HasCopyAssign { HasCopyAssign operator =(const HasCopyAssign&); };
-struct HasMoveAssign { HasMoveAssign operator =(const HasMoveAssign&&); }; // \
- // expected-warning {{rvalue references}}
+struct HasMoveAssign { HasMoveAssign operator =(const HasMoveAssign&&); };
struct HasDest { ~HasDest(); };
class HasPriv { int priv; };
class HasProt { protected: int prot; };
@@ -1069,7 +1068,7 @@
};
struct HasMove {
- HasMove(HasMove&& cp); // expected-warning {{rvalue references}}
+ HasMove(HasMove&& cp);
};
struct HasTemplateCons {
@@ -1253,6 +1252,9 @@
{ int arr[F(__has_nothrow_copy(cvoid))]; }
}
+template<bool b> struct assert_expr;
+template<> struct assert_expr<true> {};
+
void has_nothrow_constructor() {
{ int arr[T(__has_nothrow_constructor(Int))]; }
{ int arr[T(__has_nothrow_constructor(IntAr))]; }
@@ -1280,6 +1282,11 @@
{ int arr[F(__has_nothrow_constructor(void))]; }
{ int arr[F(__has_nothrow_constructor(cvoid))]; }
{ int arr[F(__has_nothrow_constructor(HasTemplateCons))]; }
+
+ // While parsing an in-class initializer, the constructor is not known to be
+ // non-throwing yet.
+ struct HasInClassInit { int n = (assert_expr<!__has_nothrow_constructor(HasInClassInit)>(), 0); };
+ { int arr[T(__has_nothrow_constructor(HasInClassInit))]; }
}
void has_virtual_destructor() {
More information about the cfe-commits
mailing list