Add support for C++0x's range-based for loops, as specified by the C++11 draft standard (N3291).

llvm-svn: 129541
This commit is contained in:
Richard Smith 2011-04-14 22:09:26 +00:00
parent 55858499e2
commit 02e85f3bc5
47 changed files with 1961 additions and 48 deletions

View File

@ -423,6 +423,10 @@ public:
CanQualType OverloadTy, DependentTy, UnknownAnyTy; CanQualType OverloadTy, DependentTy, UnknownAnyTy;
CanQualType ObjCBuiltinIdTy, ObjCBuiltinClassTy, ObjCBuiltinSelTy; CanQualType ObjCBuiltinIdTy, ObjCBuiltinClassTy, ObjCBuiltinSelTy;
// Types for deductions in C++0x [stmt.ranged]'s desugaring. Built on demand.
mutable QualType AutoDeductTy; // Deduction against 'auto'.
mutable QualType AutoRRefDeductTy; // Deduction against 'auto &&'.
ASTContext(const LangOptions& LOpts, SourceManager &SM, const TargetInfo &t, ASTContext(const LangOptions& LOpts, SourceManager &SM, const TargetInfo &t,
IdentifierTable &idents, SelectorTable &sels, IdentifierTable &idents, SelectorTable &sels,
Builtin::Context &builtins, Builtin::Context &builtins,
@ -745,6 +749,12 @@ public:
/// getAutoType - C++0x deduced auto type. /// getAutoType - C++0x deduced auto type.
QualType getAutoType(QualType DeducedType) const; QualType getAutoType(QualType DeducedType) const;
/// getAutoDeductType - C++0x deduction pattern for 'auto' type.
QualType getAutoDeductType() const;
/// getAutoRRefDeductType - C++0x deduction pattern for 'auto &&' type.
QualType getAutoRRefDeductType() const;
/// getTagDeclType - Return the unique reference to the type for the /// getTagDeclType - Return the unique reference to the type for the
/// specified TagDecl (struct/union/class/enum) decl. /// specified TagDecl (struct/union/class/enum) decl.
QualType getTagDeclType(const TagDecl *Decl) const; QualType getTagDeclType(const TagDecl *Decl) const;

View File

@ -696,6 +696,10 @@ private:
/// slot of its function, enabling the named return value optimization (NRVO). /// slot of its function, enabling the named return value optimization (NRVO).
bool NRVOVariable : 1; bool NRVOVariable : 1;
/// \brief Whether this variable is the for-range-declaration in a C++0x
/// for-range statement.
bool CXXForRangeDecl : 1;
friend class StmtIteratorBase; friend class StmtIteratorBase;
friend class ASTDeclReader; friend class ASTDeclReader;
@ -706,7 +710,7 @@ protected:
StorageClass SCAsWritten) StorageClass SCAsWritten)
: DeclaratorDecl(DK, DC, IdLoc, Id, T, TInfo, StartLoc), Init(), : DeclaratorDecl(DK, DC, IdLoc, Id, T, TInfo, StartLoc), Init(),
ThreadSpecified(false), HasCXXDirectInit(false), ThreadSpecified(false), HasCXXDirectInit(false),
ExceptionVar(false), NRVOVariable(false) { ExceptionVar(false), NRVOVariable(false), CXXForRangeDecl(false) {
SClass = SC; SClass = SC;
SClassAsWritten = SCAsWritten; SClassAsWritten = SCAsWritten;
} }
@ -1052,6 +1056,11 @@ public:
bool isNRVOVariable() const { return NRVOVariable; } bool isNRVOVariable() const { return NRVOVariable; }
void setNRVOVariable(bool NRVO) { NRVOVariable = NRVO; } void setNRVOVariable(bool NRVO) { NRVOVariable = NRVO; }
/// \brief Determine whether this variable is the for-range-declaration in
/// a C++0x for-range statement.
bool isCXXForRangeDecl() const { return CXXForRangeDecl; }
void setCXXForRangeDecl(bool FRD) { CXXForRangeDecl = FRD; }
/// \brief If this variable is an instantiated static data member of a /// \brief If this variable is an instantiated static data member of a
/// class template specialization, returns the templated static data member /// class template specialization, returns the templated static data member
/// from which it was instantiated. /// from which it was instantiated.

View File

@ -1738,6 +1738,10 @@ class UnresolvedLookupExpr : public OverloadExpr {
/// call. /// call.
bool RequiresADL; bool RequiresADL;
/// True if namespace ::std should be considered an associated namespace
/// for the purposes of argument-dependent lookup. See C++0x [stmt.ranged]p1.
bool StdIsAssociatedNamespace;
/// True if these lookup results are overloaded. This is pretty /// True if these lookup results are overloaded. This is pretty
/// trivially rederivable if we urgently need to kill this field. /// trivially rederivable if we urgently need to kill this field.
bool Overloaded; bool Overloaded;
@ -1755,15 +1759,19 @@ class UnresolvedLookupExpr : public OverloadExpr {
const DeclarationNameInfo &NameInfo, const DeclarationNameInfo &NameInfo,
bool RequiresADL, bool Overloaded, bool RequiresADL, bool Overloaded,
const TemplateArgumentListInfo *TemplateArgs, const TemplateArgumentListInfo *TemplateArgs,
UnresolvedSetIterator Begin, UnresolvedSetIterator End) UnresolvedSetIterator Begin, UnresolvedSetIterator End,
bool StdIsAssociatedNamespace)
: OverloadExpr(UnresolvedLookupExprClass, C, QualifierLoc, NameInfo, : OverloadExpr(UnresolvedLookupExprClass, C, QualifierLoc, NameInfo,
TemplateArgs, Begin, End), TemplateArgs, Begin, End),
RequiresADL(RequiresADL), Overloaded(Overloaded), NamingClass(NamingClass) RequiresADL(RequiresADL),
StdIsAssociatedNamespace(StdIsAssociatedNamespace),
Overloaded(Overloaded), NamingClass(NamingClass)
{} {}
UnresolvedLookupExpr(EmptyShell Empty) UnresolvedLookupExpr(EmptyShell Empty)
: OverloadExpr(UnresolvedLookupExprClass, Empty), : OverloadExpr(UnresolvedLookupExprClass, Empty),
RequiresADL(false), Overloaded(false), NamingClass(0) RequiresADL(false), StdIsAssociatedNamespace(false), Overloaded(false),
NamingClass(0)
{} {}
friend class ASTStmtReader; friend class ASTStmtReader;
@ -1775,9 +1783,13 @@ public:
const DeclarationNameInfo &NameInfo, const DeclarationNameInfo &NameInfo,
bool ADL, bool Overloaded, bool ADL, bool Overloaded,
UnresolvedSetIterator Begin, UnresolvedSetIterator Begin,
UnresolvedSetIterator End) { UnresolvedSetIterator End,
bool StdIsAssociatedNamespace = false) {
assert((ADL || !StdIsAssociatedNamespace) &&
"std considered associated namespace when not performing ADL");
return new(C) UnresolvedLookupExpr(C, NamingClass, QualifierLoc, NameInfo, return new(C) UnresolvedLookupExpr(C, NamingClass, QualifierLoc, NameInfo,
ADL, Overloaded, 0, Begin, End); ADL, Overloaded, 0, Begin, End,
StdIsAssociatedNamespace);
} }
static UnresolvedLookupExpr *Create(ASTContext &C, static UnresolvedLookupExpr *Create(ASTContext &C,
@ -1797,6 +1809,10 @@ public:
/// argument-dependent lookup. /// argument-dependent lookup.
bool requiresADL() const { return RequiresADL; } bool requiresADL() const { return RequiresADL; }
/// True if namespace ::std should be artificially added to the set of
/// associated namespaecs for argument-dependent lookup purposes.
bool isStdAssociatedNamespace() const { return StdIsAssociatedNamespace; }
/// True if this lookup is overloaded. /// True if this lookup is overloaded.
bool isOverloaded() const { return Overloaded; } bool isOverloaded() const { return Overloaded; }

View File

@ -39,6 +39,7 @@ struct PrintingPolicy {
PrintingPolicy(const LangOptions &LO) PrintingPolicy(const LangOptions &LO)
: Indentation(2), LangOpts(LO), SuppressSpecifiers(false), : Indentation(2), LangOpts(LO), SuppressSpecifiers(false),
SuppressTagKeyword(false), SuppressTag(false), SuppressScope(false), SuppressTagKeyword(false), SuppressTag(false), SuppressScope(false),
SuppressInitializers(false),
Dump(false), ConstantArraySizeAsWritten(false), Dump(false), ConstantArraySizeAsWritten(false),
AnonymousTagLocations(true) { } AnonymousTagLocations(true) { }
@ -87,6 +88,19 @@ struct PrintingPolicy {
/// \brief Suppresses printing of scope specifiers. /// \brief Suppresses printing of scope specifiers.
bool SuppressScope : 1; bool SuppressScope : 1;
/// \brief Suppress printing of variable initializers.
///
/// This flag is used when printing the loop variable in a for-range
/// statement. For example, given:
///
/// \code
/// for (auto x : coll)
/// \endcode
///
/// SuppressInitializers will be true when printing "auto x", so that the
/// internal initializer constructed for x will not be printed.
bool SuppressInitializers : 1;
/// \brief True when we are "dumping" rather than "pretty-printing", /// \brief True when we are "dumping" rather than "pretty-printing",
/// where dumping involves printing the internal details of the AST /// where dumping involves printing the internal details of the AST
/// and pretty-printing involves printing something similar to /// and pretty-printing involves printing something similar to

View File

@ -1696,6 +1696,7 @@ DEF_TRAVERSE_STMT(ObjCAtSynchronizedStmt, { })
DEF_TRAVERSE_STMT(ObjCAtThrowStmt, { }) DEF_TRAVERSE_STMT(ObjCAtThrowStmt, { })
DEF_TRAVERSE_STMT(ObjCAtTryStmt, { }) DEF_TRAVERSE_STMT(ObjCAtTryStmt, { })
DEF_TRAVERSE_STMT(ObjCForCollectionStmt, { }) DEF_TRAVERSE_STMT(ObjCForCollectionStmt, { })
DEF_TRAVERSE_STMT(CXXForRangeStmt, { })
DEF_TRAVERSE_STMT(ReturnStmt, { }) DEF_TRAVERSE_STMT(ReturnStmt, { })
DEF_TRAVERSE_STMT(SwitchStmt, { }) DEF_TRAVERSE_STMT(SwitchStmt, { })
DEF_TRAVERSE_STMT(WhileStmt, { }) DEF_TRAVERSE_STMT(WhileStmt, { })

View File

@ -119,6 +119,88 @@ public:
friend class ASTStmtReader; friend class ASTStmtReader;
}; };
/// CXXForRangeStmt - This represents C++0x [stmt.ranged]'s ranged for
/// statement, represented as 'for (range-declarator : range-expression)'.
///
/// This is stored in a partially-desugared form to allow full semantic
/// analysis of the constituent components. The original syntactic components
/// can be extracted using getLoopVariable and getRangeInit.
class CXXForRangeStmt : public Stmt {
enum { RANGE, BEGINEND, COND, INC, LOOPVAR, BODY, END };
// SubExprs[RANGE] is an expression or declstmt.
// SubExprs[COND] and SubExprs[INC] are expressions.
Stmt *SubExprs[END];
SourceLocation ForLoc;
SourceLocation ColonLoc;
SourceLocation RParenLoc;
public:
CXXForRangeStmt(DeclStmt *Range, DeclStmt *BeginEnd,
Expr *Cond, Expr *Inc, DeclStmt *LoopVar, Stmt *Body,
SourceLocation FL, SourceLocation CL, SourceLocation RPL);
CXXForRangeStmt(EmptyShell Empty) : Stmt(CXXForRangeStmtClass, Empty) { }
VarDecl *getLoopVariable();
Expr *getRangeInit();
const VarDecl *getLoopVariable() const;
const Expr *getRangeInit() const;
DeclStmt *getRangeStmt() { return cast<DeclStmt>(SubExprs[RANGE]); }
DeclStmt *getBeginEndStmt() { return cast_or_null<DeclStmt>(SubExprs[BEGINEND]); }
Expr *getCond() { return cast_or_null<Expr>(SubExprs[COND]); }
Expr *getInc() { return cast_or_null<Expr>(SubExprs[INC]); }
DeclStmt *getLoopVarStmt() { return cast<DeclStmt>(SubExprs[LOOPVAR]); }
Stmt *getBody() { return SubExprs[BODY]; }
const DeclStmt *getRangeStmt() const {
return cast<DeclStmt>(SubExprs[RANGE]);
}
const DeclStmt *getBeginEndStmt() const {
return cast_or_null<DeclStmt>(SubExprs[BEGINEND]);
}
const Expr *getCond() const {
return cast_or_null<Expr>(SubExprs[COND]);
}
const Expr *getInc() const {
return cast_or_null<Expr>(SubExprs[INC]);
}
const DeclStmt *getLoopVarStmt() const {
return cast<DeclStmt>(SubExprs[LOOPVAR]);
}
const Stmt *getBody() const { return SubExprs[BODY]; }
void setRangeInit(Expr *E) { SubExprs[RANGE] = reinterpret_cast<Stmt*>(E); }
void setRangeStmt(Stmt *S) { SubExprs[RANGE] = S; }
void setBeginEndStmt(Stmt *S) { SubExprs[BEGINEND] = S; }
void setCond(Expr *E) { SubExprs[COND] = reinterpret_cast<Stmt*>(E); }
void setInc(Expr *E) { SubExprs[INC] = reinterpret_cast<Stmt*>(E); }
void setLoopVarStmt(Stmt *S) { SubExprs[LOOPVAR] = S; }
void setBody(Stmt *S) { SubExprs[BODY] = S; }
SourceLocation getForLoc() const { return ForLoc; }
void setForLoc(SourceLocation Loc) { ForLoc = Loc; }
SourceLocation getColonLoc() const { return ColonLoc; }
void setColonLoc(SourceLocation Loc) { ColonLoc = Loc; }
SourceLocation getRParenLoc() const { return RParenLoc; }
void setRParenLoc(SourceLocation Loc) { RParenLoc = Loc; }
SourceRange getSourceRange() const {
return SourceRange(ForLoc, SubExprs[BODY]->getLocEnd());
}
static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXForRangeStmtClass;
}
static bool classof(const CXXForRangeStmt *) { return true; }
// Iterators
child_range children() {
return child_range(&SubExprs[0], &SubExprs[END]);
}
};
} // end namespace clang } // end namespace clang

View File

