forked from OSchip/llvm-project
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:
parent
55858499e2
commit
02e85f3bc5
|
@ -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;
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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; }
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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, { })
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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">;
|
||||||
|
|
|
@ -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>;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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 *
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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";
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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));
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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;
|
||||||
|
}}
|
||||||
|
}
|
|
@ -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}}
|
|
@ -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;
|
||||||
|
}
|
|
@ -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.
|
||||||
|
|
|
@ -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
|
|
@ -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
|
||||||
|
}
|
|
@ -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())
|
||||||
|
;
|
||||||
|
}
|
|
@ -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())
|
||||||
|
;
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
|
@ -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}}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue