]> granicus.if.org Git - clang/commitdiff
Add support for C++0x's range-based for loops, as specified by the C++11 draft standa...
authorRichard Smith <richard-llvm@metafoo.co.uk>
Thu, 14 Apr 2011 22:09:26 +0000 (22:09 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Thu, 14 Apr 2011 22:09:26 +0000 (22:09 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@129541 91177308-0d34-0410-b5e6-96231b3b80d8

47 files changed:
include/clang/AST/ASTContext.h
include/clang/AST/Decl.h
include/clang/AST/ExprCXX.h
include/clang/AST/PrettyPrinter.h
include/clang/AST/RecursiveASTVisitor.h
include/clang/AST/StmtCXX.h
include/clang/Analysis/Visitors/CFGStmtVisitor.h
include/clang/Basic/DiagnosticSemaKinds.td
include/clang/Basic/StmtNodes.td
include/clang/Parse/Parser.h
include/clang/Sema/Sema.h
include/clang/Serialization/ASTBitCodes.h
lib/AST/ASTContext.cpp
lib/AST/DeclPrinter.cpp
lib/AST/ExprCXX.cpp
lib/AST/Stmt.cpp
lib/AST/StmtPrinter.cpp
lib/AST/StmtProfile.cpp
lib/Analysis/CFG.cpp
lib/CodeGen/CGStmt.cpp
lib/CodeGen/CodeGenFunction.h
lib/Parse/ParseDecl.cpp
lib/Parse/ParseStmt.cpp
lib/Sema/SemaDecl.cpp
lib/Sema/SemaLookup.cpp
lib/Sema/SemaOverload.cpp
lib/Sema/SemaStmt.cpp
lib/Sema/SemaTemplateInstantiateDecl.cpp
lib/Sema/TreeTransform.h
lib/Serialization/ASTReader.cpp
lib/Serialization/ASTReaderDecl.cpp
lib/Serialization/ASTReaderStmt.cpp
lib/Serialization/ASTWriter.cpp
lib/Serialization/ASTWriterDecl.cpp
lib/Serialization/ASTWriterStmt.cpp
lib/StaticAnalyzer/Core/ExprEngine.cpp
test/CXX/basic/basic.scope/basic.scope.local/p4-0x.cpp [new file with mode: 0644]
test/CXX/dcl.dcl/dcl.spec/dcl.type/p3-0x.cpp [new file with mode: 0644]
test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp [new file with mode: 0644]
test/CXX/temp/temp.decls/temp.variadic/p5.cpp
test/CodeGenCXX/for-range-temporaries.cpp [new file with mode: 0644]
test/CodeGenCXX/for-range.cpp [new file with mode: 0644]
test/PCH/cxx-for-range.cpp [new file with mode: 0644]
test/PCH/cxx-for-range.h [new file with mode: 0644]
test/SemaCXX/for-range-examples.cpp [new file with mode: 0644]
test/SemaCXX/for-range-no-std.cpp [new file with mode: 0644]
tools/libclang/CXCursor.cpp

index c330f4cda23bf8bb064750e9985f472913a1a20d..7a62af7eea73697764a7b666048babbf64a64f67 100644 (file)
@@ -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;
index 4dd3db7fad941dd26665f6bffedf18eb933e539c..48b7d9f1bf8475fdf20bf36065f2d6ed180b01b0 100644 (file)
@@ -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
index 9bb1a50be90583406ddda04f954271d6eb91ff4c..ed4661b3a4ffef970bf459257572d54ed0bfeb8e 100644 (file)
@@ -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; }
 
index 5d52cde4b113696293553cf3e4f95a2639136bb8..cf5fadbd18508b00633f8e1617a922c7fce30d93 100644 (file)
@@ -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
index ccc327b5b676af69ab5e3347b8e06f2820965825..2a4348feac3fbe9d374350c75d776f2c848f651f 100644 (file)
@@ -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, { })
index f08815fd562d57f987112e8cf3926fed0a6f4ecc..42dcf2bb7b79053d45da0801dccf89a7aa15ca4f 100644 (file)
@@ -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
 
index d197e69babde13ea3f1e2f2d251c591889e9331e..7fb4ab3ebad977d7186a9f9f36151b28736a6041 100644 (file)
@@ -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);
   }
index 90945d7bd40e81641f382a338b6e6a2f9eda39b3..b96c461c6c20a630a564b8481bc336bdf4dd6722 100644 (file)
@@ -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<
index 44f6f5393986bd90337a3911366f77a0d6f545a2..a25af44790c7a4e669f742dc682765ac668db4a8 100644 (file)
@@ -41,6 +41,7 @@ def ObjCForCollectionStmt : Stmt;
 // C++ statments
 def CXXCatchStmt : Stmt;
 def CXXTryStmt : Stmt;