@ -82,6 +82,7 @@ public:
DISPATCH_CASE(ConditionalOperator) DISPATCH_CASE(ConditionalOperator)
DISPATCH_CASE(BinaryConditionalOperator) DISPATCH_CASE(BinaryConditionalOperator)
DISPATCH_CASE(ObjCForCollectionStmt) DISPATCH_CASE(ObjCForCollectionStmt)
DISPATCH_CASE(CXXForRangeStmt)
case Stmt::BinaryOperatorClass: { case Stmt::BinaryOperatorClass: {
BinaryOperator* B = cast<BinaryOperator>(S); BinaryOperator* B = cast<BinaryOperator>(S);
@ -109,6 +110,10 @@ public:
return static_cast<ImplClass*>(this)->BlockStmt_VisitStmt(S); return static_cast<ImplClass*>(this)->BlockStmt_VisitStmt(S);
} }
RetTy BlockStmt_VisitCXXForRangeStmt(CXXForRangeStmt* S) {
return static_cast<ImplClass*>(this)->BlockStmt_VisitStmt(S);
}
RetTy BlockStmt_VisitImplicitControlFlowExpr(Expr* E) { RetTy BlockStmt_VisitImplicitControlFlowExpr(Expr* E) {
return static_cast<ImplClass*>(this)->BlockStmt_VisitExpr(E); return static_cast<ImplClass*>(this)->BlockStmt_VisitExpr(E);
} }

View File

@ -996,6 +996,28 @@ def err_delegation_unimplemented : Error<
def err_delegating_initializer_alone : Error< def err_delegating_initializer_alone : Error<
"an initializer for a delegating constructor must appear alone">; "an initializer for a delegating constructor must appear alone">;
// C++0x range-based for loop
def err_for_range_decl_must_be_var : Error<
"for range declaration must declare a variable">;
def err_for_range_storage_class : Error<
"loop variable %0 may not be declared %select{'extern'|'static'|"
"'__private_extern__'|'auto'|'register'|'constexpr'}1">;
def err_type_defined_in_for_range : Error<
"types may not be defined in a for range declaration">;
def err_for_range_deduction_failure : Error<
"cannot use type %0 as a range">;
def err_for_range_incomplete_type : Error<
"cannot use incomplete type %0 as a range">;
def err_for_range_iter_deduction_failure : Error<
"cannot use type %0 as an iterator">;
def err_for_range_member_begin_end_mismatch : Error<
"range type %0 has '%select{begin|end}1' member but no '%select{end|begin}1' member">;
def err_for_range_begin_end_types_differ : Error<
"'begin' and 'end' must return the same type (got %0 and %1)">;
def note_for_range_type : Note<"range has type %0">;
def note_for_range_begin_end : Note<
"selected '%select{begin|end}0' %select{function|template }1%2 with iterator type %3">;
// Objective-C++ // Objective-C++
def err_objc_decls_may_only_appear_in_global_scope : Error< def err_objc_decls_may_only_appear_in_global_scope : Error<
"Objective-C declarations may only appear in global scope">; "Objective-C declarations may only appear in global scope">;

View File

@ -41,6 +41,7 @@ def ObjCForCollectionStmt : Stmt;
// C++ statments // C++ statments
def CXXCatchStmt : Stmt; def CXXCatchStmt : Stmt;
def CXXTryStmt : Stmt; def CXXTryStmt : Stmt;
def CXXForRangeStmt : Stmt;
// Expressions // Expressions
def Expr : Stmt<1>; def Expr : Stmt<1>;

View File

@ -1288,6 +1288,15 @@ private:
DSC_top_level // top-level/namespace declaration context DSC_top_level // top-level/namespace declaration context
}; };
/// Information on a C++0x for-range-initializer found while parsing a
/// declaration which turns out to be a for-range-declaration.
struct ForRangeInit {
SourceLocation ColonLoc;
ExprResult RangeExpr;
bool ParsedForRangeDecl() { return !ColonLoc.isInvalid(); }
};
DeclGroupPtrTy ParseDeclaration(StmtVector &Stmts, DeclGroupPtrTy ParseDeclaration(StmtVector &Stmts,
unsigned Context, SourceLocation &DeclEnd, unsigned Context, SourceLocation &DeclEnd,
ParsedAttributesWithRange &attrs); ParsedAttributesWithRange &attrs);
@ -1295,12 +1304,17 @@ private:
unsigned Context, unsigned Context,
SourceLocation &DeclEnd, SourceLocation &DeclEnd,
ParsedAttributes &attrs, ParsedAttributes &attrs,
bool RequireSemi); bool RequireSemi,
ForRangeInit *FRI = 0);
DeclGroupPtrTy ParseDeclGroup(ParsingDeclSpec &DS, unsigned Context, DeclGroupPtrTy ParseDeclGroup(ParsingDeclSpec &DS, unsigned Context,
bool AllowFunctionDefinitions, bool AllowFunctionDefinitions,
SourceLocation *DeclEnd = 0); SourceLocation *DeclEnd = 0,
ForRangeInit *FRI = 0);
Decl *ParseDeclarationAfterDeclarator(Declarator &D, Decl *ParseDeclarationAfterDeclarator(Declarator &D,
const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo()); const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo());
bool ParseAttributesAfterDeclarator(Declarator &D);
Decl *ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D,
const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo());
Decl *ParseFunctionStatementBody(Decl *Decl, ParseScope &BodyScope); Decl *ParseFunctionStatementBody(Decl *Decl, ParseScope &BodyScope);
Decl *ParseFunctionTryBlock(Decl *Decl, ParseScope &BodyScope); Decl *ParseFunctionTryBlock(Decl *Decl, ParseScope &BodyScope);

View File

@ -864,6 +864,7 @@ public:
bool TypeMayContainAuto); bool TypeMayContainAuto);
void ActOnUninitializedDecl(Decl *dcl, bool TypeMayContainAuto); void ActOnUninitializedDecl(Decl *dcl, bool TypeMayContainAuto);
void ActOnInitializerError(Decl *Dcl); void ActOnInitializerError(Decl *Dcl);
void ActOnCXXForRangeDecl(Decl *D);
void SetDeclDeleted(Decl *dcl, SourceLocation DelLoc); void SetDeclDeleted(Decl *dcl, SourceLocation DelLoc);
void FinalizeDeclaration(Decl *D); void FinalizeDeclaration(Decl *D);
DeclGroupPtrTy FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS, DeclGroupPtrTy FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS,
@ -1268,7 +1269,8 @@ public:
Expr **Args, unsigned NumArgs, Expr **Args, unsigned NumArgs,
TemplateArgumentListInfo *ExplicitTemplateArgs, TemplateArgumentListInfo *ExplicitTemplateArgs,
OverloadCandidateSet& CandidateSet, OverloadCandidateSet& CandidateSet,
bool PartialOverloading = false); bool PartialOverloading = false,
bool StdNamespaceIsAssociated = false);
// Emit as a 'note' the specific overload candidate // Emit as a 'note' the specific overload candidate
void NoteOverloadCandidate(FunctionDecl *Fn); void NoteOverloadCandidate(FunctionDecl *Fn);
@ -1473,7 +1475,8 @@ public:
void ArgumentDependentLookup(DeclarationName Name, bool Operator, void ArgumentDependentLookup(DeclarationName Name, bool Operator,
Expr **Args, unsigned NumArgs, Expr **Args, unsigned NumArgs,
ADLResult &Functions); ADLResult &Functions,
bool StdNamespaceIsAssociated = false);
void LookupVisibleDecls(Scope *S, LookupNameKind Kind, void LookupVisibleDecls(Scope *S, LookupNameKind Kind,
VisibleDeclConsumer &Consumer, VisibleDeclConsumer &Consumer,
@ -1804,6 +1807,17 @@ public:
SourceLocation LParenLoc, SourceLocation LParenLoc,
Stmt *First, Expr *Second, Stmt *First, Expr *Second,
SourceLocation RParenLoc, Stmt *Body); SourceLocation RParenLoc, Stmt *Body);
StmtResult ActOnCXXForRangeStmt(SourceLocation ForLoc,
SourceLocation LParenLoc, Stmt *LoopVar,
SourceLocation ColonLoc, Expr *Collection,
SourceLocation RParenLoc);
StmtResult BuildCXXForRangeStmt(SourceLocation ForLoc,
SourceLocation ColonLoc,
Stmt *RangeDecl, Stmt *BeginEndDecl,
Expr *Cond, Expr *Inc,
Stmt *LoopVarDecl,
SourceLocation RParenLoc);
StmtResult FinishCXXForRangeStmt(Stmt *ForRange, Stmt *Body);
StmtResult ActOnGotoStmt(SourceLocation GotoLoc, StmtResult ActOnGotoStmt(SourceLocation GotoLoc,
SourceLocation LabelLoc, SourceLocation LabelLoc,

View File

@ -624,7 +624,11 @@ namespace clang {
/// \brief NSConstantString type /// \brief NSConstantString type
SPECIAL_TYPE_NS_CONSTANT_STRING = 15, SPECIAL_TYPE_NS_CONSTANT_STRING = 15,
/// \brief Whether __[u]int128_t identifier is installed. /// \brief Whether __[u]int128_t identifier is installed.
SPECIAL_TYPE_INT128_INSTALLED = 16 SPECIAL_TYPE_INT128_INSTALLED = 16,
/// \brief Cached "auto" deduction type.
SPECIAL_TYPE_AUTO_DEDUCT = 17,
/// \brief Cached "auto &&" deduction type.
SPECIAL_TYPE_AUTO_RREF_DEDUCT = 18
}; };
/// \brief Record codes for each kind of declaration. /// \brief Record codes for each kind of declaration.
@ -915,6 +919,8 @@ namespace clang {
STMT_CXX_CATCH, STMT_CXX_CATCH,
/// \brief A CXXTryStmt record. /// \brief A CXXTryStmt record.
STMT_CXX_TRY, STMT_CXX_TRY,
/// \brief A CXXForRangeStmt record.
STMT_CXX_FOR_RANGE,
/// \brief A CXXOperatorCallExpr record. /// \brief A CXXOperatorCallExpr record.
EXPR_CXX_OPERATOR_CALL, EXPR_CXX_OPERATOR_CALL,

View File

@ -2754,6 +2754,22 @@ QualType ASTContext::getAutoType(QualType DeducedType) const {
return QualType(AT, 0); return QualType(AT, 0);
} }
/// getAutoDeductType - Get type pattern for deducing against 'auto'.
QualType ASTContext::getAutoDeductType() const {
if (AutoDeductTy.isNull())
AutoDeductTy = getAutoType(QualType());
assert(!AutoDeductTy.isNull() && "can't build 'auto' pattern");
return AutoDeductTy;
}
/// getAutoRRefDeductType - Get type pattern for deducing against 'auto &&'.
QualType ASTContext::getAutoRRefDeductType() const {
if (AutoRRefDeductTy.isNull())
AutoRRefDeductTy = getRValueReferenceType(getAutoDeductType());
assert(!AutoRRefDeductTy.isNull() && "can't build 'auto &&' pattern");
return AutoRRefDeductTy;
}
/// getTagDeclType - Return the unique reference to the type for the /// getTagDeclType - Return the unique reference to the type for the
/// specified TagDecl (struct/union/class/enum) decl. /// specified TagDecl (struct/union/class/enum) decl.
QualType ASTContext::getTagDeclType(const TagDecl *Decl) const { QualType ASTContext::getTagDeclType(const TagDecl *Decl) const {

View File

@ -567,7 +567,8 @@ void DeclPrinter::VisitVarDecl(VarDecl *D) {
T = Parm->getOriginalType(); T = Parm->getOriginalType();
T.getAsStringInternal(Name, Policy); T.getAsStringInternal(Name, Policy);
Out << Name; Out << Name;
if (Expr *Init = D->getInit()) { Expr *Init = D->getInit();
if (!Policy.SuppressInitializers && Init) {
if (D->hasCXXDirectInitializer()) if (D->hasCXXDirectInitializer())
Out << "("; Out << "(";
else { else {

View File

@ -189,7 +189,7 @@ UnresolvedLookupExpr::Create(ASTContext &C,
ExplicitTemplateArgumentList::sizeFor(Args)); ExplicitTemplateArgumentList::sizeFor(Args));
return new (Mem) UnresolvedLookupExpr(C, NamingClass, QualifierLoc, NameInfo, return new (Mem) UnresolvedLookupExpr(C, NamingClass, QualifierLoc, NameInfo,
ADL, /*Overload*/ true, &Args, ADL, /*Overload*/ true, &Args,
Begin, End); Begin, End, /*StdIsAssociated=*/false);
} }
UnresolvedLookupExpr * UnresolvedLookupExpr *

View File

@ -540,6 +540,40 @@ CXXTryStmt::CXXTryStmt(SourceLocation tryLoc, Stmt *tryBlock,
std::copy(handlers, handlers + NumHandlers, Stmts + 1); std::copy(handlers, handlers + NumHandlers, Stmts + 1);
} }
CXXForRangeStmt::CXXForRangeStmt(DeclStmt *Range, DeclStmt *BeginEndStmt,
Expr *Cond, Expr *Inc, DeclStmt *LoopVar,
Stmt *Body, SourceLocation FL,
SourceLocation CL, SourceLocation RPL)
: Stmt(CXXForRangeStmtClass), ForLoc(FL), ColonLoc(CL), RParenLoc(RPL) {
SubExprs[RANGE] = Range;
SubExprs[BEGINEND] = BeginEndStmt;
SubExprs[COND] = reinterpret_cast<Stmt*>(Cond);
SubExprs[INC] = reinterpret_cast<Stmt*>(Inc);
SubExprs[LOOPVAR] = LoopVar;
SubExprs[BODY] = Body;
}
Expr *CXXForRangeStmt::getRangeInit() {
DeclStmt *RangeStmt = getRangeStmt();
VarDecl *RangeDecl = dyn_cast_or_null<VarDecl>(RangeStmt->getSingleDecl());
assert(RangeDecl &&& "for-range should have a single var decl");
return RangeDecl->getInit();
}
const Expr *CXXForRangeStmt::getRangeInit() const {
return const_cast<CXXForRangeStmt*>(this)->getRangeInit();
}
VarDecl *CXXForRangeStmt::getLoopVariable() {
Decl *LV = cast<DeclStmt>(getLoopVarStmt())->getSingleDecl();
assert(LV && "No loop variable in CXXForRangeStmt");
return cast<VarDecl>(LV);
}
const VarDecl *CXXForRangeStmt::getLoopVariable() const {
return const_cast<CXXForRangeStmt*>(this)->getLoopVariable();
}
IfStmt::IfStmt(ASTContext &C, SourceLocation IL, VarDecl *var, Expr *cond, IfStmt::IfStmt(ASTContext &C, SourceLocation IL, VarDecl *var, Expr *cond,
Stmt *then, SourceLocation EL, Stmt *elsev) Stmt *then, SourceLocation EL, Stmt *elsev)
: Stmt(IfStmtClass), IfLoc(IL), ElseLoc(EL) : Stmt(IfStmtClass), IfLoc(IL), ElseLoc(EL)

View File

@ -291,6 +291,18 @@ void StmtPrinter::VisitObjCForCollectionStmt(ObjCForCollectionStmt *Node) {
} }
} }
void StmtPrinter::VisitCXXForRangeStmt(CXXForRangeStmt *Node) {
Indent() << "for (";
PrintingPolicy SubPolicy(Policy);
SubPolicy.SuppressInitializers = true;
Node->getLoopVariable()->print(OS, SubPolicy, IndentLevel);
OS << " : ";
PrintExpr(Node->getRangeInit());
OS << ") {\n";
PrintStmt(Node->getBody());
Indent() << "}\n";
}
void StmtPrinter::VisitGotoStmt(GotoStmt *Node) { void StmtPrinter::VisitGotoStmt(GotoStmt *Node) {
Indent() << "goto " << Node->getLabel()->getName() << ";\n"; Indent() << "goto " << Node->getLabel()->getName() << ";\n";
} }

View File

@ -177,6 +177,10 @@ void StmtProfiler::VisitCXXTryStmt(CXXTryStmt *S) {
VisitStmt(S); VisitStmt(S);
} }
void StmtProfiler::VisitCXXForRangeStmt(CXXForRangeStmt *S) {
VisitStmt(S);
}
void StmtProfiler::VisitObjCForCollectionStmt(ObjCForCollectionStmt *S) { void StmtProfiler::VisitObjCForCollectionStmt(ObjCForCollectionStmt *S) {
VisitStmt(S); VisitStmt(S);
} }

