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 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,
|
||||
IdentifierTable &idents, SelectorTable &sels,
|
||||
Builtin::Context &builtins,
|
||||
|
@ -745,6 +749,12 @@ public:
|
|||
/// getAutoType - C++0x deduced auto type.
|
||||
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
|
||||
/// specified TagDecl (struct/union/class/enum) decl.
|
||||
QualType getTagDeclType(const TagDecl *Decl) const;
|
||||
|
|
|
@ -696,6 +696,10 @@ private:
|
|||
/// slot of its function, enabling the named return value optimization (NRVO).
|
||||
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 ASTDeclReader;
|
||||
|
||||
|
@ -706,7 +710,7 @@ protected:
|
|||
StorageClass SCAsWritten)
|
||||
: DeclaratorDecl(DK, DC, IdLoc, Id, T, TInfo, StartLoc), Init(),
|
||||
ThreadSpecified(false), HasCXXDirectInit(false),
|
||||
ExceptionVar(false), NRVOVariable(false) {
|
||||
ExceptionVar(false), NRVOVariable(false), CXXForRangeDecl(false) {
|
||||
SClass = SC;
|
||||
SClassAsWritten = SCAsWritten;
|
||||
}
|
||||
|
@ -1051,6 +1055,11 @@ public:
|
|||
/// NRVO candidate.
|
||||
bool isNRVOVariable() const { return NRVOVariable; }
|
||||
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
|
||||
/// class template specialization, returns the templated static data member
|
||||
|
|
|
@ -1738,6 +1738,10 @@ class UnresolvedLookupExpr : public OverloadExpr {
|
|||
/// call.
|
||||
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
|
||||
/// trivially rederivable if we urgently need to kill this field.
|
||||
bool Overloaded;
|
||||
|
@ -1755,15 +1759,19 @@ class UnresolvedLookupExpr : public OverloadExpr {
|
|||
const DeclarationNameInfo &NameInfo,
|
||||
bool RequiresADL, bool Overloaded,
|
||||
const TemplateArgumentListInfo *TemplateArgs,
|
||||
UnresolvedSetIterator Begin, UnresolvedSetIterator End)
|
||||
UnresolvedSetIterator Begin, UnresolvedSetIterator End,
|
||||
bool StdIsAssociatedNamespace)
|
||||
: OverloadExpr(UnresolvedLookupExprClass, C, QualifierLoc, NameInfo,
|
||||
TemplateArgs, Begin, End),
|
||||
RequiresADL(RequiresADL), Overloaded(Overloaded), NamingClass(NamingClass)
|
||||
RequiresADL(RequiresADL),
|
||||
StdIsAssociatedNamespace(StdIsAssociatedNamespace),
|
||||
Overloaded(Overloaded), NamingClass(NamingClass)
|
||||
{}
|
||||
|
||||
UnresolvedLookupExpr(EmptyShell Empty)
|
||||
: OverloadExpr(UnresolvedLookupExprClass, Empty),
|
||||
RequiresADL(false), Overloaded(false), NamingClass(0)
|
||||
RequiresADL(false), StdIsAssociatedNamespace(false), Overloaded(false),
|
||||
NamingClass(0)
|
||||
{}
|
||||
|
||||
friend class ASTStmtReader;
|
||||
|
@ -1775,9 +1783,13 @@ public:
|
|||
const DeclarationNameInfo &NameInfo,
|
||||
bool ADL, bool Overloaded,
|
||||
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,
|
||||
ADL, Overloaded, 0, Begin, End);
|
||||
ADL, Overloaded, 0, Begin, End,
|
||||
StdIsAssociatedNamespace);
|
||||
}
|
||||
|
||||
static UnresolvedLookupExpr *Create(ASTContext &C,
|
||||
|
@ -1797,6 +1809,10 @@ public:
|
|||
/// argument-dependent lookup.
|
||||
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.
|
||||
bool isOverloaded() const { return Overloaded; }
|
||||
|
||||
|
|
|
@ -39,6 +39,7 @@ struct PrintingPolicy {
|
|||
PrintingPolicy(const LangOptions &LO)
|
||||
: Indentation(2), LangOpts(LO), SuppressSpecifiers(false),
|
||||
SuppressTagKeyword(false), SuppressTag(false), SuppressScope(false),
|
||||
SuppressInitializers(false),
|
||||
Dump(false), ConstantArraySizeAsWritten(false),
|
||||
AnonymousTagLocations(true) { }
|
||||
|
||||
|
@ -87,6 +88,19 @@ struct PrintingPolicy {
|
|||
/// \brief Suppresses printing of scope specifiers.
|
||||
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",
|
||||
/// where dumping involves printing the internal details of the AST
|
||||
/// and pretty-printing involves printing something similar to
|
||||
|
|
|
@ -1696,6 +1696,7 @@ DEF_TRAVERSE_STMT(ObjCAtSynchronizedStmt, { })
|
|||
DEF_TRAVERSE_STMT(ObjCAtThrowStmt, { })
|
||||
DEF_TRAVERSE_STMT(ObjCAtTryStmt, { })
|
||||
DEF_TRAVERSE_STMT(ObjCForCollectionStmt, { })
|
||||
DEF_TRAVERSE_STMT(CXXForRangeStmt, { })
|
||||
DEF_TRAVERSE_STMT(ReturnStmt, { })
|
||||
DEF_TRAVERSE_STMT(SwitchStmt, { })
|
||||
DEF_TRAVERSE_STMT(WhileStmt, { })
|
||||
|
|
|
@ -119,6 +119,88 @@ public:
|
|||
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
|
||||
|
||||
|
|
|
@ -82,6 +82,7 @@ public:
|
|||
DISPATCH_CASE(ConditionalOperator)
|
||||
DISPATCH_CASE(BinaryConditionalOperator)
|
||||
DISPATCH_CASE(ObjCForCollectionStmt)
|
||||
DISPATCH_CASE(CXXForRangeStmt)
|
||||
|
||||
case Stmt::BinaryOperatorClass: {
|
||||
BinaryOperator* B = cast<BinaryOperator>(S);
|
||||
|
@ -109,6 +110,10 @@ public:
|
|||
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) {
|
||||
return static_cast<ImplClass*>(this)->BlockStmt_VisitExpr(E);
|
||||
}
|
||||
|
|
|
@ -995,6 +995,28 @@ def err_delegation_unimplemented : Error<
|
|||
"delegating constructors are not fully implemented">;
|
||||
def err_delegating_initializer_alone : Error<
|
||||
"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++
|
||||
def err_objc_decls_may_only_appear_in_global_scope : Error<
|
||||
|
|
|
@ -41,6 +41,7 @@ def ObjCForCollectionStmt : Stmt;
|
|||
// C++ statments
|
||||
def CXXCatchStmt : Stmt;
|
||||
def CXXTryStmt : Stmt;
|
||||
def CXXForRangeStmt : Stmt;
|
||||
|
||||
// Expressions
|
||||
def Expr : Stmt<1>;
|
||||
|
|
|
@ -1288,6 +1288,15 @@ private:
|
|||
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,
|
||||
unsigned Context, SourceLocation &DeclEnd,
|
||||
ParsedAttributesWithRange &attrs);
|
||||
|
@ -1295,12 +1304,17 @@ private:
|
|||
unsigned Context,
|
||||
SourceLocation &DeclEnd,
|
||||
ParsedAttributes &attrs,
|
||||
bool RequireSemi);
|
||||
bool RequireSemi,
|
||||
ForRangeInit *FRI = 0);
|
||||
DeclGroupPtrTy ParseDeclGroup(ParsingDeclSpec &DS, unsigned Context,
|
||||
bool AllowFunctionDefinitions,
|
||||
SourceLocation *DeclEnd = 0);
|
||||
SourceLocation *DeclEnd = 0,
|
||||
ForRangeInit *FRI = 0);
|
||||
Decl *ParseDeclarationAfterDeclarator(Declarator &D,
|
||||
const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo());
|
||||
bool ParseAttributesAfterDeclarator(Declarator &D);
|
||||
Decl *ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D,
|
||||
const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo());
|
||||
Decl *ParseFunctionStatementBody(Decl *Decl, ParseScope &BodyScope);
|
||||
Decl *ParseFunctionTryBlock(Decl *Decl, ParseScope &BodyScope);
|
||||
|
||||
|
|
|
@ -864,6 +864,7 @@ public:
|
|||
bool TypeMayContainAuto);
|
||||
void ActOnUninitializedDecl(Decl *dcl, bool TypeMayContainAuto);
|
||||
void ActOnInitializerError(Decl *Dcl);
|
||||
void ActOnCXXForRangeDecl(Decl *D);
|
||||
void SetDeclDeleted(Decl *dcl, SourceLocation DelLoc);
|
||||
void FinalizeDeclaration(Decl *D);
|
||||
DeclGroupPtrTy FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS,
|
||||
|
@ -1268,7 +1269,8 @@ public:
|
|||
Expr **Args, unsigned NumArgs,
|
||||
TemplateArgumentListInfo *ExplicitTemplateArgs,
|
||||
OverloadCandidateSet& CandidateSet,
|
||||
bool PartialOverloading = false);
|
||||
bool PartialOverloading = false,
|
||||
bool StdNamespaceIsAssociated = false);
|
||||
|
||||
// Emit as a 'note' the specific overload candidate
|
||||
void NoteOverloadCandidate(FunctionDecl *Fn);
|
||||
|
@ -1473,7 +1475,8 @@ public:
|
|||
|
||||
void ArgumentDependentLookup(DeclarationName Name, bool Operator,
|
||||
Expr **Args, unsigned NumArgs,
|
||||
ADLResult &Functions);
|
||||
ADLResult &Functions,
|
||||
bool StdNamespaceIsAssociated = false);
|
||||
|
||||
void LookupVisibleDecls(Scope *S, LookupNameKind Kind,
|
||||
VisibleDeclConsumer &Consumer,
|
||||
|
@ -1804,6 +1807,17 @@ public:
|
|||
SourceLocation LParenLoc,
|
||||
Stmt *First, Expr *Second,
|
||||
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,
|
||||
SourceLocation LabelLoc,
|
||||
|
|
|
@ -624,7 +624,11 @@ namespace clang {
|
|||
/// \brief NSConstantString type
|
||||
SPECIAL_TYPE_NS_CONSTANT_STRING = 15,
|
||||
/// \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.
|
||||
|
@ -915,6 +919,8 @@ namespace clang {
|
|||
STMT_CXX_CATCH,
|
||||
/// \brief A CXXTryStmt record.
|
||||
STMT_CXX_TRY,
|
||||
/// \brief A CXXForRangeStmt record.
|
||||
STMT_CXX_FOR_RANGE,
|
||||
|
||||
/// \brief A CXXOperatorCallExpr record.
|
||||
EXPR_CXX_OPERATOR_CALL,
|
||||
|
|
|
@ -2754,6 +2754,22 @@ QualType ASTContext::getAutoType(QualType DeducedType) const {
|
|||
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
|
||||
/// specified TagDecl (struct/union/class/enum) decl.
|
||||
QualType ASTContext::getTagDeclType(const TagDecl *Decl) const {
|
||||
|
|
|
@ -567,7 +567,8 @@ void DeclPrinter::VisitVarDecl(VarDecl *D) {
|
|||
T = Parm->getOriginalType();
|
||||
T.getAsStringInternal(Name, Policy);
|
||||
Out << Name;
|
||||
if (Expr *Init = D->getInit()) {
|
||||
Expr *Init = D->getInit();
|
||||
if (!Policy.SuppressInitializers && Init) {
|
||||
if (D->hasCXXDirectInitializer())
|
||||
Out << "(";
|
||||
else {
|
||||
|
|
|
@ -189,7 +189,7 @@ UnresolvedLookupExpr::Create(ASTContext &C,
|
|||
ExplicitTemplateArgumentList::sizeFor(Args));
|
||||
return new (Mem) UnresolvedLookupExpr(C, NamingClass, QualifierLoc, NameInfo,
|
||||
ADL, /*Overload*/ true, &Args,
|
||||
Begin, End);
|
||||
Begin, End, /*StdIsAssociated=*/false);
|
||||
}
|
||||
|
||||
UnresolvedLookupExpr *
|
||||
|
|
|
@ -540,6 +540,40 @@ CXXTryStmt::CXXTryStmt(SourceLocation tryLoc, Stmt *tryBlock,
|
|||
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,
|
||||
Stmt *then, SourceLocation EL, Stmt *elsev)
|
||||
: 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) {
|
||||
Indent() << "goto " << Node->getLabel()->getName() << ";\n";
|
||||
}
|
||||
|
|
|
@ -177,6 +177,10 @@ void StmtProfiler::VisitCXXTryStmt(CXXTryStmt *S) {
|
|||
VisitStmt(S);
|
||||
}
|
||||
|
||||
void StmtProfiler::VisitCXXForRangeStmt(CXXForRangeStmt *S) {
|
||||
VisitStmt(S);
|
||||
}
|
||||
|
||||
void StmtProfiler::VisitObjCForCollectionStmt(ObjCForCollectionStmt *S) {
|
||||
VisitStmt(S);
|
||||
}
|
||||
|
|
|
@ -312,6 +312,7 @@ private:
|
|||
AddStmtChoice asc);
|
||||
CFGBlock *VisitCXXThrowExpr(CXXThrowExpr *T);
|
||||
CFGBlock *VisitCXXTryStmt(CXXTryStmt *S);
|
||||
CFGBlock *VisitCXXForRangeStmt(CXXForRangeStmt *S);
|
||||
CFGBlock *VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E,
|
||||
AddStmtChoice asc);
|
||||
CFGBlock *VisitCXXConstructExpr(CXXConstructExpr *C, AddStmtChoice asc);
|
||||
|
@ -911,6 +912,9 @@ tryAgain:
|
|||
case Stmt::CXXTryStmtClass:
|
||||
return VisitCXXTryStmt(cast<CXXTryStmt>(S));
|
||||
|
||||
case Stmt::CXXForRangeStmtClass:
|
||||
return VisitCXXForRangeStmt(cast<CXXForRangeStmt>(S));
|
||||
|
||||
case Stmt::DeclStmtClass:
|
||||
return VisitDeclStmt(cast<DeclStmt>(S));
|
||||
|
||||
|
@ -2513,6 +2517,122 @@ CFGBlock* CFGBuilder::VisitCXXCatchStmt(CXXCatchStmt* CS) {
|
|||
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,
|
||||
AddStmtChoice asc) {
|
||||
if (BuildOpts.AddImplicitDtors) {
|
||||
|
|
|
@ -153,6 +153,9 @@ void CodeGenFunction::EmitStmt(const Stmt *S) {
|
|||
case Stmt::CXXTryStmtClass:
|
||||
EmitCXXTryStmt(cast<CXXTryStmt>(*S));
|
||||
break;
|
||||
case Stmt::CXXForRangeStmtClass:
|
||||
EmitCXXForRangeStmt(cast<CXXForRangeStmt>(*S));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -636,6 +639,80 @@ void CodeGenFunction::EmitForStmt(const ForStmt &S) {
|
|||
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) {
|
||||
if (RV.isScalar()) {
|
||||
Builder.CreateStore(RV.getScalarVal(), ReturnValue);
|
||||
|
|
|
@ -42,6 +42,7 @@ namespace clang {
|
|||
class APValue;
|
||||
class ASTContext;
|
||||
class CXXDestructorDecl;
|
||||
class CXXForRangeStmt;
|
||||
class CXXTryStmt;
|
||||
class Decl;
|
||||
class LabelDecl;
|
||||
|
@ -1694,6 +1695,7 @@ public:
|
|||
void ExitCXXTryStmt(const CXXTryStmt &S, bool IsFnTryBlock = false);
|
||||
|
||||
void EmitCXXTryStmt(const CXXTryStmt &S);
|
||||
void EmitCXXForRangeStmt(const CXXForRangeStmt &S);
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// LValue Expression Emission
|
||||
|
|
|
@ -705,13 +705,21 @@ Parser::DeclGroupPtrTy Parser::ParseDeclaration(StmtVector &Stmts,
|
|||
///[C90/C++]init-declarator-list ';' [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
|
||||
/// 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,
|
||||
unsigned Context,
|
||||
SourceLocation &DeclEnd,
|
||||
ParsedAttributes &attrs,
|
||||
bool RequireSemi) {
|
||||
bool RequireSemi,
|
||||
ForRangeInit *FRI) {
|
||||
// Parse the common declaration-specifiers piece.
|
||||
ParsingDeclSpec DS(*this);
|
||||
DS.takeAttributesFrom(attrs);
|
||||
|
@ -731,7 +739,7 @@ Parser::DeclGroupPtrTy Parser::ParseSimpleDeclaration(StmtVector &Stmts,
|
|||
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
|
||||
|
@ -740,7 +748,8 @@ Parser::DeclGroupPtrTy Parser::ParseSimpleDeclaration(StmtVector &Stmts,
|
|||
Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
|
||||
unsigned Context,
|
||||
bool AllowFunctionDefinitions,
|
||||
SourceLocation *DeclEnd) {
|
||||
SourceLocation *DeclEnd,
|
||||
ForRangeInit *FRI) {
|
||||
// Parse the first declarator.
|
||||
ParsingDeclarator D(*this, DS, static_cast<Declarator::TheContext>(Context));
|
||||
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;
|
||||
Decl *FirstDecl = ParseDeclarationAfterDeclarator(D);
|
||||
Decl *FirstDecl = ParseDeclarationAfterDeclaratorAndAttributes(D);
|
||||
D.complete(FirstDecl);
|
||||
if (FirstDecl)
|
||||
DeclsInGroup.push_back(FirstDecl);
|
||||
|
@ -841,6 +866,26 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
|
|||
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
|
||||
/// declarator'. This method parses the remainder of the declaration
|
||||
/// (including any attributes or initializer, among other things) and
|
||||
|
@ -864,21 +909,14 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
|
|||
///
|
||||
Decl *Parser::ParseDeclarationAfterDeclarator(Declarator &D,
|
||||
const ParsedTemplateInfo &TemplateInfo) {
|
||||
// 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 0;
|
||||
}
|
||||
if (ParseAttributesAfterDeclarator(D))
|
||||
return 0;
|
||||
|
||||
D.setAsmLabel(AsmLabel.release());
|
||||
D.SetRangeEnd(Loc);
|
||||
}
|
||||
|
||||
MaybeParseGNUAttributes(D);
|
||||
return ParseDeclarationAfterDeclaratorAndAttributes(D, TemplateInfo);
|
||||
}
|
||||
|
||||
Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D,
|
||||
const ParsedTemplateInfo &TemplateInfo) {
|
||||
// Inform the current actions module that we just parsed this declarator.
|
||||
Decl *ThisDecl = 0;
|
||||
switch (TemplateInfo.Kind) {
|
||||
|
|
|
@ -977,6 +977,7 @@ StmtResult Parser::ParseDoStatement(ParsedAttributes &attrs) {
|
|||
/// 'for' '(' declaration expr[opt] ';' expr[opt] ')' statement
|
||||
/// [C++] 'for' '(' for-init-statement condition[opt] ';' expression[opt] ')'
|
||||
/// [C++] statement
|
||||
/// [C++0x] 'for' '(' for-range-declaration : for-range-initializer ) statement
|
||||
/// [OBJC2] 'for' '(' declaration 'in' expr ')' statement
|
||||
/// [OBJC2] 'for' '(' expr 'in' expr ')' statement
|
||||
///
|
||||
|
@ -984,6 +985,11 @@ StmtResult Parser::ParseDoStatement(ParsedAttributes &attrs) {
|
|||
/// [C++] expression-statement
|
||||
/// [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) {
|
||||
// FIXME: Use attributes?
|
||||
|
||||
|
@ -1025,11 +1031,12 @@ StmtResult Parser::ParseForStatement(ParsedAttributes &attrs) {
|
|||
SourceLocation LParenLoc = ConsumeParen();
|
||||
ExprResult Value;
|
||||
|
||||
bool ForEach = false;
|
||||
bool ForEach = false, ForRange = false;
|
||||
StmtResult FirstPart;
|
||||
bool SecondPartIsInvalid = false;
|
||||
FullExprArg SecondPart(Actions);
|
||||
ExprResult Collection;
|
||||
ForRangeInit ForRangeInit;
|
||||
FullExprArg ThirdPart(Actions);
|
||||
Decl *SecondVar = 0;
|
||||
|
||||
|
@ -1052,13 +1059,21 @@ StmtResult Parser::ParseForStatement(ParsedAttributes &attrs) {
|
|||
ParsedAttributesWithRange attrs(AttrFactory);
|
||||
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;
|
||||
StmtVector Stmts(Actions);
|
||||
DeclGroupPtrTy DG = ParseSimpleDeclaration(Stmts, Declarator::ForContext,
|
||||
DeclEnd, attrs, false);
|
||||
DeclEnd, attrs, false,
|
||||
MightBeForRangeStmt ?
|
||||
&ForRangeInit : 0);
|
||||
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();
|
||||
} else if ((ForEach = isTokIdentifier_in())) {
|
||||
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.");
|
||||
// Parse the second part of the for specifier.
|
||||
if (Tok.is(tok::semi)) { // for (...;;
|
||||
|
@ -1149,6 +1164,17 @@ StmtResult Parser::ParseForStatement(ParsedAttributes &attrs) {
|
|||
// Match the ')'.
|
||||
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
|
||||
// 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.
|
||||
|
@ -1175,15 +1201,19 @@ StmtResult Parser::ParseForStatement(ParsedAttributes &attrs) {
|
|||
if (Body.isInvalid())
|
||||
return StmtError();
|
||||
|
||||
if (!ForEach)
|
||||
return Actions.ActOnForStmt(ForLoc, LParenLoc, FirstPart.take(), SecondPart,
|
||||
SecondVar, ThirdPart, RParenLoc, Body.take());
|
||||
if (ForEach)
|
||||
// FIXME: It isn't clear how to communicate the late destruction of
|
||||
// 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
|
||||
// C++ temporaries used to create the collection.
|
||||
return Actions.ActOnObjCForCollectionStmt(ForLoc, LParenLoc, FirstPart.take(),
|
||||
Collection.take(), RParenLoc,
|
||||
Body.take());
|
||||
if (ForRange)
|
||||
return Actions.FinishCXXForRangeStmt(ForRangeStmt.take(), Body.take());
|
||||
|
||||
return Actions.ActOnForStmt(ForLoc, LParenLoc, FirstPart.take(), SecondPart,
|
||||
SecondVar, ThirdPart, RParenLoc, Body.take());
|
||||
}
|
||||
|
||||
/// 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) {
|
||||
if (var->isInvalidDecl()) return;
|
||||
|
||||
|
|
|
@ -2205,7 +2205,8 @@ void ADLResult::insert(NamedDecl *New) {
|
|||
|
||||
void Sema::ArgumentDependentLookup(DeclarationName Name, bool Operator,
|
||||
Expr **Args, unsigned NumArgs,
|
||||
ADLResult &Result) {
|
||||
ADLResult &Result,
|
||||
bool StdNamespaceIsAssociated) {
|
||||
// Find all of the associated namespaces and classes based on the
|
||||
// arguments we have.
|
||||
AssociatedNamespaceSet AssociatedNamespaces;
|
||||
|
@ -2213,6 +2214,8 @@ void Sema::ArgumentDependentLookup(DeclarationName Name, bool Operator,
|
|||
FindAssociatedClassesAndNamespaces(Args, NumArgs,
|
||||
AssociatedNamespaces,
|
||||
AssociatedClasses);
|
||||
if (StdNamespaceIsAssociated && StdNamespace)
|
||||
AssociatedNamespaces.insert(getStdNamespace());
|
||||
|
||||
QualType T1, T2;
|
||||
if (Operator) {
|
||||
|
|
|
@ -6152,7 +6152,8 @@ Sema::AddArgumentDependentLookupCandidates(DeclarationName Name,
|
|||
Expr **Args, unsigned NumArgs,
|
||||
TemplateArgumentListInfo *ExplicitTemplateArgs,
|
||||
OverloadCandidateSet& CandidateSet,
|
||||
bool PartialOverloading) {
|
||||
bool PartialOverloading,
|
||||
bool StdNamespaceIsAssociated) {
|
||||
ADLResult Fns;
|
||||
|
||||
// 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?
|
||||
|
||||
// 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.
|
||||
for (OverloadCandidateSet::iterator Cand = CandidateSet.begin(),
|
||||
|
@ -7693,7 +7695,8 @@ void Sema::AddOverloadedCallCandidates(UnresolvedLookupExpr *ULE,
|
|||
Args, NumArgs,
|
||||
ExplicitTemplateArgs,
|
||||
CandidateSet,
|
||||
PartialOverloading);
|
||||
PartialOverloading,
|
||||
ULE->isStdAssociatedNamespace());
|
||||
}
|
||||
|
||||
/// 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.
|
||||
assert(getLangOptions().CPlusPlus && "ADL enabled in C");
|
||||
}
|
||||
} else
|
||||
assert(!ULE->isStdAssociatedNamespace() &&
|
||||
"std is associated namespace but not doing ADL");
|
||||
#endif
|
||||
|
||||
OverloadCandidateSet CandidateSet(Fn->getExprLoc());
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include "clang/Sema/Scope.h"
|
||||
#include "clang/Sema/ScopeInfo.h"
|
||||
#include "clang/Sema/Initialization.h"
|
||||
#include "clang/Sema/Lookup.h"
|
||||
#include "clang/AST/APValue.h"
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "clang/AST/DeclObjC.h"
|
||||
|
@ -1013,6 +1014,387 @@ Sema::ActOnObjCForCollectionStmt(SourceLocation ForLoc,
|
|||
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,
|
||||
SourceLocation LabelLoc,
|
||||
LabelDecl *TheDecl) {
|
||||
|
|
|
@ -271,6 +271,7 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) {
|
|||
D->getStorageClassAsWritten());
|
||||
Var->setThreadSpecified(D->isThreadSpecified());
|
||||
Var->setCXXDirectInitializer(D->hasCXXDirectInitializer());
|
||||
Var->setCXXForRangeDecl(D->isCXXForRangeDecl());
|
||||
|
||||
// Substitute the nested name specifier, if any.
|
||||
if (SubstQualifier(D, Var))
|
||||
|
@ -350,7 +351,8 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) {
|
|||
}
|
||||
|
||||
SemaRef.PopExpressionEvaluationContext();
|
||||
} else if (!Var->isStaticDataMember() || Var->isOutOfLine())
|
||||
} else if ((!Var->isStaticDataMember() || Var->isOutOfLine()) &&
|
||||
!Var->isCXXForRangeDecl())
|
||||
SemaRef.ActOnUninitializedDecl(Var, false);
|
||||
|
||||
// Diagnose unused local variables.
|
||||
|
|
|
@ -1228,6 +1228,28 @@ public:
|
|||
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.
|
||||
///
|
||||
/// By default, performs semantic analysis to build the new expression.
|
||||
|
@ -5352,6 +5374,61 @@ TreeTransform<Derived>::TransformCXXTryStmt(CXXTryStmt *S) {
|
|||
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
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
|
@ -2676,6 +2676,11 @@ void ASTReader::InitializeContext(ASTContext &Ctx) {
|
|||
if (SpecialTypes[SPECIAL_TYPE_INT128_INSTALLED])
|
||||
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());
|
||||
|
||||
// If there were any CUDA special declarations, deserialize them.
|
||||
|
|
|
@ -684,6 +684,7 @@ void ASTDeclReader::VisitVarDecl(VarDecl *VD) {
|
|||
VD->setCXXDirectInitializer(Record[Idx++]);
|
||||
VD->setExceptionVariable(Record[Idx++]);
|
||||
VD->setNRVOVariable(Record[Idx++]);
|
||||
VD->setCXXForRangeDecl(Record[Idx++]);
|
||||
if (Record[Idx++])
|
||||
VD->setInit(Reader.ReadExpr(F));
|
||||
|
||||
|
|
|
@ -141,6 +141,7 @@ namespace clang {
|
|||
// C++ Statements
|
||||
void VisitCXXCatchStmt(CXXCatchStmt *S);
|
||||
void VisitCXXTryStmt(CXXTryStmt *S);
|
||||
void VisitCXXForRangeStmt(CXXForRangeStmt *);
|
||||
|
||||
void VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E);
|
||||
void VisitCXXConstructExpr(CXXConstructExpr *E);
|
||||
|
@ -999,6 +1000,19 @@ void ASTStmtReader::VisitCXXTryStmt(CXXTryStmt *S) {
|
|||
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) {
|
||||
VisitCallExpr(E);
|
||||
E->setOperator((OverloadedOperatorKind)Record[Idx++]);
|
||||
|
@ -1269,6 +1283,8 @@ void ASTStmtReader::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *E) {
|
|||
void ASTStmtReader::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *E) {
|
||||
VisitOverloadExpr(E);
|
||||
E->RequiresADL = Record[Idx++];
|
||||
if (E->RequiresADL)
|
||||
E->StdIsAssociatedNamespace = Record[Idx++];
|
||||
E->Overloaded = 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]);
|
||||
break;
|
||||
|
||||
case STMT_CXX_FOR_RANGE:
|
||||
S = new (Context) CXXForRangeStmt(Empty);
|
||||
break;
|
||||
|
||||
case EXPR_CXX_OPERATOR_CALL:
|
||||
S = new (Context) CXXOperatorCallExpr(*Context, Empty);
|
||||
break;
|
||||
|
|
|
@ -2825,6 +2825,8 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, MemorizeStatCalls *StatCalls,
|
|||
AddTypeRef(Context.ObjCSelRedefinitionType, Record);
|
||||
AddTypeRef(Context.getRawNSConstantStringType(), Record);
|
||||
Record.push_back(Context.isInt128Installed());
|
||||
AddTypeRef(Context.AutoDeductTy, Record);
|
||||
AddTypeRef(Context.AutoRRefDeductTy, Record);
|
||||
Stream.EmitRecord(SPECIAL_TYPES, Record);
|
||||
|
||||
// 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->isExceptionVariable());
|
||||
Record.push_back(D->isNRVOVariable());
|
||||
Record.push_back(D->isCXXForRangeDecl());
|
||||
Record.push_back(D->getInit() ? 1 : 0);
|
||||
if (D->getInit())
|
||||
Writer.AddStmt(D->getInit());
|
||||
|
@ -1145,6 +1146,7 @@ void ASTWriter::WriteDeclsBlockAbbrevs() {
|
|||
Abv->Add(BitCodeAbbrevOp(0)); // hasCXXDirectInitializer
|
||||
Abv->Add(BitCodeAbbrevOp(0)); // isExceptionVariable
|
||||
Abv->Add(BitCodeAbbrevOp(0)); // isNRVOVariable
|
||||
Abv->Add(BitCodeAbbrevOp(0)); // isCXXForRangeDecl
|
||||
Abv->Add(BitCodeAbbrevOp(0)); // HasInit
|
||||
Abv->Add(BitCodeAbbrevOp(0)); // HasMemberSpecializationInfo
|
||||
// ParmVarDecl
|
||||
|
|
|
@ -115,6 +115,7 @@ namespace clang {
|
|||
// C++ Statements
|
||||
void VisitCXXCatchStmt(CXXCatchStmt *S);
|
||||
void VisitCXXTryStmt(CXXTryStmt *S);
|
||||
void VisitCXXForRangeStmt(CXXForRangeStmt *);
|
||||
|
||||
void VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E);
|
||||
void VisitCXXMemberCallExpr(CXXMemberCallExpr *E);
|
||||
|
@ -963,6 +964,20 @@ void ASTStmtWriter::VisitCXXTryStmt(CXXTryStmt *S) {
|
|||
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) {
|
||||
VisitCallExpr(E);
|
||||
Record.push_back(E->getOperator());
|
||||
|
@ -1267,6 +1282,8 @@ void ASTStmtWriter::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *E) {
|
|||
void ASTStmtWriter::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *E) {
|
||||
VisitOverloadExpr(E);
|
||||
Record.push_back(E->requiresADL());
|
||||
if (E->requiresADL())
|
||||
Record.push_back(E->isStdAssociatedNamespace());
|
||||
Record.push_back(E->isOverloaded());
|
||||
Writer.AddDeclRef(E->getNamingClass(), Record);
|
||||
Code = serialization::EXPR_CXX_UNRESOLVED_LOOKUP;
|
||||
|
|
|
@ -423,6 +423,7 @@ void ExprEngine::Visit(const Stmt* S, ExplodedNode* Pred,
|
|||
case Stmt::CXXBindTemporaryExprClass:
|
||||
case Stmt::CXXCatchStmtClass:
|
||||
case Stmt::CXXDependentScopeMemberExprClass:
|
||||
case Stmt::CXXForRangeStmtClass:
|
||||
case Stmt::CXXNullPtrLiteralExprClass:
|
||||
case Stmt::CXXPseudoDestructorExprClass:
|
||||
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'}}
|
||||
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'}}
|
||||
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'}}
|
||||
|
@ -341,6 +343,8 @@ void test_unexpanded_exprs(Types ...values) {
|
|||
// SizeOfPackExpr is uninteresting
|
||||
|
||||
// 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.
|
||||
|
|
|
@ -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::CXXCatchStmtClass:
|
||||
case Stmt::CXXTryStmtClass:
|
||||
case Stmt::CXXForRangeStmtClass:
|
||||
K = CXCursor_UnexposedStmt;
|
||||
break;
|
||||
|
||||
|
|
Loading…
Reference in New Issue