+def CXXForRangeStmt : Stmt;
 
 // Expressions
 def Expr : Stmt<1>;
index 4c422cc4b64fc0b245ec5b9951a16050b65c6cf0..f10003fcd2b6d84c9d8c971d7f8c6d6d4bb2adc1 100644 (file)
@@ -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);
 
index 1169b50f852933c95d581456439d9e6e87e6196d..f03bfe49b4122fabca14a89aafa70268f8377dbb 100644 (file)
@@ -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,
index 17cb9efcea180046d9dbab4a91bcafd6fc27887b..35d6fe7f3b1eee03f5caba43e2c426e6f614db51 100644 (file)
@@ -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,
index 7317928d971ee7265884631500cb6061ec6af7c6..eea5394cfa5d90a56dd7c9dfd96ecab5511f9386 100644 (file)
@@ -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 {
index 446b4d4646464892bfcf03342af21fd0bfc4b00f..37cd2af1b18d4b4df03bc930d997550d4c9f0cc1 100644 (file)
@@ -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 {
index 692c2c37607fb9e8022250e98a207314ce0849d8..127431ba7d661f1c3399cecc8cb891f3b300fbc4 100644 (file)
@@ -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 *
index 6c353192785722cd8574a32cc048c194e304a6c4..5b0db8621a3111d57ee6446e91984600aac4d846 100644 (file)
@@ -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)
index 4f500441166d5bddbee327f4c8e60f1b24902023..37010a0358d6b4915cfd3f7bcd40eacd33969a9a 100644 (file)
@@ -291,6 +291,18 @@ void StmtPrinter::VisitObjCForCollectionStmt(ObjCForCollectionStmt *Node) {
   }
 }
 
+void StmtPrinter::VisitCXXForRangeStmt(CXXForRangeStmt *Node) {
+  Indent() << "for (";
+  PrintingPolicy SubPolicy(Policy);
+  SubPolicy.SuppressInitializers = true;
+  Node->getLoopVariable()->print(OS, SubPolicy, IndentLevel);
+  OS << " : ";
+  PrintExpr(Node->getRangeInit());
+  OS << ") {\n";
+  PrintStmt(Node->getBody());
+  Indent() << "}\n";
+}
+
 void StmtPrinter::VisitGotoStmt(GotoStmt *Node) {
   Indent() << "goto " << Node->getLabel()->getName() << ";\n";
 }
index a506d055b30586c658e255d9c747ccf5260d771f..92292cea719418b898d53591f2de5c98eab07d44 100644 (file)
@@ -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);
 }
index 3dcc763edaac1dc06360246010c73c98cbe2a942..149607404c9b3c6586047dac0b114ffc70a1444d 100644 (file)
@@ -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) {
index e72d5c73f58ff6b728c415e9b10f4947f4636cea..7a1ce19b07cc401c419e1897b79d41d786d1ff20 100644 (file)
@@ -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);
index f3b00e3370004923b75da4e6d04c8a8c2d0d7c84..d53da9f341907d612284db813a3002f88340aa8e 100644 (file)
@@ -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
index 8674485d5f84f91fee5e7dddbb5dc9788b860127..5e6c51c1ee92fc81e81533cad0b058067722600c 100644 (file)
@@ -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) {
index 8ffd6e921b2e3dba6c4bb049fecd057b8a18fb8b..d70a745314ee2b945d9eaac78391a0daf4d2fc16 100644 (file)
@@ -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());
+
+  if (ForRange)
+    return Actions.FinishCXXForRangeStmt(ForRangeStmt.take(), 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());
+  return Actions.ActOnForStmt(ForLoc, LParenLoc, FirstPart.take(), SecondPart,
+                              SecondVar, ThirdPart, RParenLoc, Body.take());
 }
 
 /// ParseGotoStatement
index 29174245816b9290900736a9c79ef0df168857c9..7c32a381df2699dd58e47ec33b790a5afece56fe 100644 (file)
@@ -5247,6 +5247,47 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl,
   }
 }
 
+void Sema::ActOnCXXForRangeDecl(Decl *D) {
+  VarDecl *VD = dyn_cast<VarDecl>(D);
+  if (!VD) {
+    Diag(D->getLocation(), diag::err_for_range_decl_must_be_var);
+    D->setInvalidDecl();
+    return;
+  }
+
+  VD->setCXXForRangeDecl(true);
+
+  // for-range-declaration cannot be given a storage class specifier.
+  int Error = -1;
+  switch (VD->getStorageClassAsWritten()) {
+  case SC_None:
+    break;
+  case SC_Extern:
+    Error = 0;
+    break;
+  case SC_Static:
+    Error = 1;
+    break;
+  case SC_PrivateExtern:
+    Error = 2;
+    break;
+  case SC_Auto:
+    Error = 3;
+    break;
+  case SC_Register:
+    Error = 4;
+    break;
+  }
+  // FIXME: constexpr isn't allowed here.
+  //if (DS.isConstexprSpecified())
+  //  Error = 5;
+  if (Error != -1) {
+    Diag(VD->getOuterLocStart(), diag::err_for_range_storage_class)
+      << VD->getDeclName() << Error;
+    D->setInvalidDecl();
+  }
+}
+
 void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
   if (var->isInvalidDecl()) return;
 