View File

@ -312,6 +312,7 @@ private:
AddStmtChoice asc); AddStmtChoice asc);
CFGBlock *VisitCXXThrowExpr(CXXThrowExpr *T); CFGBlock *VisitCXXThrowExpr(CXXThrowExpr *T);
CFGBlock *VisitCXXTryStmt(CXXTryStmt *S); CFGBlock *VisitCXXTryStmt(CXXTryStmt *S);
CFGBlock *VisitCXXForRangeStmt(CXXForRangeStmt *S);
CFGBlock *VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E, CFGBlock *VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E,
AddStmtChoice asc); AddStmtChoice asc);
CFGBlock *VisitCXXConstructExpr(CXXConstructExpr *C, AddStmtChoice asc); CFGBlock *VisitCXXConstructExpr(CXXConstructExpr *C, AddStmtChoice asc);
@ -911,6 +912,9 @@ tryAgain:
case Stmt::CXXTryStmtClass: case Stmt::CXXTryStmtClass:
return VisitCXXTryStmt(cast<CXXTryStmt>(S)); return VisitCXXTryStmt(cast<CXXTryStmt>(S));
case Stmt::CXXForRangeStmtClass:
return VisitCXXForRangeStmt(cast<CXXForRangeStmt>(S));
case Stmt::DeclStmtClass: case Stmt::DeclStmtClass:
return VisitDeclStmt(cast<DeclStmt>(S)); return VisitDeclStmt(cast<DeclStmt>(S));
@ -2513,6 +2517,122 @@ CFGBlock* CFGBuilder::VisitCXXCatchStmt(CXXCatchStmt* CS) {
return CatchBlock; return CatchBlock;
} }
CFGBlock* CFGBuilder::VisitCXXForRangeStmt(CXXForRangeStmt* S) {
// C++0x for-range statements are specified as [stmt.ranged]:
//
// {
// auto && __range = range-init;
// for ( auto __begin = begin-expr,
// __end = end-expr;
// __begin != __end;
// ++__begin ) {
// for-range-declaration = *__begin;
// statement
// }
// }
// Save local scope position before the addition of the implicit variables.
SaveAndRestore<LocalScope::const_iterator> save_scope_pos(ScopePos);
// Create local scopes and destructors for range, begin and end variables.
if (Stmt *Range = S->getRangeStmt())
addLocalScopeForStmt(Range);
if (Stmt *BeginEnd = S->getBeginEndStmt())
addLocalScopeForStmt(BeginEnd);
addAutomaticObjDtors(ScopePos, save_scope_pos.get(), S);
LocalScope::const_iterator ContinueScopePos = ScopePos;
// "for" is a control-flow statement. Thus we stop processing the current
// block.
CFGBlock* LoopSuccessor = NULL;
if (Block) {
if (badCFG)
return 0;
LoopSuccessor = Block;
} else
LoopSuccessor = Succ;
// Save the current value for the break targets.
// All breaks should go to the code following the loop.
SaveAndRestore<JumpTarget> save_break(BreakJumpTarget);
BreakJumpTarget = JumpTarget(LoopSuccessor, ScopePos);
// The block for the __begin != __end expression.
CFGBlock* ConditionBlock = createBlock(false);
ConditionBlock->setTerminator(S);
// Now add the actual condition to the condition block.
if (Expr *C = S->getCond()) {
Block = ConditionBlock;
CFGBlock *BeginConditionBlock = addStmt(C);
if (badCFG)
return 0;
assert(BeginConditionBlock == ConditionBlock &&
"condition block in for-range was unexpectedly complex");
(void)BeginConditionBlock;
}
// The condition block is the implicit successor for the loop body as well as
// any code above the loop.
Succ = ConditionBlock;
// See if this is a known constant.
TryResult KnownVal(true);
if (S->getCond())
KnownVal = tryEvaluateBool(S->getCond());
// Now create the loop body.
{
assert(S->getBody());
// Save the current values for Block, Succ, and continue targets.
SaveAndRestore<CFGBlock*> save_Block(Block), save_Succ(Succ);
SaveAndRestore<JumpTarget> save_continue(ContinueJumpTarget);
// Generate increment code in its own basic block. This is the target of
// continue statements.
Block = 0;
Succ = addStmt(S->getInc());
ContinueJumpTarget = JumpTarget(Succ, ContinueScopePos);
// The starting block for the loop increment is the block that should
// represent the 'loop target' for looping back to the start of the loop.
ContinueJumpTarget.block->setLoopTarget(S);
// Finish up the increment block and prepare to start the loop body.
assert(Block);
if (badCFG)
return 0;
Block = 0;
// Add implicit scope and dtors for loop variable.
addLocalScopeAndDtors(S->getLoopVarStmt());
// Populate a new block to contain the loop body and loop variable.
Block = addStmt(S->getBody());
if (badCFG)
return 0;
Block = addStmt(S->getLoopVarStmt());
if (badCFG)
return 0;
// This new body block is a successor to our condition block.
addSuccessor(ConditionBlock, KnownVal.isFalse() ? 0 : Block);
}
// Link up the condition block with the code that follows the loop (the
// false branch).
addSuccessor(ConditionBlock, KnownVal.isTrue() ? 0 : LoopSuccessor);
// Add the initialization statements.
Block = createBlock();
addStmt(S->getRangeStmt());
return addStmt(S->getBeginEndStmt());
}
CFGBlock *CFGBuilder::VisitExprWithCleanups(ExprWithCleanups *E, CFGBlock *CFGBuilder::VisitExprWithCleanups(ExprWithCleanups *E,
AddStmtChoice asc) { AddStmtChoice asc) {
if (BuildOpts.AddImplicitDtors) { if (BuildOpts.AddImplicitDtors) {

View File

@ -153,6 +153,9 @@ void CodeGenFunction::EmitStmt(const Stmt *S) {
case Stmt::CXXTryStmtClass: case Stmt::CXXTryStmtClass:
EmitCXXTryStmt(cast<CXXTryStmt>(*S)); EmitCXXTryStmt(cast<CXXTryStmt>(*S));
break; break;
case Stmt::CXXForRangeStmtClass:
EmitCXXForRangeStmt(cast<CXXForRangeStmt>(*S));
break;
} }
} }
@ -636,6 +639,80 @@ void CodeGenFunction::EmitForStmt(const ForStmt &S) {
EmitBlock(LoopExit.getBlock(), true); EmitBlock(LoopExit.getBlock(), true);
} }
void CodeGenFunction::EmitCXXForRangeStmt(const CXXForRangeStmt &S) {
JumpDest LoopExit = getJumpDestInCurrentScope("for.end");
RunCleanupsScope ForScope(*this);
CGDebugInfo *DI = getDebugInfo();
if (DI) {
DI->setLocation(S.getSourceRange().getBegin());
DI->EmitRegionStart(Builder);
}
// Evaluate the first pieces before the loop.
EmitStmt(S.getRangeStmt());
EmitStmt(S.getBeginEndStmt());
// Start the loop with a block that tests the condition.
// If there's an increment, the continue scope will be overwritten
// later.
llvm::BasicBlock *CondBlock = createBasicBlock("for.cond");
EmitBlock(CondBlock);
// If there are any cleanups between here and the loop-exit scope,
// create a block to stage a loop exit along.
llvm::BasicBlock *ExitBlock = LoopExit.getBlock();
if (ForScope.requiresCleanups())
ExitBlock = createBasicBlock("for.cond.cleanup");
// The loop body, consisting of the specified body and the loop variable.
llvm::BasicBlock *ForBody = createBasicBlock("for.body");
// The body is executed if the expression, contextually converted
// to bool, is true.
llvm::Value *BoolCondVal = EvaluateExprAsBool(S.getCond());
Builder.CreateCondBr(BoolCondVal, ForBody, ExitBlock);
if (ExitBlock != LoopExit.getBlock()) {
EmitBlock(ExitBlock);
EmitBranchThroughCleanup(LoopExit);
}
EmitBlock(ForBody);
// Create a block for the increment. In case of a 'continue', we jump there.
JumpDest Continue = getJumpDestInCurrentScope("for.inc");
// Store the blocks to use for break and continue.
BreakContinueStack.push_back(BreakContinue(LoopExit, Continue));
{
// Create a separate cleanup scope for the loop variable and body.
RunCleanupsScope BodyScope(*this);
EmitStmt(S.getLoopVarStmt());
EmitStmt(S.getBody());
}
// If there is an increment, emit it next.
EmitBlock(Continue.getBlock());
EmitStmt(S.getInc());
BreakContinueStack.pop_back();
EmitBranch(CondBlock);
ForScope.ForceCleanup();
if (DI) {
DI->setLocation(S.getSourceRange().getEnd());
DI->EmitRegionEnd(Builder);
}
// Emit the fall-through block.
EmitBlock(LoopExit.getBlock(), true);
}
void CodeGenFunction::EmitReturnOfRValue(RValue RV, QualType Ty) { void CodeGenFunction::EmitReturnOfRValue(RValue RV, QualType Ty) {
if (RV.isScalar()) { if (RV.isScalar()) {
Builder.CreateStore(RV.getScalarVal(), ReturnValue); Builder.CreateStore(RV.getScalarVal(), ReturnValue);

View File

@ -42,6 +42,7 @@ namespace clang {
class APValue; class APValue;
class ASTContext; class ASTContext;
class CXXDestructorDecl; class CXXDestructorDecl;
class CXXForRangeStmt;
class CXXTryStmt; class CXXTryStmt;
class Decl; class Decl;
class LabelDecl; class LabelDecl;
@ -1694,6 +1695,7 @@ public:
void ExitCXXTryStmt(const CXXTryStmt &S, bool IsFnTryBlock = false); void ExitCXXTryStmt(const CXXTryStmt &S, bool IsFnTryBlock = false);
void EmitCXXTryStmt(const CXXTryStmt &S); void EmitCXXTryStmt(const CXXTryStmt &S);
void EmitCXXForRangeStmt(const CXXForRangeStmt &S);
//===--------------------------------------------------------------------===// //===--------------------------------------------------------------------===//
// LValue Expression Emission // LValue Expression Emission

View File

@ -705,13 +705,21 @@ Parser::DeclGroupPtrTy Parser::ParseDeclaration(StmtVector &Stmts,
///[C90/C++]init-declarator-list ';' [TODO] ///[C90/C++]init-declarator-list ';' [TODO]
/// [OMP] threadprivate-directive [TODO] /// [OMP] threadprivate-directive [TODO]
/// ///
/// for-range-declaration: [C++0x 6.5p1: stmt.ranged]
/// attribute-specifier-seq[opt] type-specifier-seq declarator
///
/// If RequireSemi is false, this does not check for a ';' at the end of the /// If RequireSemi is false, this does not check for a ';' at the end of the
/// declaration. If it is true, it checks for and eats it. /// declaration. If it is true, it checks for and eats it.
///
/// If FRI is non-null, we might be parsing a for-range-declaration instead
/// of a simple-declaration. If we find that we are, we also parse the
/// for-range-initializer, and place it here.
Parser::DeclGroupPtrTy Parser::ParseSimpleDeclaration(StmtVector &Stmts, Parser::DeclGroupPtrTy Parser::ParseSimpleDeclaration(StmtVector &Stmts,
unsigned Context, unsigned Context,
SourceLocation &DeclEnd, SourceLocation &DeclEnd,
ParsedAttributes &attrs, ParsedAttributes &attrs,
bool RequireSemi) { bool RequireSemi,
ForRangeInit *FRI) {
// Parse the common declaration-specifiers piece. // Parse the common declaration-specifiers piece.
ParsingDeclSpec DS(*this); ParsingDeclSpec DS(*this);
DS.takeAttributesFrom(attrs); DS.takeAttributesFrom(attrs);
@ -731,7 +739,7 @@ Parser::DeclGroupPtrTy Parser::ParseSimpleDeclaration(StmtVector &Stmts,
return Actions.ConvertDeclToDeclGroup(TheDecl); return Actions.ConvertDeclToDeclGroup(TheDecl);
} }
return ParseDeclGroup(DS, Context, /*FunctionDefs=*/ false, &DeclEnd); return ParseDeclGroup(DS, Context, /*FunctionDefs=*/ false, &DeclEnd, FRI);
} }
/// ParseDeclGroup - Having concluded that this is either a function /// ParseDeclGroup - Having concluded that this is either a function
@ -740,7 +748,8 @@ Parser::DeclGroupPtrTy Parser::ParseSimpleDeclaration(StmtVector &Stmts,
Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
unsigned Context, unsigned Context,
bool AllowFunctionDefinitions, bool AllowFunctionDefinitions,
SourceLocation *DeclEnd) { SourceLocation *DeclEnd,
ForRangeInit *FRI) {
// Parse the first declarator. // Parse the first declarator.
ParsingDeclarator D(*this, DS, static_cast<Declarator::TheContext>(Context)); ParsingDeclarator D(*this, DS, static_cast<Declarator::TheContext>(Context));
ParseDeclarator(D); ParseDeclarator(D);
@ -786,8 +795,24 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
} }
} }
if (ParseAttributesAfterDeclarator(D))
return DeclGroupPtrTy();
// C++0x [stmt.iter]p1: Check if we have a for-range-declarator. If so, we
// must parse and analyze the for-range-initializer before the declaration is
// analyzed.
if (FRI && Tok.is(tok::colon)) {
FRI->ColonLoc = ConsumeToken();
// FIXME: handle braced-init-list here.
FRI->RangeExpr = ParseExpression();
Decl *ThisDecl = Actions.ActOnDeclarator(getCurScope(), D);
Actions.ActOnCXXForRangeDecl(ThisDecl);
Actions.FinalizeDeclaration(ThisDecl);
return Actions.FinalizeDeclaratorGroup(getCurScope(), DS, &ThisDecl, 1);
}
llvm::SmallVector<Decl *, 8> DeclsInGroup; llvm::SmallVector<Decl *, 8> DeclsInGroup;
Decl *FirstDecl = ParseDeclarationAfterDeclarator(D); Decl *FirstDecl = ParseDeclarationAfterDeclaratorAndAttributes(D);
D.complete(FirstDecl); D.complete(FirstDecl);
if (FirstDecl) if (FirstDecl)
DeclsInGroup.push_back(FirstDecl); DeclsInGroup.push_back(FirstDecl);
@ -841,6 +866,26 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
DeclsInGroup.size()); DeclsInGroup.size());
} }
/// Parse an optional simple-asm-expr and attributes, and attach them to a
/// declarator. Returns true on an error.
bool Parser::ParseAttributesAfterDeclarator(Declarator &D) {
// If a simple-asm-expr is present, parse it.
if (Tok.is(tok::kw_asm)) {
SourceLocation Loc;
ExprResult AsmLabel(ParseSimpleAsm(&Loc));
if (AsmLabel.isInvalid()) {
SkipUntil(tok::semi, true, true);
return true;
}
D.setAsmLabel(AsmLabel.release());
D.SetRangeEnd(Loc);
}
MaybeParseGNUAttributes(D);
return false;
}
/// \brief Parse 'declaration' after parsing 'declaration-specifiers /// \brief Parse 'declaration' after parsing 'declaration-specifiers
/// declarator'. This method parses the remainder of the declaration /// declarator'. This method parses the remainder of the declaration
/// (including any attributes or initializer, among other things) and /// (including any attributes or initializer, among other things) and
@ -864,21 +909,14 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
/// ///
Decl *Parser::ParseDeclarationAfterDeclarator(Declarator &D, Decl *Parser::ParseDeclarationAfterDeclarator(Declarator &D,
const ParsedTemplateInfo &TemplateInfo) { const ParsedTemplateInfo &TemplateInfo) {
// If a simple-asm-expr is present, parse it. if (ParseAttributesAfterDeclarator(D))
if (Tok.is(tok::kw_asm)) { return 0;
SourceLocation Loc;
ExprResult AsmLabel(ParseSimpleAsm(&Loc));
if (AsmLabel.isInvalid()) {
SkipUntil(tok::semi, true, true);
return 0;
}
D.setAsmLabel(AsmLabel.release()); return ParseDeclarationAfterDeclaratorAndAttributes(D, TemplateInfo);
D.SetRangeEnd(Loc); }
}
MaybeParseGNUAttributes(D);
Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D,
const ParsedTemplateInfo &TemplateInfo) {
// Inform the current actions module that we just parsed this declarator. // Inform the current actions module that we just parsed this declarator.
Decl *ThisDecl = 0; Decl *ThisDecl = 0;
switch (TemplateInfo.Kind) { switch (TemplateInfo.Kind) {

View File

@ -977,6 +977,7 @@ StmtResult Parser::ParseDoStatement(ParsedAttributes &attrs) {
/// 'for' '(' declaration expr[opt] ';' expr[opt] ')' statement /// 'for' '(' declaration expr[opt] ';' expr[opt] ')' statement
/// [C++] 'for' '(' for-init-statement condition[opt] ';' expression[opt] ')' /// [C++] 'for' '(' for-init-statement condition[opt] ';' expression[opt] ')'
/// [C++] statement /// [C++] statement
/// [C++0x] 'for' '(' for-range-declaration : for-range-initializer ) statement
/// [OBJC2] 'for' '(' declaration 'in' expr ')' statement /// [OBJC2] 'for' '(' declaration 'in' expr ')' statement
/// [OBJC2] 'for' '(' expr 'in' expr ')' statement /// [OBJC2] 'for' '(' expr 'in' expr ')' statement
/// ///
@ -984,6 +985,11 @@ StmtResult Parser::ParseDoStatement(ParsedAttributes &attrs) {
/// [C++] expression-statement /// [C++] expression-statement
/// [C++] simple-declaration /// [C++] simple-declaration
/// ///
/// [C++0x] for-range-declaration:
/// [C++0x] attribute-specifier-seq[opt] type-specifier-seq declarator
/// [C++0x] for-range-initializer:
/// [C++0x] expression
/// [C++0x] braced-init-list [TODO]
StmtResult Parser::ParseForStatement(ParsedAttributes &attrs) { StmtResult Parser::ParseForStatement(ParsedAttributes &attrs) {
// FIXME: Use attributes? // FIXME: Use attributes?
@ -1025,11 +1031,12 @@ StmtResult Parser::ParseForStatement(ParsedAttributes &attrs) {
SourceLocation LParenLoc = ConsumeParen(); SourceLocation LParenLoc = ConsumeParen();
ExprResult Value; ExprResult Value;
bool ForEach = false; bool ForEach = false, ForRange = false;
StmtResult FirstPart; StmtResult FirstPart;
bool SecondPartIsInvalid = false; bool SecondPartIsInvalid = false;
FullExprArg SecondPart(Actions); FullExprArg SecondPart(Actions);
ExprResult Collection; ExprResult Collection;
ForRangeInit ForRangeInit;
FullExprArg ThirdPart(Actions); FullExprArg ThirdPart(Actions);
Decl *SecondVar = 0; Decl *SecondVar = 0;
@ -1052,13 +1059,21 @@ StmtResult Parser::ParseForStatement(ParsedAttributes &attrs) {
ParsedAttributesWithRange attrs(AttrFactory); ParsedAttributesWithRange attrs(AttrFactory);
MaybeParseCXX0XAttributes(attrs); MaybeParseCXX0XAttributes(attrs);
// In C++0x, "for (T NS:a" might not be a typo for ::
bool MightBeForRangeStmt = getLang().CPlusPlus;
ColonProtectionRAIIObject ColonProtection(*this, MightBeForRangeStmt);
SourceLocation DeclStart = Tok.getLocation(), DeclEnd; SourceLocation DeclStart = Tok.getLocation(), DeclEnd;
StmtVector Stmts(Actions); StmtVector Stmts(Actions);
DeclGroupPtrTy DG = ParseSimpleDeclaration(Stmts, Declarator::ForContext, DeclGroupPtrTy DG = ParseSimpleDeclaration(Stmts, Declarator::ForContext,
DeclEnd, attrs, false); DeclEnd, attrs, false,
MightBeForRangeStmt ?
&ForRangeInit : 0);
FirstPart = Actions.ActOnDeclStmt(DG, DeclStart, Tok.getLocation()); FirstPart = Actions.ActOnDeclStmt(DG, DeclStart, Tok.getLocation());
if (Tok.is(tok::semi)) { // for (int x = 4; if (ForRangeInit.ParsedForRangeDecl()) {
ForRange = true;
} else if (Tok.is(tok::semi)) { // for (int x = 4;
ConsumeToken(); ConsumeToken();
} else if ((ForEach = isTokIdentifier_in())) { } else if ((ForEach = isTokIdentifier_in())) {
Actions.ActOnForEachDeclStmt(DG); Actions.ActOnForEachDeclStmt(DG);
@ -1107,7 +1122,7 @@ StmtResult Parser::ParseForStatement(ParsedAttributes &attrs) {
} }
} }
} }
if (!ForEach) { if (!ForEach && !ForRange) {
assert(!SecondPart.get() && "Shouldn't have a second expression yet."); assert(!SecondPart.get() && "Shouldn't have a second expression yet.");
// Parse the second part of the for specifier. // Parse the second part of the for specifier.
if (Tok.is(tok::semi)) { // for (...;; if (Tok.is(tok::semi)) { // for (...;;
@ -1149,6 +1164,17 @@ StmtResult Parser::ParseForStatement(ParsedAttributes &attrs) {
// Match the ')'. // Match the ')'.
SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc); SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
// We need to perform most of the semantic analysis for a C++0x for-range
// statememt before parsing the body, in order to be able to deduce the type
// of an auto-typed loop variable.
StmtResult ForRangeStmt;
if (ForRange)
ForRangeStmt = Actions.ActOnCXXForRangeStmt(ForLoc, LParenLoc,
FirstPart.take(),
ForRangeInit.ColonLoc,
ForRangeInit.RangeExpr.get(),
RParenLoc);
// C99 6.8.5p5 - In C99, the body of the if statement is a scope, even if // C99 6.8.5p5 - In C99, the body of the if statement is a scope, even if
// there is no compound stmt. C90 does not have this clause. We only do this // there is no compound stmt. C90 does not have this clause. We only do this
// if the body isn't a compound statement to avoid push/pop in common cases. // if the body isn't a compound statement to avoid push/pop in common cases.
@ -1175,15 +1201,19 @@ StmtResult Parser::ParseForStatement(ParsedAttributes &attrs) {
if (Body.isInvalid()) if (Body.isInvalid())
return StmtError(); return StmtError();
if (!ForEach) if (ForEach)
return Actions.ActOnForStmt(ForLoc, LParenLoc, FirstPart.take(), SecondPart, // FIXME: It isn't clear how to communicate the late destruction of
SecondVar, ThirdPart, RParenLoc, Body.take()); // C++ temporaries used to create the collection.
return Actions.ActOnObjCForCollectionStmt(ForLoc, LParenLoc,
FirstPart.take(),
Collection.take(), RParenLoc,
Body.take());
// FIXME: It isn't clear how to communicate the late destruction of if (ForRange)
// C++ temporaries used to create the collection. return Actions.FinishCXXForRangeStmt(ForRangeStmt.take(), Body.take());
return Actions.ActOnObjCForCollectionStmt(ForLoc, LParenLoc, FirstPart.take(),
Collection.take(), RParenLoc, return Actions.ActOnForStmt(ForLoc, LParenLoc, FirstPart.take(), SecondPart,
Body.take()); SecondVar, ThirdPart, RParenLoc, Body.take());
} }
/// ParseGotoStatement /// ParseGotoStatement

View File

@ -5247,6 +5247,47 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl,
} }
} }
void Sema::ActOnCXXForRangeDecl(Decl *D) {
VarDecl *VD = dyn_cast<VarDecl>(D);
if (!VD) {
Diag(D->getLocation(), diag::err_for_range_decl_must_be_var);
D->setInvalidDecl();
return;
}
VD->setCXXForRangeDecl(true);
// for-range-declaration cannot be given a storage class specifier.
int Error = -1;
switch (VD->getStorageClassAsWritten()) {
case SC_None:
break;
case SC_Extern:
Error = 0;
break;
case SC_Static:
Error = 1;
break;
case SC_PrivateExtern:
Error = 2;
break;
case SC_Auto:
Error = 3;
break;
case SC_Register:
Error = 4;
break;
}
// FIXME: constexpr isn't allowed here.
//if (DS.isConstexprSpecified())
// Error = 5;
if (Error != -1) {
Diag(VD->getOuterLocStart(), diag::err_for_range_storage_class)
<< VD->getDeclName() << Error;
D->setInvalidDecl();
}
}
void Sema::CheckCompleteVariableDeclaration(VarDecl *var) { void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
if (var->isInvalidDecl()) return; if (var->isInvalidDecl()) return;

View File

@ -2205,7 +2205,8 @@ void ADLResult::insert(NamedDecl *New) {
void Sema::ArgumentDependentLookup(DeclarationName Name, bool Operator, void Sema::ArgumentDependentLookup(DeclarationName Name, bool Operator,
Expr **Args, unsigned NumArgs, Expr **Args, unsigned NumArgs,
ADLResult &Result) { ADLResult &Result,
bool StdNamespaceIsAssociated) {
// Find all of the associated namespaces and classes based on the // Find all of the associated namespaces and classes based on the
// arguments we have. // arguments we have.
AssociatedNamespaceSet AssociatedNamespaces; AssociatedNamespaceSet AssociatedNamespaces;
@ -2213,6 +2214,8 @@ void Sema::ArgumentDependentLookup(DeclarationName Name, bool Operator,
FindAssociatedClassesAndNamespaces(Args, NumArgs, FindAssociatedClassesAndNamespaces(Args, NumArgs,
AssociatedNamespaces, AssociatedNamespaces,
AssociatedClasses); AssociatedClasses);
if (StdNamespaceIsAssociated && StdNamespace)
AssociatedNamespaces.insert(getStdNamespace());
QualType T1, T2; QualType T1, T2;
if (Operator) { if (Operator) {

View File

@ -6152,7 +6152,8 @@ Sema::AddArgumentDependentLookupCandidates(DeclarationName Name,
Expr **Args, unsigned NumArgs, Expr **Args, unsigned NumArgs,
TemplateArgumentListInfo *ExplicitTemplateArgs, TemplateArgumentListInfo *ExplicitTemplateArgs,
OverloadCandidateSet& CandidateSet, OverloadCandidateSet& CandidateSet,
bool PartialOverloading) { bool PartialOverloading,
bool StdNamespaceIsAssociated) {
ADLResult Fns; ADLResult Fns;
// FIXME: This approach for uniquing ADL results (and removing // FIXME: This approach for uniquing ADL results (and removing
@ -6163,7 +6164,8 @@ Sema::AddArgumentDependentLookupCandidates(DeclarationName Name,
// we supposed to consider on ADL candidates, anyway? // we supposed to consider on ADL candidates, anyway?
// FIXME: Pass in the explicit template arguments? // FIXME: Pass in the explicit template arguments?
ArgumentDependentLookup(Name, Operator, Args, NumArgs, Fns); ArgumentDependentLookup(Name, Operator, Args, NumArgs, Fns,
StdNamespaceIsAssociated);
// Erase all of the candidates we already knew about. // Erase all of the candidates we already knew about.
for (OverloadCandidateSet::iterator Cand = CandidateSet.begin(), for (OverloadCandidateSet::iterator Cand = CandidateSet.begin(),
@ -7693,7 +7695,8 @@ void Sema::AddOverloadedCallCandidates(UnresolvedLookupExpr *ULE,
Args, NumArgs, Args, NumArgs,
ExplicitTemplateArgs, ExplicitTemplateArgs,
CandidateSet, CandidateSet,
PartialOverloading); PartialOverloading,
ULE->isStdAssociatedNamespace());
} }
/// Attempts to recover from a call where no functions were found. /// Attempts to recover from a call where no functions were found.
@ -7772,7 +7775,9 @@ Sema::BuildOverloadedCallExpr(Scope *S, Expr *Fn, UnresolvedLookupExpr *ULE,
// We don't perform ADL in C. // We don't perform ADL in C.
assert(getLangOptions().CPlusPlus && "ADL enabled in C"); assert(getLangOptions().CPlusPlus && "ADL enabled in C");
} } else
assert(!ULE->isStdAssociatedNamespace() &&
"std is associated namespace but not doing ADL");
#endif #endif
OverloadCandidateSet CandidateSet(Fn->getExprLoc()); OverloadCandidateSet CandidateSet(Fn->getExprLoc());

View File

@ -15,6 +15,7 @@
#include "clang/Sema/Scope.h" #include "clang/Sema/Scope.h"
#include "clang/Sema/ScopeInfo.h" #include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/Initialization.h" #include "clang/Sema/Initialization.h"
#include "clang/Sema/Lookup.h"
#include "clang/AST/APValue.h" #include "clang/AST/APValue.h"
#include "clang/AST/ASTContext.h" #include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h" #include "clang/AST/DeclObjC.h"
@ -1013,6 +1014,387 @@ Sema::ActOnObjCForCollectionStmt(SourceLocation ForLoc,
ForLoc, RParenLoc)); ForLoc, RParenLoc));
} }
namespace {
enum BeginEndFunction {
BEF_begin,
BEF_end
};
/// Build a variable declaration for a for-range statement.
static VarDecl *BuildForRangeVarDecl(Sema &SemaRef, SourceLocation Loc,
QualType Type, const char *Name) {
DeclContext *DC = SemaRef.CurContext;
IdentifierInfo *II = &SemaRef.PP.getIdentifierTable().get(Name);
TypeSourceInfo *TInfo = SemaRef.Context.getTrivialTypeSourceInfo(Type, Loc);
VarDecl *Decl = VarDecl::Create(SemaRef.Context, DC, Loc, Loc, II, Type,
TInfo, SC_Auto, SC_None);
return Decl;
}
/// Finish building a variable declaration for a for-range statement.
/// \return true if an error occurs.
static bool FinishForRangeVarDecl(Sema &SemaRef, VarDecl *Decl, Expr *Init,
SourceLocation Loc, int diag) {
// Deduce the type for the iterator variable now rather than leaving it to
// AddInitializerToDecl, so we can produce a more suitable diagnostic.
TypeSourceInfo *InitTSI = 0;
if (Init->getType()->isVoidType() ||
!SemaRef.DeduceAutoType(Decl->getTypeSourceInfo(), Init, InitTSI))
SemaRef.Diag(Loc, diag) << Init->getType();
if (!InitTSI) {
Decl->setInvalidDecl();
return true;
}
Decl->setTypeSourceInfo(InitTSI);
Decl->setType(InitTSI->getType());
SemaRef.AddInitializerToDecl(Decl, Init, /*DirectInit=*/false,
/*TypeMayContainAuto=*/false);
SemaRef.FinalizeDeclaration(Decl);
return false;
}
/// Produce a note indicating which begin/end function was implicitly called
/// by a C++0x for-range statement. This is often not obvious from the code,
/// nor from the diagnostics produced when analysing the implicit expressions
/// required in a for-range statement.
void NoteForRangeBeginEndFunction(Sema &SemaRef, Expr *E,
BeginEndFunction BEF) {
CallExpr *CE = dyn_cast<CallExpr>(E);
if (!CE)
return;
FunctionDecl *D = dyn_cast<FunctionDecl>(CE->getCalleeDecl());
if (!D)
return;
SourceLocation Loc = D->getLocation();
std::string Description;
bool IsTemplate = false;
if (FunctionTemplateDecl *FunTmpl = D->getPrimaryTemplate()) {
Description = SemaRef.getTemplateArgumentBindingsText(
FunTmpl->getTemplateParameters(), *D->getTemplateSpecializationArgs());
IsTemplate = true;
}
SemaRef.Diag(Loc, diag::note_for_range_begin_end)
<< BEF << IsTemplate << Description << E->getType();
}
/// Build a call to 'begin' or 'end' for a C++0x for-range statement. If the
/// given LookupResult is non-empty, it is assumed to describe a member which
/// will be invoked. Otherwise, the function will be found via argument
/// dependent lookup.
static ExprResult BuildForRangeBeginEndCall(Sema &SemaRef, Scope *S,
SourceLocation Loc,
VarDecl *Decl,
BeginEndFunction BEF,
const DeclarationNameInfo &NameInfo,
LookupResult &MemberLookup,
Expr *Range) {
ExprResult CallExpr;
if (!MemberLookup.empty()) {
ExprResult MemberRef =
SemaRef.BuildMemberReferenceExpr(Range, Range->getType(), Loc,
/*IsPtr=*/false, CXXScopeSpec(),
/*Qualifier=*/0, MemberLookup,
/*TemplateArgs=*/0);
if (MemberRef.isInvalid())
return ExprError();
CallExpr = SemaRef.ActOnCallExpr(S, MemberRef.get(), Loc, MultiExprArg(),
Loc, 0);
if (CallExpr.isInvalid())
return ExprError();
} else {
UnresolvedSet<0> FoundNames;
// C++0x [stmt.ranged]p1: For the purposes of this name lookup, namespace
// std is an associated namespace.
UnresolvedLookupExpr *Fn =
UnresolvedLookupExpr::Create(SemaRef.Context, /*NamingClass=*/0,
NestedNameSpecifierLoc(), NameInfo,
/*NeedsADL=*/true, /*Overloaded=*/false,
FoundNames.begin(), FoundNames.end(),
/*LookInStdNamespace=*/true);
CallExpr = SemaRef.BuildOverloadedCallExpr(S, Fn, Fn, Loc, &Range, 1, Loc,
0);
if (CallExpr.isInvalid()) {
SemaRef.Diag(Range->getLocStart(), diag::note_for_range_type)
<< Range->getType();
return ExprError();
}
}
if (FinishForRangeVarDecl(SemaRef, Decl, CallExpr.get(), Loc,
diag::err_for_range_iter_deduction_failure)) {
NoteForRangeBeginEndFunction(SemaRef, CallExpr.get(), BEF);
return ExprError();
}
return CallExpr;
}
}
/// ActOnCXXForRangeStmt - Check and build a C++0x for-range statement.
///
/// C++0x [stmt.ranged]:
/// A range-based for statement is equivalent to
///
/// {
/// auto && __range = range-init;
/// for ( auto __begin = begin-expr,
/// __end = end-expr;
/// __begin != __end;
/// ++__begin ) {
/// for-range-declaration = *__begin;
/// statement
/// }
/// }
///
/// The body of the loop is not available yet, since it cannot be analysed until
/// we have determined the type of the for-range-declaration.
StmtResult
Sema::ActOnCXXForRangeStmt(SourceLocation ForLoc, SourceLocation LParenLoc,
Stmt *First, SourceLocation ColonLoc, Expr *Range,
SourceLocation RParenLoc) {
if (!First || !Range)
return StmtError();
DeclStmt *DS = dyn_cast<DeclStmt>(First);
assert(DS && "first part of for range not a decl stmt");
if (!DS->isSingleDecl()) {
Diag(DS->getStartLoc(), diag::err_type_defined_in_for_range);
return StmtError();
}
if (DS->getSingleDecl()->isInvalidDecl())
return StmtError();
if (DiagnoseUnexpandedParameterPack(Range, UPPC_Expression))
return StmtError();
// Build auto && __range = range-init
SourceLocation RangeLoc = Range->getLocStart();
VarDecl *RangeVar = BuildForRangeVarDecl(*this, RangeLoc,
Context.getAutoRRefDeductType(),
"__range");
if (FinishForRangeVarDecl(*this, RangeVar, Range, RangeLoc,
diag::err_for_range_deduction_failure))
return StmtError();
// Claim the type doesn't contain auto: we've already done the checking.
DeclGroupPtrTy RangeGroup =
BuildDeclaratorGroup((Decl**)&RangeVar, 1, /*TypeMayContainAuto=*/false);
StmtResult RangeDecl = ActOnDeclStmt(RangeGroup, RangeLoc, RangeLoc);
if (RangeDecl.isInvalid())
return StmtError();
return BuildCXXForRangeStmt(ForLoc, ColonLoc, RangeDecl.get(),
/*BeginEndDecl=*/0, /*Cond=*/0, /*Inc=*/0, DS,
RParenLoc);
}
/// BuildCXXForRangeStmt - Build or instantiate a C++0x for-range statement.
StmtResult
Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc,
Stmt *RangeDecl, Stmt *BeginEnd, Expr *Cond,
Expr *Inc, Stmt *LoopVarDecl,
SourceLocation RParenLoc) {
Scope *S = getCurScope();
DeclStmt *RangeDS = cast<DeclStmt>(RangeDecl);
VarDecl *RangeVar = cast<VarDecl>(RangeDS->getSingleDecl());
QualType RangeVarType = RangeVar->getType();
DeclStmt *LoopVarDS = cast<DeclStmt>(LoopVarDecl);
VarDecl *LoopVar = cast<VarDecl>(LoopVarDS->getSingleDecl());
StmtResult BeginEndDecl = BeginEnd;
ExprResult NotEqExpr = Cond, IncrExpr = Inc;
if (!BeginEndDecl.get() && !RangeVarType->isDependentType()) {
SourceLocation RangeLoc = RangeVar->getLocation();
ExprResult RangeRef = BuildDeclRefExpr(RangeVar,
RangeVarType.getNonReferenceType(),
VK_LValue, ColonLoc);
if (RangeRef.isInvalid())
return StmtError();
QualType AutoType = Context.getAutoDeductType();
Expr *Range = RangeVar->getInit();
if (!Range)
return StmtError();
QualType RangeType = Range->getType();
if (RequireCompleteType(RangeLoc, RangeType,
PDiag(diag::err_for_range_incomplete_type)))
return StmtError();
// Build auto __begin = begin-expr, __end = end-expr.
VarDecl *BeginVar = BuildForRangeVarDecl(*this, ColonLoc, AutoType,
"__begin");
VarDecl *EndVar = BuildForRangeVarDecl(*this, ColonLoc, AutoType,
"__end");
// Build begin-expr and end-expr and attach to __begin and __end variables.
ExprResult BeginExpr, EndExpr;
if (const ArrayType *UnqAT = RangeType->getAsArrayTypeUnsafe()) {
// - if _RangeT is an array type, begin-expr and end-expr are __range and
// __range + __bound, respectively, where __bound is the array bound. If
// _RangeT is an array of unknown size or an array of incomplete type,
// the program is ill-formed;
// begin-expr is __range.
BeginExpr = RangeRef;
if (FinishForRangeVarDecl(*this, BeginVar, RangeRef.get(), ColonLoc,
diag::err_for_range_iter_deduction_failure)) {
NoteForRangeBeginEndFunction(*this, BeginExpr.get(), BEF_begin);
return StmtError();
}
// Find the array bound.
ExprResult BoundExpr;
if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(UnqAT))
BoundExpr = Owned(IntegerLiteral::Create(Context, CAT->getSize(),
Context.IntTy, RangeLoc));
else if (const VariableArrayType *VAT =
dyn_cast<VariableArrayType>(UnqAT))
BoundExpr = VAT->getSizeExpr();
else {
// Can't be a DependentSizedArrayType or an IncompleteArrayType since
// UnqAT is not incomplete and Range is not type-dependent.
assert(0 && "Unexpected array type in for-range");
return StmtError();
}
// end-expr is __range + __bound.
EndExpr = ActOnBinOp(S, ColonLoc, tok::plus, RangeRef.get(),
BoundExpr.get());
if (EndExpr.isInvalid())
return StmtError();
if (FinishForRangeVarDecl(*this, EndVar, EndExpr.get(), ColonLoc,
diag::err_for_range_iter_deduction_failure)) {
NoteForRangeBeginEndFunction(*this, EndExpr.get(), BEF_end);
return StmtError();
}
} else {
DeclarationNameInfo BeginNameInfo(&PP.getIdentifierTable().get("begin"),
ColonLoc);
DeclarationNameInfo EndNameInfo(&PP.getIdentifierTable().get("end"),
ColonLoc);
LookupResult BeginMemberLookup(*this, BeginNameInfo, LookupMemberName);
LookupResult EndMemberLookup(*this, EndNameInfo, LookupMemberName);
if (CXXRecordDecl *D = RangeType->getAsCXXRecordDecl()) {
// - if _RangeT is a class type, the unqualified-ids begin and end are
// looked up in the scope of class _RangeT as if by class member access
// lookup (3.4.5), and if either (or both) finds at least one
// declaration, begin-expr and end-expr are __range.begin() and
// __range.end(), respectively;
LookupQualifiedName(BeginMemberLookup, D);
LookupQualifiedName(EndMemberLookup, D);
if (BeginMemberLookup.empty() != EndMemberLookup.empty()) {
Diag(ColonLoc, diag::err_for_range_member_begin_end_mismatch)
<< RangeType << BeginMemberLookup.empty();
return StmtError();
}
} else {
// - otherwise, begin-expr and end-expr are begin(__range) and
// end(__range), respectively, where begin and end are looked up with
// argument-dependent lookup (3.4.2). For the purposes of this name
// lookup, namespace std is an associated namespace.
}
BeginExpr = BuildForRangeBeginEndCall(*this, S, ColonLoc, BeginVar,
BEF_begin, BeginNameInfo,
BeginMemberLookup, RangeRef.get());
if (BeginExpr.isInvalid())
return StmtError();
EndExpr = BuildForRangeBeginEndCall(*this, S, ColonLoc, EndVar,
BEF_end, EndNameInfo,
EndMemberLookup, RangeRef.get());
if (EndExpr.isInvalid())
return StmtError();
}
// C++0x [decl.spec.auto]p6: BeginType and EndType must be the same.
QualType BeginType = BeginVar->getType(), EndType = EndVar->getType();
if (!Context.hasSameType(BeginType, EndType)) {
Diag(RangeLoc, diag::err_for_range_begin_end_types_differ)
<< BeginType << EndType;
NoteForRangeBeginEndFunction(*this, BeginExpr.get(), BEF_begin);
NoteForRangeBeginEndFunction(*this, EndExpr.get(), BEF_end);
}
Decl *BeginEndDecls[] = { BeginVar, EndVar };
// Claim the type doesn't contain auto: we've already done the checking.
DeclGroupPtrTy BeginEndGroup =
BuildDeclaratorGroup(BeginEndDecls, 2, /*TypeMayContainAuto=*/false);
BeginEndDecl = ActOnDeclStmt(BeginEndGroup, ColonLoc, ColonLoc);
ExprResult BeginRef = BuildDeclRefExpr(BeginVar,
BeginType.getNonReferenceType(),
VK_LValue, ColonLoc);
ExprResult EndRef = BuildDeclRefExpr(EndVar, EndType.getNonReferenceType(),
VK_LValue, ColonLoc);
// Build and check __begin != __end expression.
NotEqExpr = ActOnBinOp(S, ColonLoc, tok::exclaimequal,
BeginRef.get(), EndRef.get());
NotEqExpr = ActOnBooleanCondition(S, ColonLoc, NotEqExpr.get());
NotEqExpr = ActOnFinishFullExpr(NotEqExpr.get());
if (NotEqExpr.isInvalid()) {
NoteForRangeBeginEndFunction(*this, BeginExpr.get(), BEF_begin);
if (!Context.hasSameType(BeginType, EndType))
NoteForRangeBeginEndFunction(*this, EndExpr.get(), BEF_end);
return StmtError();
}
// Build and check ++__begin expression.
IncrExpr = ActOnUnaryOp(S, ColonLoc, tok::plusplus, BeginRef.get());
IncrExpr = ActOnFinishFullExpr(IncrExpr.get());
if (IncrExpr.isInvalid()) {
NoteForRangeBeginEndFunction(*this, BeginExpr.get(), BEF_begin);
return StmtError();
}
// Build and check *__begin expression.
ExprResult DerefExpr = ActOnUnaryOp(S, ColonLoc, tok::star, BeginRef.get());
if (DerefExpr.isInvalid()) {
NoteForRangeBeginEndFunction(*this, BeginExpr.get(), BEF_begin);
return StmtError();
}
// Attach *__begin as initializer for VD.
if (!LoopVar->isInvalidDecl()) {
AddInitializerToDecl(LoopVar, DerefExpr.get(), /*DirectInit=*/false,
/*TypeMayContainAuto=*/true);
if (LoopVar->isInvalidDecl())
NoteForRangeBeginEndFunction(*this, BeginExpr.get(), BEF_begin);
}
}
return Owned(new (Context) CXXForRangeStmt(RangeDS,
cast_or_null<DeclStmt>(BeginEndDecl.get()),
NotEqExpr.take(), IncrExpr.take(),
LoopVarDS, /*Body=*/0, ForLoc,
ColonLoc, RParenLoc));
}
/// FinishCXXForRangeStmt - Attach the body to a C++0x for-range statement.
/// This is a separate step from ActOnCXXForRangeStmt because analysis of the
/// body cannot be performed until after the type of the range variable is
/// determined.
StmtResult Sema::FinishCXXForRangeStmt(Stmt *S, Stmt *B) {
if (!S || !B)
return StmtError();
cast<CXXForRangeStmt>(S)->setBody(B);
return S;
}
StmtResult Sema::ActOnGotoStmt(SourceLocation GotoLoc, StmtResult Sema::ActOnGotoStmt(SourceLocation GotoLoc,
SourceLocation LabelLoc, SourceLocation LabelLoc,
LabelDecl *TheDecl) { LabelDecl *TheDecl) {

View File

@ -271,6 +271,7 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) {
D->getStorageClassAsWritten()); D->getStorageClassAsWritten());
Var->setThreadSpecified(D->isThreadSpecified()); Var->setThreadSpecified(D->isThreadSpecified());
Var->setCXXDirectInitializer(D->hasCXXDirectInitializer()); Var->setCXXDirectInitializer(D->hasCXXDirectInitializer());
Var->setCXXForRangeDecl(D->isCXXForRangeDecl());
// Substitute the nested name specifier, if any. // Substitute the nested name specifier, if any.
if (SubstQualifier(D, Var)) if (SubstQualifier(D, Var))
@ -350,7 +351,8 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) {
} }
SemaRef.PopExpressionEvaluationContext(); SemaRef.PopExpressionEvaluationContext();
} else if (!Var->isStaticDataMember() || Var->isOutOfLine()) } else if ((!Var->isStaticDataMember() || Var->isOutOfLine()) &&
!Var->isCXXForRangeDecl())
SemaRef.ActOnUninitializedDecl(Var, false); SemaRef.ActOnUninitializedDecl(Var, false);
// Diagnose unused local variables. // Diagnose unused local variables.

View File

@ -1228,6 +1228,28 @@ public:
return getSema().ActOnCXXTryBlock(TryLoc, TryBlock, move(Handlers)); return getSema().ActOnCXXTryBlock(TryLoc, TryBlock, move(Handlers));
} }
/// \brief Build a new C++0x range-based for statement.
///
/// By default, performs semantic analysis to build the new statement.
/// Subclasses may override this routine to provide different behavior.
StmtResult RebuildCXXForRangeStmt(SourceLocation ForLoc,
SourceLocation ColonLoc,
Stmt *Range, Stmt *BeginEnd,
Expr *Cond, Expr *Inc,
Stmt *LoopVar,
SourceLocation RParenLoc) {
return getSema().BuildCXXForRangeStmt(ForLoc, ColonLoc, Range, BeginEnd,
Cond, Inc, LoopVar, RParenLoc);
}
/// \brief Attach body to a C++0x range-based for statement.
///
/// By default, performs semantic analysis to finish the new statement.
/// Subclasses may override this routine to provide different behavior.
StmtResult FinishCXXForRangeStmt(Stmt *ForRange, Stmt *Body) {
return getSema().FinishCXXForRangeStmt(ForRange, Body);
}
/// \brief Build a new expression that references a declaration. /// \brief Build a new expression that references a declaration.
/// ///
/// By default, performs semantic analysis to build the new expression. /// By default, performs semantic analysis to build the new expression.
@ -5352,6 +5374,61 @@ TreeTransform<Derived>::TransformCXXTryStmt(CXXTryStmt *S) {
move_arg(Handlers)); move_arg(Handlers));
} }
template<typename Derived>
StmtResult
TreeTransform<Derived>::TransformCXXForRangeStmt(CXXForRangeStmt *S) {
StmtResult Range = getDerived().TransformStmt(S->getRangeStmt());
if (Range.isInvalid())
return StmtError();
StmtResult BeginEnd = getDerived().TransformStmt(S->getBeginEndStmt());
if (BeginEnd.isInvalid())
return StmtError();
ExprResult Cond = getDerived().TransformExpr(S->getCond());
if (Cond.isInvalid())
return StmtError();
ExprResult Inc = getDerived().TransformExpr(S->getInc());
if (Inc.isInvalid())
return StmtError();
StmtResult LoopVar = getDerived().TransformStmt(S->getLoopVarStmt());
if (LoopVar.isInvalid())
return StmtError();
StmtResult NewStmt = S;
if (getDerived().AlwaysRebuild() ||
Range.get() != S->getRangeStmt() ||
BeginEnd.get() != S->getBeginEndStmt() ||
Cond.get() != S->getCond() ||
Inc.get() != S->getInc() ||
LoopVar.get() != S->getLoopVarStmt())
NewStmt = getDerived().RebuildCXXForRangeStmt(S->getForLoc(),
S->getColonLoc(), Range.get(),
BeginEnd.get(), Cond.get(),
Inc.get(), LoopVar.get(),
S->getRParenLoc());
StmtResult Body = getDerived().TransformStmt(S->getBody());
if (Body.isInvalid())
return StmtError();
// Body has changed but we didn't rebuild the for-range statement. Rebuild
// it now so we have a new statement to attach the body to.
if (Body.get() != S->getBody() && NewStmt.get() == S)
NewStmt = getDerived().RebuildCXXForRangeStmt(S->getForLoc(),
S->getColonLoc(), Range.get(),
BeginEnd.get(), Cond.get(),
Inc.get(), LoopVar.get(),
S->getRParenLoc());
if (NewStmt.get() == S)
return SemaRef.Owned(S);
return FinishCXXForRangeStmt(NewStmt.get(), Body.get());
}
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
// Expression transformation // Expression transformation
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//