index fe94224a6e6c5989571231d2135ec687919f1022..437898775a82b986313fdb7054280727b43e76ab 100644 (file)
@@ -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) {
index 25e25a2139d4f13b654f8e4480e304a77832c40c..57338f255ce4064deba63b370f7d2fb6c07884fd 100644 (file)
@@ -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());
index e957a4b93f85385f78ca7120f6e77db130a93bae..407618219fbf322aaf15e799345ed40cdf7084bb 100644 (file)
@@ -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) {
index a2d1f871a2f8f1d128068bc28144f1315b288ac9..11b98e0af2a1175bd9bb0d083e8761d39ee426bd 100644 (file)
@@ -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.
index a7dc920f84897b770cf3376b2ed487d1470c76d5..a639f5f303480b5720ce8993cfecbcb775deb2f7 100644 (file)
@@ -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
 //===----------------------------------------------------------------------===//
index 8e8a1bd2dc06f255d4322097ca0ffef15508dc19..a7c3fea7d60684cbf2205296e4d34e78eef55a18 100644 (file)
@@ -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.
index 60fcc14d611f7293234d8fcd64516182a7aced7b..92b387e21aca0ee0dae9a01619d74e34f164bdeb 100644 (file)
@@ -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));
 
index 557cb381954f03dfa5383d2aa1009a0f1d4eeaa7..68591bec3fdf39656b27ab39d5d613e91e80ce3a 100644 (file)
@@ -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;
index 0e925a2691b876ddea3a0da059ec5e6afc248404..85b5326da993b71b6a45d6f7bbe6a3dad432cafd 100644 (file)
@@ -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
index 95b0c3c4dbf3181e8d3a568c811496870a018cf7..c74fe176f356420d31248e9c17fcd141624f5cff 100644 (file)
@@ -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
index 875d662929894d42318d450b690627d8dc5bbb4f..9d54bb9b21ba6ff24386d5852cd58ca5f523fb76 100644 (file)
@@ -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;
index 9102f23f154f318d242822ce6001c7313a9d81e7..477292f6ff0654b7b5dd2924280360a694d7d053 100644 (file)
@@ -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:
diff --git a/test/CXX/basic/basic.scope/basic.scope.local/p4-0x.cpp b/test/CXX/basic/basic.scope/basic.scope.local/p4-0x.cpp
new file mode 100644 (file)
index 0000000..d930f97
--- /dev/null
@@ -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;
+  }}
+}
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.type/p3-0x.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.type/p3-0x.cpp
new file mode 100644 (file)
index 0000000..10184a0
--- /dev/null
@@ -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}}
diff --git a/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp b/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp
new file mode 100644 (file)
index 0000000..12acde1
--- /dev/null
@@ -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;
+}
index a0b17adad6ae7d792e166bc4d565cc93ac32c4f5..25338e3bae67f8ae497bbaf87cbf4f0889dd3812 100644 (file)
@@ -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.
diff --git a/test/CodeGenCXX/for-range-temporaries.cpp b/test/CodeGenCXX/for-range-temporaries.cpp
new file mode 100644 (file)
index 0000000..285862f
--- /dev/null
@@ -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
diff --git a/test/CodeGenCXX/for-range.cpp b/test/CodeGenCXX/for-range.cpp
new file mode 100644 (file)
index 0000000..94b614f
--- /dev/null
@@ -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
+}
diff --git a/test/PCH/cxx-for-range.cpp b/test/PCH/cxx-for-range.cpp
new file mode 100644 (file)
index 0000000..5854917
--- /dev/null
@@ -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())
+          ;
+}
diff --git a/test/PCH/cxx-for-range.h b/test/PCH/cxx-for-range.h
new file mode 100644 (file)
index 0000000..f15c7e7
--- /dev/null
@@ -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())
+          ;
+}
diff --git a/test/SemaCXX/for-range-examples.cpp b/test/SemaCXX/for-range-examples.cpp
new file mode 100644 (file)
index 0000000..810f1de
--- /dev/null
@@ -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);
+}
diff --git a/test/SemaCXX/for-range-no-std.cpp b/test/SemaCXX/for-range-no-std.cpp
new file mode 100644 (file)
index 0000000..8cc71e5
--- /dev/null
@@ -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}}
+}
index 7ed5d2051cfc0aeacde1ceae9489da8777263c24..89800598ed019ca54a1c756cfdf70bd36cd49847 100644 (file)
@@ -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;