View File

@ -2676,6 +2676,11 @@ void ASTReader::InitializeContext(ASTContext &Ctx) {
if (SpecialTypes[SPECIAL_TYPE_INT128_INSTALLED]) if (SpecialTypes[SPECIAL_TYPE_INT128_INSTALLED])
Context->setInt128Installed(); Context->setInt128Installed();
if (unsigned AutoDeduct = SpecialTypes[SPECIAL_TYPE_AUTO_DEDUCT])
Context->AutoDeductTy = GetType(AutoDeduct);
if (unsigned AutoRRefDeduct = SpecialTypes[SPECIAL_TYPE_AUTO_RREF_DEDUCT])
Context->AutoRRefDeductTy = GetType(AutoRRefDeduct);
ReadPragmaDiagnosticMappings(Context->getDiagnostics()); ReadPragmaDiagnosticMappings(Context->getDiagnostics());
// If there were any CUDA special declarations, deserialize them. // If there were any CUDA special declarations, deserialize them.

View File

@ -684,6 +684,7 @@ void ASTDeclReader::VisitVarDecl(VarDecl *VD) {
VD->setCXXDirectInitializer(Record[Idx++]); VD->setCXXDirectInitializer(Record[Idx++]);
VD->setExceptionVariable(Record[Idx++]); VD->setExceptionVariable(Record[Idx++]);
VD->setNRVOVariable(Record[Idx++]); VD->setNRVOVariable(Record[Idx++]);
VD->setCXXForRangeDecl(Record[Idx++]);
if (Record[Idx++]) if (Record[Idx++])
VD->setInit(Reader.ReadExpr(F)); VD->setInit(Reader.ReadExpr(F));

View File

@ -141,6 +141,7 @@ namespace clang {
// C++ Statements // C++ Statements
void VisitCXXCatchStmt(CXXCatchStmt *S); void VisitCXXCatchStmt(CXXCatchStmt *S);
void VisitCXXTryStmt(CXXTryStmt *S); void VisitCXXTryStmt(CXXTryStmt *S);
void VisitCXXForRangeStmt(CXXForRangeStmt *);
void VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E); void VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E);
void VisitCXXConstructExpr(CXXConstructExpr *E); void VisitCXXConstructExpr(CXXConstructExpr *E);
@ -999,6 +1000,19 @@ void ASTStmtReader::VisitCXXTryStmt(CXXTryStmt *S) {
S->getStmts()[i + 1] = Reader.ReadSubStmt(); S->getStmts()[i + 1] = Reader.ReadSubStmt();
} }
void ASTStmtReader::VisitCXXForRangeStmt(CXXForRangeStmt *S) {
VisitStmt(S);
S->setForLoc(ReadSourceLocation(Record, Idx));
S->setColonLoc(ReadSourceLocation(Record, Idx));
S->setRParenLoc(ReadSourceLocation(Record, Idx));
S->setRangeStmt(Reader.ReadSubStmt());
S->setBeginEndStmt(Reader.ReadSubStmt());
S->setCond(Reader.ReadSubExpr());
S->setInc(Reader.ReadSubExpr());
S->setLoopVarStmt(Reader.ReadSubStmt());
S->setBody(Reader.ReadSubStmt());
}
void ASTStmtReader::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) { void ASTStmtReader::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) {
VisitCallExpr(E); VisitCallExpr(E);
E->setOperator((OverloadedOperatorKind)Record[Idx++]); E->setOperator((OverloadedOperatorKind)Record[Idx++]);
@ -1269,6 +1283,8 @@ void ASTStmtReader::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *E) {
void ASTStmtReader::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *E) { void ASTStmtReader::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *E) {
VisitOverloadExpr(E); VisitOverloadExpr(E);
E->RequiresADL = Record[Idx++]; E->RequiresADL = Record[Idx++];
if (E->RequiresADL)
E->StdIsAssociatedNamespace = Record[Idx++];
E->Overloaded = Record[Idx++]; E->Overloaded = Record[Idx++];
E->NamingClass = cast_or_null<CXXRecordDecl>(Reader.GetDecl(Record[Idx++])); E->NamingClass = cast_or_null<CXXRecordDecl>(Reader.GetDecl(Record[Idx++]));
} }
@ -1738,6 +1754,10 @@ Stmt *ASTReader::ReadStmtFromStream(PerFileData &F) {
/*NumHandlers=*/Record[ASTStmtReader::NumStmtFields]); /*NumHandlers=*/Record[ASTStmtReader::NumStmtFields]);
break; break;
case STMT_CXX_FOR_RANGE:
S = new (Context) CXXForRangeStmt(Empty);
break;
case EXPR_CXX_OPERATOR_CALL: case EXPR_CXX_OPERATOR_CALL:
S = new (Context) CXXOperatorCallExpr(*Context, Empty); S = new (Context) CXXOperatorCallExpr(*Context, Empty);
break; break;

View File

@ -2825,6 +2825,8 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, MemorizeStatCalls *StatCalls,
AddTypeRef(Context.ObjCSelRedefinitionType, Record); AddTypeRef(Context.ObjCSelRedefinitionType, Record);
AddTypeRef(Context.getRawNSConstantStringType(), Record); AddTypeRef(Context.getRawNSConstantStringType(), Record);
Record.push_back(Context.isInt128Installed()); Record.push_back(Context.isInt128Installed());
AddTypeRef(Context.AutoDeductTy, Record);
AddTypeRef(Context.AutoRRefDeductTy, Record);
Stream.EmitRecord(SPECIAL_TYPES, Record); Stream.EmitRecord(SPECIAL_TYPES, Record);
// Keep writing types and declarations until all types and // Keep writing types and declarations until all types and

View File

@ -553,6 +553,7 @@ void ASTDeclWriter::VisitVarDecl(VarDecl *D) {
Record.push_back(D->hasCXXDirectInitializer()); Record.push_back(D->hasCXXDirectInitializer());
Record.push_back(D->isExceptionVariable()); Record.push_back(D->isExceptionVariable());
Record.push_back(D->isNRVOVariable()); Record.push_back(D->isNRVOVariable());
Record.push_back(D->isCXXForRangeDecl());
Record.push_back(D->getInit() ? 1 : 0); Record.push_back(D->getInit() ? 1 : 0);
if (D->getInit()) if (D->getInit())
Writer.AddStmt(D->getInit()); Writer.AddStmt(D->getInit());
@ -1145,6 +1146,7 @@ void ASTWriter::WriteDeclsBlockAbbrevs() {
Abv->Add(BitCodeAbbrevOp(0)); // hasCXXDirectInitializer Abv->Add(BitCodeAbbrevOp(0)); // hasCXXDirectInitializer
Abv->Add(BitCodeAbbrevOp(0)); // isExceptionVariable Abv->Add(BitCodeAbbrevOp(0)); // isExceptionVariable
Abv->Add(BitCodeAbbrevOp(0)); // isNRVOVariable Abv->Add(BitCodeAbbrevOp(0)); // isNRVOVariable
Abv->Add(BitCodeAbbrevOp(0)); // isCXXForRangeDecl
Abv->Add(BitCodeAbbrevOp(0)); // HasInit Abv->Add(BitCodeAbbrevOp(0)); // HasInit
Abv->Add(BitCodeAbbrevOp(0)); // HasMemberSpecializationInfo Abv->Add(BitCodeAbbrevOp(0)); // HasMemberSpecializationInfo
// ParmVarDecl // ParmVarDecl

View File

@ -115,6 +115,7 @@ namespace clang {
// C++ Statements // C++ Statements
void VisitCXXCatchStmt(CXXCatchStmt *S); void VisitCXXCatchStmt(CXXCatchStmt *S);
void VisitCXXTryStmt(CXXTryStmt *S); void VisitCXXTryStmt(CXXTryStmt *S);
void VisitCXXForRangeStmt(CXXForRangeStmt *);
void VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E); void VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E);
void VisitCXXMemberCallExpr(CXXMemberCallExpr *E); void VisitCXXMemberCallExpr(CXXMemberCallExpr *E);
@ -963,6 +964,20 @@ void ASTStmtWriter::VisitCXXTryStmt(CXXTryStmt *S) {
Code = serialization::STMT_CXX_TRY; Code = serialization::STMT_CXX_TRY;
} }
void ASTStmtWriter::VisitCXXForRangeStmt(CXXForRangeStmt *S) {
VisitStmt(S);
Writer.AddSourceLocation(S->getForLoc(), Record);
Writer.AddSourceLocation(S->getColonLoc(), Record);
Writer.AddSourceLocation(S->getRParenLoc(), Record);
Writer.AddStmt(S->getRangeStmt());
Writer.AddStmt(S->getBeginEndStmt());
Writer.AddStmt(S->getCond());
Writer.AddStmt(S->getInc());
Writer.AddStmt(S->getLoopVarStmt());
Writer.AddStmt(S->getBody());
Code = serialization::STMT_CXX_FOR_RANGE;
}
void ASTStmtWriter::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) { void ASTStmtWriter::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) {
VisitCallExpr(E); VisitCallExpr(E);
Record.push_back(E->getOperator()); Record.push_back(E->getOperator());
@ -1267,6 +1282,8 @@ void ASTStmtWriter::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *E) {
void ASTStmtWriter::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *E) { void ASTStmtWriter::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *E) {
VisitOverloadExpr(E); VisitOverloadExpr(E);
Record.push_back(E->requiresADL()); Record.push_back(E->requiresADL());
if (E->requiresADL())
Record.push_back(E->isStdAssociatedNamespace());
Record.push_back(E->isOverloaded()); Record.push_back(E->isOverloaded());
Writer.AddDeclRef(E->getNamingClass(), Record); Writer.AddDeclRef(E->getNamingClass(), Record);
Code = serialization::EXPR_CXX_UNRESOLVED_LOOKUP; Code = serialization::EXPR_CXX_UNRESOLVED_LOOKUP;

View File

@ -423,6 +423,7 @@ void ExprEngine::Visit(const Stmt* S, ExplodedNode* Pred,
case Stmt::CXXBindTemporaryExprClass: case Stmt::CXXBindTemporaryExprClass:
case Stmt::CXXCatchStmtClass: case Stmt::CXXCatchStmtClass:
case Stmt::CXXDependentScopeMemberExprClass: case Stmt::CXXDependentScopeMemberExprClass:
case Stmt::CXXForRangeStmtClass:
case Stmt::CXXNullPtrLiteralExprClass: case Stmt::CXXNullPtrLiteralExprClass:
case Stmt::CXXPseudoDestructorExprClass: case Stmt::CXXPseudoDestructorExprClass:
case Stmt::CXXTemporaryObjectExprClass: case Stmt::CXXTemporaryObjectExprClass:

View File

@ -0,0 +1,68 @@
// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
void f() {
int b;
int arr[] = {1, 2, 3};
if (bool b = true) // expected-note 2{{previous definition}}
bool b; // expected-error {{redefinition}}
else
int b; // expected-error {{redefinition}}
while (bool b = true) // expected-note {{previous definition}}
int b; // expected-error {{redefinition}}
for (int c; // expected-note 2{{previous definition}}
bool c = true;) // expected-error {{redefinition}}
double c; // expected-error {{redefinition}}
switch (int n = 37 + 5) // expected-note {{previous definition}}
int n; // expected-error {{redefinition}}
for (int a : arr) // expected-note {{previous definition}}
int a = 0; // expected-error {{redefinition}}
if (bool b = true) { // expected-note 2{{previous definition}}
int b; // expected-error {{redefinition}}
} else {
int b; // expected-error {{redefinition}}
}
while (bool b = true) { // expected-note {{previous definition}}
int b; // expected-error {{redefinition}}
}
for (int c; // expected-note 2{{previous definition}}
bool c = true;) { // expected-error {{redefinition}}
double c; // expected-error {{redefinition}}
}
switch (int n = 37 + 5) { // expected-note {{previous definition}}
int n; // expected-error {{redefinition}}
}
for (int &a : arr) { // expected-note {{previous definition}}
int a = 0; // expected-error {{redefinition}}
}
if (bool b = true) {{ // expected-note {{previous definition}}
bool b;
}} else {
int b; // expected-error {{redefinition}}
}
if (bool b = true) { // expected-note {{previous definition}}
bool b; // expected-error {{redefinition}}
} else {{
int b;
}}
if (bool b = true) {{
bool b;
}} else {{
int b;
}}
while (bool b = true) {{
int b;
}}
for (int c; // expected-note {{previous definition}}
bool c = true; ) {{ // expected-error {{redefinition}}
double c;
}}
switch (int n = 37 + 5) {{
int n;
}}
for (int &a : arr) {{
int a = 0;
}}
}

View File

@ -0,0 +1,44 @@
// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
// FIXME: when clang supports alias-declarations.
#if 0
using X = struct { // ok
};
#endif
class K {
virtual ~K();
// FIXME: the diagnostic here isn't very good
operator struct S {} (); // expected-error 2{{}}
};
void f() {
int arr[3] = {1,2,3};
for (struct S { S(int) {} } s : arr) { // expected-error {{types may not be defined in a for range declaration}}
}
new struct T {}; // expected-error {{allocation of incomplete type}} expected-note {{forward declaration}}
// FIXME: the diagnostic here isn't very good
try {} catch (struct U {}); // expected-error 3{{}} expected-note 2{{}}
(void)(struct V { V(int); })0; // expected-error {{'V' can not be defined in a type specifier}}
(void)dynamic_cast<struct W {}*>((K*)0); // expected-error {{'W' can not be defined in a type specifier}}
(void)static_cast<struct X {}*>(0); // expected-error {{'X' can not be defined in a type specifier}}
(void)reinterpret_cast<struct Y {}*>(0); // expected-error {{'Y' can not be defined in a type specifier}}
(void)const_cast<struct Z {}*>((const Z*)0); // expected-error {{'Z' can not be defined in a type specifier}}
}
void g() throw (struct Ex {}) { // expected-error {{'Ex' can not be defined in a type specifier}}
}
// FIXME: this currently gives a strange error because alignas is not recognised as a keyword yet.
int alignas(struct Aa {}) x; // expected-error {{'Aa' can not be defined in a parameter type}} expected-error {{expected function body}}
int a = sizeof(struct So {}); // expected-error {{'So' can not be defined in a type specifier}}
int b = alignof(struct Ao {}); // expected-error {{'Ao' can not be defined in a type specifier}}
namespace std { struct type_info; }
const std::type_info &ti = typeid(struct Ti {}); // expected-error {{'Ti' can not be defined in a type specifier}}

View File

@ -0,0 +1,210 @@
// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
namespace std {
template<typename T>
auto begin(T &&t) -> decltype(t.begin()) { return t.begin(); } // expected-note 4{{ignored: substitution failure}}
template<typename T>
auto end(T &&t) -> decltype(t.end()) { return t.end(); } // expected-note {{candidate template ignored: substitution failure [with T = }}
template<typename T>
auto begin(T &&t) -> decltype(t.alt_begin()) { return t.alt_begin(); } // expected-note {{selected 'begin' template [with T = }} \
expected-note 4{{candidate template ignored: substitution failure [with T = }}
template<typename T>
auto end(T &&t) -> decltype(t.alt_end()) { return t.alt_end(); } // expected-note {{candidate template ignored: substitution failure [with T = }}
namespace inner {
// These should never be considered.
int begin(int);
int end(int);
}
using namespace inner;
}
struct A { // expected-note {{candidate constructor}}
A();
int *begin(); // expected-note 3{{selected 'begin' function with iterator type 'int *'}} expected-note {{'begin' declared here}}
int *end();
};
struct B {
B();
int *alt_begin();
int *alt_end();
};
void f(); // expected-note {{candidate}}
void f(int); // expected-note {{candidate}}
void g() {
for (int a : A())
A __begin;
for (char *a : A()) { // expected-error {{cannot initialize a variable of type 'char *' with an lvalue of type 'int'}}
}
for (char *a : B()) { // expected-error {{cannot initialize a variable of type 'char *' with an lvalue of type 'int'}}
}
// FIXME: Terrible diagnostic here. auto deduction should fail, but does not!
for (double a : f) { // expected-error {{address of overloaded function 'f' does not match required type '<overloaded function type>'}}
}
for (auto a : A()) {
}
for (auto a : B()) {
}
for (auto *a : A()) { // expected-error {{variable 'a' with type 'auto *' has incompatible initializer of type 'int'}}
}
// : is not a typo for :: here.
for (A NS:A()) { // expected-error {{no viable conversion from 'int' to 'A'}}
}
for (auto not_in_scope : not_in_scope) { // expected-error {{use of undeclared identifier 'not_in_scope'}}
}
for (auto a : A())
for (auto b : A()) {
__range.begin(); // expected-error {{use of undeclared identifier '__range'}}
++__begin; // expected-error {{use of undeclared identifier '__begin'}}
--__end; // expected-error {{use of undeclared identifier '__end'}}
}
for (char c : "test")
;
for (auto a : f()) // expected-error {{cannot use type 'void' as a range}}
;
extern int incomplete[];
for (auto a : incomplete) // expected-error {{cannot use incomplete type 'int []' as a range}}
;
extern struct Incomplete also_incomplete[2]; // expected-note {{forward declaration}}
for (auto &a : also_incomplete) // expected-error {{cannot use incomplete type 'struct Incomplete [2]' as a range}}
;
struct VoidBegin {
void begin(); // expected-note {{selected 'begin' function with iterator type 'void'}}
void end();
};
for (auto a : VoidBegin()) // expected-error {{cannot use type 'void' as an iterator}}
;
struct null_t {
operator int*();
};
struct Differ {
int *begin(); // expected-note {{selected 'begin' function with iterator type 'int *'}}
null_t end(); // expected-note {{selected 'end' function with iterator type 'null_t'}}
};
for (auto a : Differ()) // expected-error {{'begin' and 'end' must return the same type (got 'int *' and 'null_t')}}
;
for (void f() : "error") // expected-error {{for range declaration must declare a variable}}
;
for (extern int a : A()) {} // expected-error {{loop variable 'a' may not be declared 'extern'}}
for (static int a : A()) {} // expected-error {{loop variable 'a' may not be declared 'static'}}
for (register int a : A()) {} // expected-error {{loop variable 'a' may not be declared 'register'}}
// FIXME: when clang supports constexpr, this should be rejected.
for (constexpr int a : A()) {} // desired-error {{loop variable 'a' may not be declared 'constexpr'}}
struct NoBeginADL {
null_t alt_end();
};
struct NoEndADL {
null_t alt_begin();
};
for (auto u : NoBeginADL()) { // expected-error {{no matching function for call to 'begin'}} expected-note {{range has type 'NoBeginADL'}}
}
for (auto u : NoEndADL()) { // expected-error {{no matching function for call to 'end'}} expected-note {{range has type 'NoEndADL'}}
}
struct NoBegin {
null_t end();
};
struct NoEnd {
null_t begin();
};
for (auto u : NoBegin()) { // expected-error {{range type 'NoBegin' has 'end' member but no 'begin' member}}
}
for (auto u : NoEnd()) { // expected-error {{range type 'NoEnd' has 'begin' member but no 'end' member}}
}
struct NoIncr {
void *begin(); // expected-note {{selected 'begin' function with iterator type 'void *'}}
void *end();
};
for (auto u : NoIncr()) { // expected-error {{arithmetic on pointer to void type}}
}
struct NoNotEq {
NoNotEq begin(); // expected-note {{selected 'begin' function with iterator type 'NoNotEq'}}
NoNotEq end();
void operator++();
};
for (auto u : NoNotEq()) { // expected-error {{invalid operands to binary expression}}
}
struct NoCopy {
NoCopy();
NoCopy(const NoCopy &) = delete;
int *begin();
int *end();
};
for (int n : NoCopy()) { // ok
}
for (int n : 42) { // expected-error {{no matching function for call to 'begin'}} \
expected-note {{range has type 'int'}}
}
for (auto a : *also_incomplete) { // expected-error {{cannot use incomplete type 'struct Incomplete' as a range}}
}
}
template<typename T, typename U>
void h(T t) {
for (U u : t) { // expected-error {{no viable conversion from 'A' to 'int'}}
}
for (auto u : t) {
}
}
template void h<A, int>(A);
template void h<A(&)[4], A &>(A(&)[4]);
template void h<A(&)[13], A>(A(&)[13]);
template void h<A(&)[13], int>(A(&)[13]); // expected-note {{requested here}}
template<typename T>
void i(T t) {
for (auto u : t) { // expected-error {{no matching function for call to 'begin'}} \
expected-error {{member function 'begin' not viable}} \
expected-note {{range has type}}
}
}
template void i<A[13]>(A*); // expected-note {{requested here}}
template void i<const A>(const A); // expected-note {{requested here}}
namespace NS {
class ADL {};
int *begin(ADL); // expected-note {{no known conversion from 'NS::NoADL' to 'NS::ADL'}}
int *end(ADL);
class NoADL {};
}
int *begin(NS::NoADL);
int *end(NS::NoADL);
struct VoidBeginADL {};
void begin(VoidBeginADL); // expected-note {{selected 'begin' function with iterator type 'void'}}
void end(VoidBeginADL);
void j() {
for (auto u : NS::ADL()) {
}
for (auto u : NS::NoADL()) { // expected-error {{no matching function for call to 'begin'}} expected-note {{range has type}}
}
for (auto a : VoidBeginADL()) { // expected-error {{cannot use type 'void' as an iterator}}
}
}
void example() {
int array[5] = { 1, 2, 3, 4, 5 };
for (int &x : array)
x *= 2;
}

View File

@ -205,6 +205,8 @@ struct TestUnexpandedDecls : T{
Types t; // expected-error{{declaration type contains unexpanded parameter pack 'Types'}} Types t; // expected-error{{declaration type contains unexpanded parameter pack 'Types'}}
for (Types *t = 0; ; ) { } // expected-error{{declaration type contains unexpanded parameter pack 'Types'}} for (Types *t = 0; ; ) { } // expected-error{{declaration type contains unexpanded parameter pack 'Types'}}
for (; Types *t = 0; ) { } // expected-error{{declaration type contains unexpanded parameter pack 'Types'}} for (; Types *t = 0; ) { } // expected-error{{declaration type contains unexpanded parameter pack 'Types'}}
T a[] = { T(), T(), T() };
for (Types t : a) { } // expected-error{{declaration type contains unexpanded parameter pack 'Types'}}
switch(Types *t = 0) { } // expected-error{{declaration type contains unexpanded parameter pack 'Types'}} switch(Types *t = 0) { } // expected-error{{declaration type contains unexpanded parameter pack 'Types'}}
while(Types *t = 0) { } // expected-error{{declaration type contains unexpanded parameter pack 'Types'}} while(Types *t = 0) { } // expected-error{{declaration type contains unexpanded parameter pack 'Types'}}
if (Types *t = 0) { } // expected-error{{declaration type contains unexpanded parameter pack 'Types'}} if (Types *t = 0) { } // expected-error{{declaration type contains unexpanded parameter pack 'Types'}}
@ -341,6 +343,8 @@ void test_unexpanded_exprs(Types ...values) {
// SizeOfPackExpr is uninteresting // SizeOfPackExpr is uninteresting
// FIXME: Objective-C expressions will need to go elsewhere // FIXME: Objective-C expressions will need to go elsewhere
for (auto t : values) { } // expected-error{{expression contains unexpanded parameter pack 'values'}}
} }
// Test unexpanded parameter packs in partial specializations. // Test unexpanded parameter packs in partial specializations.

View File

@ -0,0 +1,131 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++0x -emit-llvm -o - -UDESUGAR %s | FileCheck %s
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++0x -emit-llvm -o - -DDESUGAR %s | FileCheck %s
struct A {
A();
A(const A &);
~A();
};
struct B {
B();
B(const B &);
~B();
};
struct C {
C(const B &);
C(const C &);
~C();
};
struct E;
struct D {
D(const C &);
D(const D &);
~D();
};
E begin(D);
E end(D);
struct F;
struct G;
struct H;
struct E {
E(const E &);
~E();
F operator*();
G operator++();
H operator!=(const E &o);
};
struct I;
struct F {
F(const F &);
~F();
operator I();
};
struct G {
G(const G &);
~G();
operator bool();
};
struct H {
H(const H &);
~H();
operator bool();
};
struct I {
I(const I &);
~I();
};
void body(const I &);
void for_temps() {
A a;
#ifdef DESUGAR
{
auto && __range = D(B());
for (auto __begin = begin(__range), __end = end(__range);
__begin != __end; ++__begin) {
I i = *__begin;
body(i);
}
}
#else
for (I i : D(B())) {
body(i);
}
#endif
}
// CHECK: define void @_Z9for_tempsv()
// CHECK: call void @_ZN1AC1Ev(
// CHECK: call void @_ZN1BC1Ev(
// CHECK: call void @_ZN1CC1ERK1B(
// CHECK: call void @_ZN1DC1ERK1C(
// CHECK: call void @_ZN1CD1Ev(
// CHECK: call void @_ZN1BD1Ev(
// CHECK: call void @_ZN1DC1ERKS_(
// CHECK: call void @_Z5begin1D(
// CHECK: call void @_ZN1DD1Ev(
// CHECK: call void @_ZN1DC1ERKS_(
// CHECK: call void @_Z3end1D(
// CHECK: call void @_ZN1DD1Ev(
// CHECK: br label %[[COND:.*]]
// CHECK: [[COND]]:
// CHECK: call void @_ZN1EneERKS_(
// CHECK: %[[CMP:.*]] = call zeroext i1 @_ZN1HcvbEv(
// CHECK: call void @_ZN1HD1Ev(
// CHECK: br i1 %[[CMP]], label %[[BODY:.*]], label %[[CLEANUP:.*]]
// CHECK: [[CLEANUP]]:
// CHECK: call void @_ZN1ED1Ev(
// CHECK: call void @_ZN1ED1Ev(
// In for-range:
// call void @_ZN1DD1Ev(
// CHECK: br label %[[END:.*]]
// CHECK: [[BODY]]:
// CHECK: call void @_ZN1EdeEv(
// CHECK: call void @_ZN1Fcv1IEv(
// CHECK: call void @_ZN1FD1Ev(
// CHECK: call void @_Z4bodyRK1I(
// CHECK: call void @_ZN1ID1Ev(
// CHECK: br label %[[INC:.*]]
// CHECK: [[INC]]:
// CHECK: call void @_ZN1EppEv(
// CHECK: call void @_ZN1GD1Ev(
// CHECK: br label %[[COND]]
// CHECK: [[END]]:
// In desugared version:
// call void @_ZN1DD1Ev(
// CHECK: call void @_ZN1AD1Ev(
// CHECK: ret void

View File

@ -0,0 +1,128 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++0x -emit-llvm -o - %s | FileCheck %s
struct A {
A();
A(const A&);
~A();
};
struct B {
B();
B(const B&);
~B();
};
struct C {
C();
C(const C&);
~C();
};
struct D {
D();
D(const D&);
~D();
B *begin();
B *end();
};
namespace std {
B *begin(C&);
B *end(C&);
}
extern B array[5];
// CHECK: define void @_Z9for_arrayv(
void for_array() {
// CHECK: call void @_ZN1AC1Ev(%struct.A* [[A:.*]])
A a;
for (B b : array) {
// CHECK-NOT: 5begin
// CHECK-NOT: 3end
// CHECK: getelementptr {{.*}}, i32 0
// CHECK: getelementptr {{.*}}, i64 5
// CHECK: br label %[[COND:.*]]
// CHECK: [[COND]]:
// CHECK: %[[CMP:.*]] = icmp ne
// CHECK: br i1 %[[CMP]], label %[[BODY:.*]], label %[[END:.*]]
// CHECK: [[BODY]]:
// CHECK: call void @_ZN1BC1ERKS_(
// CHECK: call void @_ZN1BD1Ev(
// CHECK: br label %[[INC:.*]]
// CHECK: [[INC]]:
// CHECK: getelementptr {{.*}} i32 1
// CHECK: br label %[[COND]]
}
// CHECK: [[END]]:
// CHECK: call void @_ZN1AD1Ev(%struct.A* [[A]])
// CHECK: ret void
}
// CHECK: define void @_Z9for_rangev(
void for_range() {
// CHECK: call void @_ZN1AC1Ev(%struct.A* [[A:.*]])
A a;
for (B b : C()) {
// CHECK: call void @_ZN1CC1Ev(
// CHECK: = call %struct.A* @_ZSt5beginR1C(
// CHECK: = call %struct.A* @_ZSt3endR1C(
// CHECK: br label %[[COND:.*]]
// CHECK: [[COND]]:
// CHECK: %[[CMP:.*]] = icmp ne
// CHECK: br i1 %[[CMP]], label %[[BODY:.*]], label %[[CLEANUP:.*]]
// CHECK: [[CLEANUP]]:
// CHECK: call void @_ZN1CD1Ev(
// CHECK: br label %[[END:.*]]
// CHECK: [[BODY]]:
// CHECK: call void @_ZN1BC1ERKS_(
// CHECK: call void @_ZN1BD1Ev(
// CHECK: br label %[[INC:.*]]
// CHECK: [[INC]]:
// CHECK: getelementptr {{.*}} i32 1
// CHECK: br label %[[COND]]
}
// CHECK: [[END]]:
// CHECK: call void @_ZN1AD1Ev(%struct.A* [[A]])
// CHECK: ret void
}
// CHECK: define void @_Z16for_member_rangev(
void for_member_range() {
// CHECK: call void @_ZN1AC1Ev(%struct.A* [[A:.*]])
A a;
for (B b : D()) {
// CHECK: call void @_ZN1DC1Ev(
// CHECK: = call %struct.A* @_ZN1D5beginEv(
// CHECK: = call %struct.A* @_ZN1D3endEv(
// CHECK: br label %[[COND:.*]]
// CHECK: [[COND]]:
// CHECK: %[[CMP:.*]] = icmp ne
// CHECK: br i1 %[[CMP]], label %[[BODY:.*]], label %[[CLEANUP:.*]]
// CHECK: [[CLEANUP]]:
// CHECK: call void @_ZN1DD1Ev(
// CHECK: br label %[[END:.*]]
// CHECK: [[BODY]]:
// CHECK: call void @_ZN1BC1ERKS_(
// CHECK: call void @_ZN1BD1Ev(
// CHECK: br label %[[INC:.*]]
// CHECK: [[INC]]:
// CHECK: getelementptr {{.*}} i32 1
// CHECK: br label %[[COND]]
}
// CHECK: [[END]]:
// CHECK: call void @_ZN1AD1Ev(%struct.A* [[A]])
// CHECK: ret void
}

View File

@ -0,0 +1,19 @@
// Test this without pch.
// RUN: %clang_cc1 -std=c++0x -include %S/cxx-for-range.h -fsyntax-only -emit-llvm -o - %s
// Test with pch.
// RUN: %clang_cc1 -std=c++0x -emit-pch -o %t %S/cxx-for-range.h
// RUN: %clang_cc1 -std=c++0x -include-pch %t -fsyntax-only -emit-llvm -o - %s
void h() {
f();
g<int>();
char a[3] = { 0, 1, 2 };
for (auto w : a)
for (auto x : S())
for (auto y : T())
for (auto z : U())
;
}

View File

@ -0,0 +1,35 @@
// Header for PCH test cxx-for-range.cpp
struct S {
int *begin();
int *end();
};
struct T { };
char *begin(T);
char *end(T);
struct U { };
namespace std {
char *begin(U);
char *end(U);
}
void f() {
char a[3] = { 0, 1, 2 };
for (auto w : a)
for (auto x : S())
for (auto y : T())
for (auto z : U())
;
}
template<typename A>
void g() {
A a[3] = { 0, 1, 2 };
for (auto &v : a)
for (auto x : S())
for (auto y : T())
for (auto z : U())
;
}

View File

@ -0,0 +1,150 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++0x
namespace value_range_detail {
template<typename T>
class value_range_iter {
T t;
public:
value_range_iter(const T &t) : t(t) {}
T operator*() const { return t; }
bool operator!=(const value_range_iter &o) const { return t != o.t; }
value_range_iter &operator++() { ++t; return *this; }
};
template<typename T>
struct value_range {
value_range(const T &a, const T &b) : begin_(a), end_(b) {}
value_range_iter<T> begin_, end_;
};
template<typename T>
value_range_iter<T> begin(const value_range<T> &r) { return r.begin_; }
template<typename T>
value_range_iter<T> end(const value_range<T> &r) { return r.end_; }
struct end_t {};
template<typename T>
class value_range_step_iter {
T it, step;
public:
value_range_step_iter(const T &it, const T &step) : it(it), step(step) {}
T operator*() const { return it; }
bool operator!=(value_range_step_iter end) const { return it != end.it; }
value_range_step_iter &operator++() { it += step; return *this; }
};
template<typename T>
class value_range_step {
T it, step, end_;
public:
value_range_step(const T &it, const T &end, const T &step) :
it(it), end_(end), step(step) {}
typedef value_range_step_iter<T> iterator;
iterator begin() const { return iterator(it, step); }
iterator end() const { return iterator(end_, step); }
};
}
template<typename T>
value_range_detail::value_range<T> range(const T &a, const T &b) { return value_range_detail::value_range<T>(a, b); }
template<typename T>
value_range_detail::value_range_step<T> range(const T &a, const T &b, const T &step) { return value_range_detail::value_range_step<T>(a, b, step); }
namespace map_range {
template<typename T>
class vector {
T storage[100];
decltype(sizeof(char)) size;
public:
vector() : size() {}
void push_back(T t) { storage[size++] = t; }
T *begin() { return storage; }
T *end() { return storage + size; }
};
template<typename T> struct tuple_elem {
T t;
tuple_elem() {}
tuple_elem(T t) : t(t) {}
};
template<typename... A>
struct tuple : tuple_elem<A>... {
tuple() : tuple_elem<A>()... {}
tuple(A... a) : tuple_elem<A>(a)... {}
template<typename B> B &get() { return tuple_elem<B>::t; }
};
template<typename F, typename I>
class map_iter {
F f;
I i;
public:
map_iter(F f, I i) : f(f), i(i) {}
auto operator*() const -> decltype(f(*i)) { return f(*i); }
bool operator!=(const map_iter &o) const { return i != o.i; }
map_iter &operator++() { ++i; return *this; }
};
template<typename T>
struct iter_pair {
T begin_, end_;
iter_pair(T begin, T end) : begin_(begin), end_(end) {}
};
template<typename T> T begin(iter_pair<T> p) { return p.begin_; }
template<typename T> T end(iter_pair<T> p) { return p.end_; }
template<typename...> class mem_fun_impl;
template<typename R, typename T, typename... A>
class mem_fun_impl<R (T::*)(A...)> {
typedef R (T::*F)(A...);
F f;
public:
mem_fun_impl(F f) : f(f) {}
R operator()(T &t, A &&...a) const { return (t.*f)(static_cast<A&&>(a)...); }
};
template<typename F> mem_fun_impl<F> mem_fun(F f) { return mem_fun_impl<F>(f); }
template<typename F, typename T>
auto map(const F &f, T &t) -> iter_pair<map_iter<F, decltype(t.begin())>> {
typedef map_iter<F, decltype(t.begin())> iter;
return iter_pair<iter>(iter(f, t.begin()), iter(f, t.end()));
}
}
#define assert(b) if (!b) { return 1; }
int main() {
int total = 0;
for (auto n : range(1, 5)) {
total += n;
}
assert(total == 10);
for (auto n : range(10, 100, 10)) {
total += n;
}
assert(total == 460);
map_range::vector<char> chars;
chars.push_back('a');
chars.push_back('b');
chars.push_back('c');
for (char c : chars) {
++total;
}
assert(total == 463);
typedef map_range::tuple<int, double> T;
map_range::vector<T> pairs;
pairs.push_back(T(42, 12.9));
pairs.push_back(T(6, 4.2));
pairs.push_back(T(9, 1.1));
for (auto a : map(map_range::mem_fun(&T::get<int>), pairs)) {
total += a;
}
assert(total == 500);
}

View File

@ -0,0 +1,37 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++0x
struct S {
int *begin();
int *end();
};
struct T {
};
struct Range {};
int begin(Range); // expected-note {{not viable}}
int end(Range);
namespace NS {
struct ADL {};
struct iter {
int operator*();
bool operator!=(iter);
void operator++();
};
iter begin(ADL); // expected-note {{not viable}}
iter end(ADL);
struct NoADL {};
}
NS::iter begin(NS::NoADL); // expected-note {{not viable}}
NS::iter end(NS::NoADL);
void f() {
int a[] = {1, 2, 3};
for (auto b : S()) {} // ok
for (auto b : T()) {} // expected-error {{no matching function for call to 'begin'}} expected-note {{range has type}}
for (auto b : a) {} // ok
for (int b : NS::ADL()) {} // ok
for (int b : NS::NoADL()) {} // expected-error {{no matching function for call to 'begin'}} expected-note {{range has type}}
}

View File

@ -95,6 +95,7 @@ CXCursor cxcursor::MakeCXCursor(Stmt *S, Decl *Parent,
case Stmt::ObjCForCollectionStmtClass: case Stmt::ObjCForCollectionStmtClass:
case Stmt::CXXCatchStmtClass: case Stmt::CXXCatchStmtClass:
case Stmt::CXXTryStmtClass: case Stmt::CXXTryStmtClass:
case Stmt::CXXForRangeStmtClass:
K = CXCursor_UnexposedStmt; K = CXCursor_UnexposedStmt;
break; break;