Hi rsmith, chandlerc, hubert.reinterpretcast, aaron.ballman,

When ARBs (arrays of runtime bound) were discussed in Lenexa last week, the 
idea that gained consensus to move forward was a "magic" class, one that could 
only be constructed on the stack, perhaps using an ARB(-like) syntax. We did 
not have a concrete proposal for such a facility, nor are there any 
implementations that follow that model. However, there is not consensus for 
ARBs as-is, nor particularly for dynarray, and some hybrid seems like the only 
viable path forward (aside from doing nothing). And I'd prefer we do 
something...

This patch implements a mode in Clang for "fancy" ARBs, controlled by a feature 
flag: -ffancy-arbs -- While still rough, I'd like early feedback on this. The 
basic idea is that declaring:

  int x[n]

where n is not a constant, not only creates a stack array to hold n objects of 
type int, but also wraps that array in a container-like class. Here I've named 
it std::arb (I know this makes it a non-conforming extension; we can certainly 
name it something else), and it is kind of like std::initializer_list on 
steroids (it looks more like an array wrapper, has more of the standard 
typedefs, is convertable to a pointer type, etc.).

The implementation wraps the VarDecl creation and causes two variables to be 
declared: an internal variable (x.ARB) that actually manages the storage and 
object lifetimes, and an std::arb wrapper (which gets the declared name x), 
through which the surrounding code interacts with the storage. Some plumbing 
changes in Sema allow for the capturing of this additional declaration so it 
can be added to the DeclGroup with the primary one.

One of the design requirement of the design is that the class be "magic" 
(unable to be created manually), and to meet this requirement, the class is 
non-copyable, non-movable, and has no public constructors. A new "magic" init 
type is added, like CallInit, but bypassing access control checks, to cause the 
ARB syntax to trigger construction of std::arb via an otherwise inaccessible 
private constructor. I'm not sure if, from a standardization perspective, this 
access-control-overriding is necessary. If we don't do it, any code that uses 
the constructor would be implementation-specific and have UB.

This should, hopefully, satisfy the consensus requirements from EWG, while 
matching the current syntax for ARBs. While you can pass x to a function 
requiring int*, x will also support begin(), end(), size(), etc. and can be 
treated like a container. This using (pointer,size) on interface boundaries is 
not required (which is part of the reason I elected to make it a type with a 
"standardized" name).

Currently, the definition of std::arb is in an internal header that is included 
before normal source parsing. To limit expense, I did not include any features 
in std::arb that would be complicated to implement, or require pulling in other 
library headers (no reverse iterators, no at() because no exceptions, no 
fill()). An alternative design is to make the implementation more 
fully-featured but require the header be included in every TU in which ARBs are 
used.

The current implementation does not work with non-POD types because the 
underlying VLA support rejects them. That can be extended separately (from this 
patch), and then non-POD types should also work with this feature.

Please review.

http://reviews.llvm.org/D9714

Files:
  include/clang/AST/Decl.h
  include/clang/Basic/DiagnosticSemaKinds.td
  include/clang/Basic/LangOptions.def
  include/clang/Driver/Options.td
  include/clang/Parse/Parser.h
  include/clang/Sema/Initialization.h
  include/clang/Sema/Sema.h
  lib/AST/ASTDumper.cpp
  lib/Driver/Tools.cpp
  lib/Frontend/CompilerInvocation.cpp
  lib/Frontend/InitPreprocessor.cpp
  lib/Headers/CMakeLists.txt
  lib/Headers/__arb.h
  lib/Parse/ParseDecl.cpp
  lib/Parse/ParseTemplate.cpp
  lib/Sema/JumpDiagnostics.cpp
  lib/Sema/Sema.cpp
  lib/Sema/SemaDecl.cpp
  lib/Sema/SemaInit.cpp
  lib/Sema/SemaTemplateInstantiateDecl.cpp
  lib/Sema/TreeTransform.h
  test/CodeGen/fancy-arbs.cpp

EMAIL PREFERENCES
  http://reviews.llvm.org/settings/panel/emailpreferences/
Index: include/clang/AST/Decl.h
===================================================================
--- include/clang/AST/Decl.h
+++ include/clang/AST/Decl.h
@@ -715,7 +715,8 @@
   enum InitializationStyle {
     CInit,    ///< C-style initialization with assignment
     CallInit, ///< Call-style initialization (C++98)
-    ListInit  ///< Direct list-initialization (C++11)
+    ListInit,  ///< Direct list-initialization (C++11)
+    MagicInit ///< Call-style init without access checking
   };
 
   /// \brief Kinds of thread-local storage.
@@ -1147,7 +1148,8 @@
   bool checkInitIsICE() const;
 
   void setInitStyle(InitializationStyle Style) {
-    VarDeclBits.InitStyle = Style;
+    if (getInitStyle() != MagicInit)
+      VarDeclBits.InitStyle = Style;
   }
 
   /// \brief The style of initialization for this declaration.
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -1697,6 +1697,10 @@
   "array backing the initializer list will be destroyed at the end of "
   "%select{the full-expression|the constructor}0">,
   InGroup<DiagGroup<"dangling-initializer-list">>;
+def err_implied_std_arb_not_found : Error<
+  "cannot deduce type of array because std::arb was not found">;
+def err_malformed_std_arb : Error<
+  "std::arb must be a class template with a single type parameter">;
 
 // C++1y decltype(auto) type
 def err_decltype_auto_cannot_be_combined : Error<
Index: include/clang/Basic/LangOptions.def
===================================================================
--- include/clang/Basic/LangOptions.def
+++ include/clang/Basic/LangOptions.def
@@ -167,6 +167,7 @@
 
 LANGOPT(AssumeSaneOperatorNew , 1, 1, "implicit __attribute__((malloc)) for C++'s new operators")
 LANGOPT(SizedDeallocation , 1, 0, "enable sized deallocation functions")
+LANGOPT(FancyARBs , 1, 0, "use std::arb to represent ARBs")
 BENIGN_LANGOPT(ElideConstructors , 1, 1, "C++ copy constructor elision")
 BENIGN_LANGOPT(DumpRecordLayouts , 1, 0, "dumping the layout of IRgen'd records")
 BENIGN_LANGOPT(DumpRecordLayoutsSimple , 1, 0, "dumping the layout of IRgen'd records in a simple form")
Index: include/clang/Driver/Options.td
===================================================================
--- include/clang/Driver/Options.td
+++ include/clang/Driver/Options.td
@@ -849,6 +849,9 @@
 def fsized_deallocation : Flag<["-"], "fsized-deallocation">, Flags<[CC1Option]>,
   HelpText<"Enable C++14 sized global deallocation functions">, Group<f_Group>;
 def fno_sized_deallocation: Flag<["-"], "fno-sized-deallocation">, Group<f_Group>;
+def ffancy_arbs : Flag<["-"], "ffancy-arbs">, Flags<[CC1Option]>,
+  HelpText<"Use std::arb for ARBs">, Group<f_Group>;
+def fno_fancy_arbs: Flag<["-"], "fno-fancy-arbs">, Group<f_Group>;
 
 def fobjc_gc_only : Flag<["-"], "fobjc-gc-only">, Group<f_Group>, Flags<[CC1Option]>,
   HelpText<"Use GC exclusively for Objective-C related memory management">;
Index: include/clang/Parse/Parser.h
===================================================================
--- include/clang/Parse/Parser.h
+++ include/clang/Parse/Parser.h
@@ -1726,11 +1726,11 @@
   DeclGroupPtrTy ParseDeclGroup(ParsingDeclSpec &DS, unsigned Context,
                                 SourceLocation *DeclEnd = nullptr,
                                 ForRangeInit *FRI = nullptr);
-  Decl *ParseDeclarationAfterDeclarator(Declarator &D,
+  Decl *ParseDeclarationAfterDeclarator(Declarator &D, Decl *&AuxDecl,
                const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo());
   bool ParseAsmAttributesAfterDeclarator(Declarator &D);
   Decl *ParseDeclarationAfterDeclaratorAndAttributes(
-      Declarator &D,
+      Declarator &D, Decl *&AuxDecl,
       const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo(),
       ForRangeInit *FRI = nullptr);
   Decl *ParseFunctionStatementBody(Decl *Decl, ParseScope &BodyScope);
Index: include/clang/Sema/Initialization.h
===================================================================
--- include/clang/Sema/Initialization.h
+++ include/clang/Sema/Initialization.h
@@ -918,7 +918,8 @@
                      const InitializedEntity &Entity,
                      const InitializationKind &Kind,
                      MultiExprArg Args,
-                     QualType *ResultType = nullptr);
+                     QualType *ResultType = nullptr,
+                     bool NoAccessCheck = false);
   
   /// \brief Diagnose an potentially-invalid initialization sequence.
   ///
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -629,6 +629,9 @@
   /// \<initializer_list>.
   ClassTemplateDecl *StdInitializerList;
 
+  /// \brief The C++ "std::arb" template, which is defined in \<arb>.
+  ClassTemplateDecl *StdARB;
+
   /// \brief The C++ "type_info" declaration, which is defined in \<typeinfo>.
   RecordDecl *CXXTypeInfoDecl;
 
@@ -1499,9 +1502,13 @@
                std::unique_ptr<CorrectionCandidateCallback> CCC = nullptr);
 
   Decl *ActOnDeclarator(Scope *S, Declarator &D);
+  Decl *ActOnDeclarator(Scope *S, Declarator &D, Decl *&AuxDecl);
 
   NamedDecl *HandleDeclarator(Scope *S, Declarator &D,
                               MultiTemplateParamsArg TemplateParameterLists);
+  NamedDecl *HandleDeclarator(Scope *S, Declarator &D,
+                              MultiTemplateParamsArg TemplateParameterLists,
+                              Decl *&AuxDecl);
   void RegisterLocallyScopedExternCDecl(NamedDecl *ND, Scope *S);
   bool DiagnoseClassNameShadow(DeclContext *DC, DeclarationNameInfo Info);
   bool diagnoseQualifiedDeclaration(CXXScopeSpec &SS, DeclContext *DC,
@@ -1533,7 +1540,7 @@
                                      TypeSourceInfo *TInfo,
                                      LookupResult &Previous,
                                      MultiTemplateParamsArg TemplateParamLists,
-                                     bool &AddToScope);
+                                     bool &AddToScope, Decl *&AuxDecl);
   // Returns true if the variable declaration is a redeclaration
   bool CheckVariableDeclaration(VarDecl *NewVD, LookupResult &Previous);
   void CheckVariableDeclarationType(VarDecl *NewVD);
@@ -3912,6 +3919,12 @@
   /// defined in [dcl.init.list]p2.
   bool isInitListConstructor(const CXXConstructorDecl *Ctor);
 
+  /// \brief Looks for the std::arb template and instantiates it
+  /// with Element, or emits an error if it's not found.
+  ///
+  /// \returns The instantiated template, or null on error.
+  QualType BuildStdARB(QualType Element, SourceLocation Loc);
+
   Decl *ActOnUsingDirective(Scope *CurScope,
                             SourceLocation UsingLoc,
                             SourceLocation NamespcLoc,
Index: lib/AST/ASTDumper.cpp
===================================================================
--- lib/AST/ASTDumper.cpp
+++ lib/AST/ASTDumper.cpp
@@ -1154,6 +1154,7 @@
     case VarDecl::CInit: OS << " cinit"; break;
     case VarDecl::CallInit: OS << " callinit"; break;
     case VarDecl::ListInit: OS << " listinit"; break;
+    case VarDecl::MagicInit: OS << " magicinit"; break;
     }
     dumpStmt(D->getInit());
   }
Index: lib/Driver/Tools.cpp
===================================================================
--- lib/Driver/Tools.cpp
+++ lib/Driver/Tools.cpp
@@ -4351,6 +4351,11 @@
                    options::OPT_fno_sized_deallocation, false))
     CmdArgs.push_back("-fsized-deallocation");
 
+  // Should we use std::arb for ARBs?
+  if (Args.hasFlag(options::OPT_ffancy_arbs,
+                   options::OPT_fno_fancy_arbs, false))
+    CmdArgs.push_back("-ffancy-arbs");
+
   // -fconstant-cfstrings is default, and may be subject to argument translation
   // on Darwin.
   if (!Args.hasFlag(options::OPT_fconstant_cfstrings,
Index: lib/Frontend/CompilerInvocation.cpp
===================================================================
--- lib/Frontend/CompilerInvocation.cpp
+++ lib/Frontend/CompilerInvocation.cpp
@@ -1535,6 +1535,7 @@
   Opts.NoMathBuiltin = Args.hasArg(OPT_fno_math_builtin);
   Opts.AssumeSaneOperatorNew = !Args.hasArg(OPT_fno_assume_sane_operator_new);
   Opts.SizedDeallocation = Args.hasArg(OPT_fsized_deallocation);
+  Opts.FancyARBs = Args.hasArg(OPT_ffancy_arbs);
   Opts.HeinousExtensions = Args.hasArg(OPT_fheinous_gnu_extensions);
   Opts.AccessControl = !Args.hasArg(OPT_fno_access_control);
   Opts.ElideConstructors = !Args.hasArg(OPT_fno_elide_constructors);
Index: lib/Frontend/InitPreprocessor.cpp
===================================================================
--- lib/Frontend/InitPreprocessor.cpp
+++ lib/Frontend/InitPreprocessor.cpp
@@ -929,6 +929,9 @@
   InitializeStandardPredefinedMacros(PP.getTargetInfo(), PP.getLangOpts(),
                                      FEOpts, Builder);
 
+  if (InitOpts.UsePredefines && LangOpts.FancyARBs)
+    AddImplicitInclude(Builder, "__arb.h");
+
   // Add on the predefines from the driver.  Wrap in a #line directive to report
   // that they come from the command line.
   if (!PP.getLangOpts().AsmPreprocessor)
Index: lib/Headers/CMakeLists.txt
===================================================================
--- lib/Headers/CMakeLists.txt
+++ lib/Headers/CMakeLists.txt
@@ -2,6 +2,7 @@
   adxintrin.h
   altivec.h
   ammintrin.h
+  __arb.h
   arm_acle.h
   avx2intrin.h
   avx512bwintrin.h
Index: lib/Headers/__arb.h
===================================================================
--- /dev/null
+++ lib/Headers/__arb.h
@@ -0,0 +1,74 @@
+// -*- C++ -*-
+//===----------------------------- arb ------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _ARB
+#define _ARB
+
+#pragma GCC system_header
+
+namespace std { inline namespace __clang_arb_v1 {
+
+template <class _Tp>
+struct arb final
+{
+public:
+    typedef _Tp                                   value_type;
+    typedef value_type&                           reference;
+    typedef const value_type&                     const_reference;
+    typedef value_type*                           iterator;
+    typedef const value_type*                     const_iterator;
+    typedef value_type*                           pointer;
+    typedef const value_type*                     const_pointer;
+    typedef __SIZE_TYPE__                         size_type;
+    typedef __PTRDIFF_TYPE__                      difference_type;
+
+public:
+    arb(arb&&) = delete;
+    arb(const arb&) = delete;
+    arb& operator=(const arb&) = delete;
+
+private:
+    value_type *            __base_;
+    size_type               __size_;
+
+private:
+    arb(pointer __p, size_type __s) noexcept : __base_(__p), __size_(__s) {}
+
+public:
+    inline iterator       begin()        noexcept { return iterator(data()); }
+    inline const_iterator begin()  const noexcept { return const_iterator(data()); }
+    inline const_iterator cbegin() const noexcept { return const_iterator(data()); }
+    inline iterator       end()          noexcept { return iterator(data() + __size_); }
+    inline const_iterator end()    const noexcept { return const_iterator(data() + __size_); }
+    inline const_iterator cend()   const noexcept { return const_iterator(data() + __size_); }
+
+    inline size_type size()     const noexcept { return __size_; }
+    inline size_type max_size() const noexcept { return __size_; }
+    inline bool      empty()    const noexcept { return __size_ == 0; }
+
+    inline reference       operator[](size_type __n)       { return data()[__n]; }
+    inline const_reference operator[](size_type __n) const { return data()[__n]; }
+
+    inline reference       front()       { return data()[0]; }
+    inline const_reference front() const { return data()[0]; }
+    inline reference       back()        { return data()[__size_-1]; }
+    inline const_reference back()  const { return data()[__size_-1]; }
+
+    inline _Tp*       data()       noexcept { return __base_; }
+    inline const _Tp* data() const noexcept { return __base_; }
+
+    inline operator _Tp*()             noexcept { return data(); }
+    inline operator const _Tp*() const noexcept { return data(); }
+};
+
+}}
+
+#endif // _ARB
+
Index: lib/Parse/ParseDecl.cpp
===================================================================
--- lib/Parse/ParseDecl.cpp
+++ lib/Parse/ParseDecl.cpp
@@ -1779,11 +1779,14 @@
   }
 
   SmallVector<Decl *, 8> DeclsInGroup;
+  Decl *AuxDecl = nullptr;
   Decl *FirstDecl = ParseDeclarationAfterDeclaratorAndAttributes(
-      D, ParsedTemplateInfo(), FRI);
+      D, AuxDecl, ParsedTemplateInfo(), FRI);
   if (LateParsedAttrs.size() > 0)
     ParseLexedAttributeList(LateParsedAttrs, FirstDecl, true, false);
   D.complete(FirstDecl);
+  if (AuxDecl)
+    DeclsInGroup.push_back(AuxDecl);
   if (FirstDecl)
     DeclsInGroup.push_back(FirstDecl);
 
@@ -1822,8 +1825,11 @@
 
     ParseDeclarator(D);
     if (!D.isInvalidType()) {
-      Decl *ThisDecl = ParseDeclarationAfterDeclarator(D);
+      Decl *AuxDecl = nullptr;
+      Decl *ThisDecl = ParseDeclarationAfterDeclarator(D, AuxDecl);
       D.complete(ThisDecl);
+      if (AuxDecl)
+        DeclsInGroup.push_back(AuxDecl);
       if (ThisDecl)
         DeclsInGroup.push_back(ThisDecl);
     }
@@ -1891,20 +1897,21 @@
 /// definitions, but that definitely doesn't fit with the parser here.
 ///
 Decl *Parser::ParseDeclarationAfterDeclarator(
-    Declarator &D, const ParsedTemplateInfo &TemplateInfo) {
+    Declarator &D, Decl *&AuxDecl, const ParsedTemplateInfo &TemplateInfo) {
   if (ParseAsmAttributesAfterDeclarator(D))
     return nullptr;
 
-  return ParseDeclarationAfterDeclaratorAndAttributes(D, TemplateInfo);
+  return ParseDeclarationAfterDeclaratorAndAttributes(D, AuxDecl, TemplateInfo);
 }
 
 Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(
-    Declarator &D, const ParsedTemplateInfo &TemplateInfo, ForRangeInit *FRI) {
+    Declarator &D, Decl *&AuxDecl, const ParsedTemplateInfo &TemplateInfo,
+    ForRangeInit *FRI) {
   // Inform the current actions module that we just parsed this declarator.
   Decl *ThisDecl = nullptr;
   switch (TemplateInfo.Kind) {
   case ParsedTemplateInfo::NonTemplate:
-    ThisDecl = Actions.ActOnDeclarator(getCurScope(), D);
+    ThisDecl = Actions.ActOnDeclarator(getCurScope(), D, AuxDecl);
     break;
 
   case ParsedTemplateInfo::Template:
@@ -2087,7 +2094,10 @@
       Actions.AddInitializerToDecl(ThisDecl, Init.get(),
                                    /*DirectInit=*/true, TypeContainsAuto);
 
-  } else {
+  } else if (!(ThisDecl && isa<VarDecl>(ThisDecl) &&
+               cast<VarDecl>(ThisDecl)->hasInit())) {
+    // Sema might have added an implicit initializer, but if not, this is an
+    // uninitialized decl.
     Actions.ActOnUninitializedDecl(ThisDecl, TypeContainsAuto);
   }
 
Index: lib/Parse/ParseTemplate.cpp
===================================================================
--- lib/Parse/ParseTemplate.cpp
+++ lib/Parse/ParseTemplate.cpp
@@ -283,8 +283,10 @@
   }
 
   // Parse this declaration.
-  Decl *ThisDecl = ParseDeclarationAfterDeclarator(DeclaratorInfo,
+  Decl *AuxDecl = nullptr;
+  Decl *ThisDecl = ParseDeclarationAfterDeclarator(DeclaratorInfo, AuxDecl,
                                                    TemplateInfo);
+  assert(!AuxDecl && "Should not have an aux decl here!");
 
   if (Tok.is(tok::comma)) {
     Diag(Tok, diag::err_multiple_template_declarators)
Index: lib/Sema/JumpDiagnostics.cpp
===================================================================
--- lib/Sema/JumpDiagnostics.cpp
+++ lib/Sema/JumpDiagnostics.cpp
@@ -184,7 +184,8 @@
       if (const CXXConstructExpr *CCE = dyn_cast<CXXConstructExpr>(Init)) {
         const CXXConstructorDecl *Ctor = CCE->getConstructor();
         if (Ctor->isTrivial() && Ctor->isDefaultConstructor() &&
-            VD->getInitStyle() == VarDecl::CallInit) {
+            (VD->getInitStyle() == VarDecl::CallInit ||
+             VD->getInitStyle() == VarDecl::MagicInit)) {
           if (OutDiag)
             InDiag = diag::note_protected_by_variable_nontriv_destructor;
           else if (!Ctor->getParent()->isPOD())
Index: lib/Sema/Sema.cpp
===================================================================
--- lib/Sema/Sema.cpp
+++ lib/Sema/Sema.cpp
@@ -90,7 +90,7 @@
     ExprNeedsCleanups(false), LateTemplateParser(nullptr),
     LateTemplateParserCleanup(nullptr),
     OpaqueParser(nullptr), IdResolver(pp), StdInitializerList(nullptr),
-    CXXTypeInfoDecl(nullptr), MSVCGuidDecl(nullptr),
+    StdARB(nullptr), CXXTypeInfoDecl(nullptr), MSVCGuidDecl(nullptr),
     NSNumberDecl(nullptr),
     NSStringDecl(nullptr), StringWithUTF8StringMethod(nullptr),
     NSArrayDecl(nullptr), ArrayWithObjectsMethod(nullptr),
Index: lib/Sema/SemaDecl.cpp
===================================================================
--- lib/Sema/SemaDecl.cpp
+++ lib/Sema/SemaDecl.cpp
@@ -4478,8 +4478,16 @@
 }
 
 Decl *Sema::ActOnDeclarator(Scope *S, Declarator &D) {
+  Decl *AuxDecl = nullptr;
+  Decl *Result = ActOnDeclarator(S, D, AuxDecl);
+  assert(!AuxDecl && "aux decl not expected here!");
+
+  return Result;
+}
+
+Decl *Sema::ActOnDeclarator(Scope *S, Declarator &D, Decl *&AuxDecl) {
   D.setFunctionDefinitionKind(FDK_Declaration);
-  Decl *Dcl = HandleDeclarator(S, D, MultiTemplateParamsArg());
+  Decl *Dcl = HandleDeclarator(S, D, MultiTemplateParamsArg(), AuxDecl);
 
   if (OriginalLexicalContext && OriginalLexicalContext->isObjCContainer() &&
       Dcl && Dcl->getDeclContext()->isFileContext())
@@ -4605,6 +4613,16 @@
 
 NamedDecl *Sema::HandleDeclarator(Scope *S, Declarator &D,
                                   MultiTemplateParamsArg TemplateParamLists) {
+  Decl *AuxDecl = nullptr;
+  NamedDecl *ND = HandleDeclarator(S, D, TemplateParamLists, AuxDecl);
+  assert(!AuxDecl && "aux decl not expected here");
+
+  return ND;
+}
+
+NamedDecl *Sema::HandleDeclarator(Scope *S, Declarator &D,
+                                  MultiTemplateParamsArg TemplateParamLists,
+                                  Decl *&AuxDecl) {
   // TODO: consider using NameInfo for diagnostic.
   DeclarationNameInfo NameInfo = GetNameForDeclarator(D);
   DeclarationName Name = NameInfo.getName();
@@ -4794,7 +4812,7 @@
                                   AddToScope);
   } else {
     New = ActOnVariableDeclarator(S, D, DC, TInfo, Previous, TemplateParamLists,
-                                  AddToScope);
+                                  AddToScope, AuxDecl);
   }
 
   if (!New)
@@ -5461,11 +5479,60 @@
   return true;
 }
 
+static ClassTemplateDecl *LookupStdARB(Sema &S, SourceLocation Loc){
+  NamespaceDecl *Std = S.getStdNamespace();
+  if (!Std) {
+    S.Diag(Loc, diag::err_implied_std_arb_not_found);
+    return nullptr;
+  }
+
+  LookupResult Result(S, &S.PP.getIdentifierTable().get("arb"),
+                      Loc, Sema::LookupOrdinaryName);
+  if (!S.LookupQualifiedName(Result, Std)) {
+    S.Diag(Loc, diag::err_implied_std_arb_not_found);
+    return nullptr;
+  }
+  ClassTemplateDecl *Template = Result.getAsSingle<ClassTemplateDecl>();
+  if (!Template) {
+    Result.suppressDiagnostics();
+    // We found something weird. Complain about the first thing we found.
+    NamedDecl *Found = *Result.begin();
+    S.Diag(Found->getLocation(), diag::err_malformed_std_arb);
+    return nullptr;
+  }
+
+  // We found some template called std::arb. Now verify that it's
+  // correct.
+  TemplateParameterList *Params = Template->getTemplateParameters();
+  if (Params->getMinRequiredArguments() != 1 ||
+      !isa<TemplateTypeParmDecl>(Params->getParam(0))) {
+    S.Diag(Template->getLocation(), diag::err_malformed_std_arb);
+    return nullptr;
+  }
+
+  return Template;
+}
+
+QualType Sema::BuildStdARB(QualType Element, SourceLocation Loc) {
+  if (!StdARB) {
+    StdARB = LookupStdARB(*this, Loc);
+    if (!StdARB)
+      return QualType();
+  }
+
+  TemplateArgumentListInfo Args(Loc, Loc);
+  Args.addArgument(TemplateArgumentLoc(TemplateArgument(Element),
+                                       Context.getTrivialTypeSourceInfo(Element,
+                                                                        Loc)));
+  return Context.getCanonicalType(
+      CheckTemplateIdType(TemplateName(StdARB), Loc, Args));
+}
+
 NamedDecl *
 Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
                               TypeSourceInfo *TInfo, LookupResult &Previous,
                               MultiTemplateParamsArg TemplateParamLists,
-                              bool &AddToScope) {
+                              bool &AddToScope, Decl *&AuxDecl) {
   QualType R = TInfo->getType();
   DeclarationName Name = GetNameForDeclarator(D).getName();
 
@@ -5704,6 +5771,62 @@
         return nullptr;
       NewVD = cast<VarDecl>(Res.get());
       AddToScope = false;
+    } else if (getLangOpts().FancyARBs && R->isVariableArrayType()) {
+      // If we're using fancy ARBs, create a std::arb object for an ARB instead
+      // of a VLA.
+      const VariableArrayType *VAT = Context.getAsVariableArrayType(R);
+      QualType ARBTy = BuildStdARB(VAT->getElementType(), D.getLocStart());
+      if (!ARBTy.isNull()) {
+        // To get the pointer, we'll create an underlying VLA (this VLA will
+        // actually own the memory and be responsible for managing the lifetime
+        // of the contained objects).
+        UnqualifiedId ARBName;
+        ARBName.setIdentifier(PP.getIdentifierInfo(Name.getAsString() + ".ARB"),
+                              D.getIdentifierLoc());
+        VarDecl *ARBVD =
+          VarDecl::Create(Context, DC, D.getLocStart(), D.getIdentifierLoc(),
+                          PP.getIdentifierInfo(Name.getAsString() + ".ARB"),
+                          R, TInfo, SC);
+        ARBVD->setImplicit();
+        ActOnUninitializedDecl(ARBVD,
+                               D.getDeclSpec().containsPlaceholderType());
+        FinalizeDeclaration(ARBVD);
+
+        ARBVD->setReferenced();
+        ARBVD->markUsed(Context);
+
+        // This must also be attached to the parent group.
+        AuxDecl = ARBVD;
+
+        ExprResult ARBExpRef = BuildDeclRefExpr(ARBVD, R, VK_LValue,
+                                                D.getIdentifierLoc(),
+                                                &D.getCXXScopeSpec());
+
+        R = ARBTy;
+        TInfo = Context.getTrivialTypeSourceInfo(R);
+
+        NewVD = VarDecl::Create(Context, DC, D.getLocStart(),
+                                D.getIdentifierLoc(), II, R, TInfo, SC);
+
+        // We're going to call a private constructor of std::arb.
+        NewVD->setInitStyle(VarDecl::MagicInit);
+
+        Expr *NumElementsExpr = VAT->getSizeExpr();
+
+        // We need to pass to the constructor a pointer to the allocated memory
+        // and the number of allocated elements.
+        SmallVector<Expr*, 2> Exprs(1, ARBExpRef.get());
+
+        // The second parameter is the size.
+        Exprs.push_back(NumElementsExpr);
+
+        ExprResult Initializer =
+          ActOnParenListExpr(D.getLocStart(), SourceLocation(), Exprs);
+        AddInitializerToDecl(NewVD, Initializer.get(), /*DirectInit=*/true,
+                             D.getDeclSpec().containsPlaceholderType());
+      } else
+        NewVD = VarDecl::Create(Context, DC, D.getLocStart(),
+                                D.getIdentifierLoc(), II, R, TInfo, SC);
     } else
       NewVD = VarDecl::Create(Context, DC, D.getLocStart(),
                               D.getIdentifierLoc(), II, R, TInfo, SC);
@@ -8980,7 +9103,9 @@
       return;
 
     InitializationSequence InitSeq(*this, Entity, Kind, Args);
-    ExprResult Result = InitSeq.Perform(*this, Entity, Kind, Args, &DclT);
+    bool NoAccessCheck = VDecl->getInitStyle() == VarDecl::MagicInit;
+    ExprResult Result = InitSeq.Perform(*this, Entity, Kind, Args, &DclT,
+                                        NoAccessCheck);
     if (Result.isInvalid()) {
       VDecl->setInvalidDecl();
       return;
Index: lib/Sema/SemaInit.cpp
===================================================================
--- lib/Sema/SemaInit.cpp
+++ lib/Sema/SemaInit.cpp
@@ -5391,6 +5391,7 @@
                                  bool &ConstructorInitRequiresZeroInit,
                                  bool IsListInitialization,
                                  bool IsStdInitListInitialization,
+                                 bool NoAccessCheck,
                                  SourceLocation LBraceLoc,
                                  SourceLocation RBraceLoc) {
   unsigned NumArgs = Args.size();
@@ -5500,8 +5501,9 @@
     return ExprError();
 
   // Only check access if all of that succeeded.
-  S.CheckConstructorAccess(Loc, Constructor, Entity,
-                           Step.Function.FoundDecl.getAccess());
+  if (!NoAccessCheck)
+    S.CheckConstructorAccess(Loc, Constructor, Entity,
+                             Step.Function.FoundDecl.getAccess());
   if (S.DiagnoseUseOfDecl(Step.Function.FoundDecl, Loc))
     return ExprError();
 
@@ -5879,7 +5881,7 @@
                                 const InitializedEntity &Entity,
                                 const InitializationKind &Kind,
                                 MultiExprArg Args,
-                                QualType *ResultType) {
+                                QualType *ResultType, bool NoAccessCheck) {
   if (Failed()) {
     Diagnose(S, Entity, Kind, Args);
     return ExprError();
@@ -6378,6 +6380,7 @@
                                                ConstructorInitRequiresZeroInit,
                                                /*IsListInitialization*/true,
                                                /*IsStdInitListInit*/false,
+                                               NoAccessCheck,
                                                InitList->getLBraceLoc(),
                                                InitList->getRBraceLoc());
       break;
@@ -6417,6 +6420,7 @@
           ConstructorInitRequiresZeroInit,
           /*IsListInitialization*/IsStdInitListInit,
           /*IsStdInitListInitialization*/IsStdInitListInit,
+          /*NoAccessCheck*/NoAccessCheck,
           /*LBraceLoc*/SourceLocation(),
           /*RBraceLoc*/SourceLocation());
       break;
Index: lib/Sema/SemaTemplateInstantiateDecl.cpp
===================================================================
--- lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -3694,7 +3694,8 @@
     // Instantiate the initializer.
     ExprResult Init =
         SubstInitializer(OldVar->getInit(), TemplateArgs,
-                         OldVar->getInitStyle() == VarDecl::CallInit);
+                         OldVar->getInitStyle() == VarDecl::CallInit ||
+                         OldVar->getInitStyle() == VarDecl::MagicInit);
     if (!Init.isInvalid()) {
       bool TypeMayContainAuto = true;
       Expr *InitExpr = Init.get();
Index: lib/Sema/TreeTransform.h
===================================================================
--- lib/Sema/TreeTransform.h
+++ lib/Sema/TreeTransform.h
@@ -9139,7 +9139,8 @@
                                           Sema::PotentiallyEvaluated);
     ExprResult NewExprInitResult = getDerived().TransformInitializer(
         C->getCapturedVar()->getInit(),
-        C->getCapturedVar()->getInitStyle() == VarDecl::CallInit);
+        C->getCapturedVar()->getInitStyle() == VarDecl::CallInit ||
+        C->getCapturedVar()->getInitStyle() == VarDecl::MagicInit);
 
     if (NewExprInitResult.isInvalid())
       return ExprError();
Index: test/CodeGen/fancy-arbs.cpp
===================================================================
--- /dev/null
+++ test/CodeGen/fancy-arbs.cpp
@@ -0,0 +1,44 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++14 -ffancy-arbs -emit-llvm -o - %s | FileCheck %s
+
+void bar(int *) {
+}
+
+template <typename T>
+int car(const T& c) {
+  return c.size();
+}
+
+void foo(int n) {
+  int q[n];
+  bar(q);
+  car(q);
+
+// CHECK-LABEL: define void @_Z3fooi
+// CHECK: [[ARB:%[0-9a-z]+]] = alloca %"struct.std::__clang_arb_v1::arb"
+// CHECK: [[VLA:%[0-9a-z]+]] = alloca i32, i64 %{{.*}}
+// CHECK: call void @_ZNSt14__clang_arb_v13arbIiEC1EPim(%"struct.std::__clang_arb_v1::arb"* [[ARB]], i32* [[VLA]]
+// CHECK: [[ARBP:%[0-9a-z]+]] = call i32* @_ZNSt14__clang_arb_v13arbIiEcvPiEv(%"struct.std::__clang_arb_v1::arb"* [[ARB]])
+// CHECK: call void @_Z3barPi(i32* [[ARBP]])
+// CHECK: call{{.*}} @_Z3carINSt14__clang_arb_v13arbIiEEEiRKT_(%"struct.std::__clang_arb_v1::arb"* dereferenceable({{[0-9]+}}) [[ARB]]
+}
+
+template <typename T>
+void too(int n) {
+  T q[n];
+  bar(q);
+  car(q);
+}
+
+// CHECK-LABEL: define linkonce_odr void @_Z3tooIiEvi
+// CHECK: [[ARB:%[0-9a-z]+]] = alloca %"struct.std::__clang_arb_v1::arb"
+// CHECK: [[VLA:%[0-9a-z]+]] = alloca i32, i64 %{{.*}}
+// CHECK: call void @_ZNSt14__clang_arb_v13arbIiEC1EPim(%"struct.std::__clang_arb_v1::arb"* [[ARB]], i32* [[VLA]]
+// CHECK: [[ARBP:%[0-9a-z]+]] = call i32* @_ZNSt14__clang_arb_v13arbIiEcvPiEv(%"struct.std::__clang_arb_v1::arb"* [[ARB]])
+// CHECK: call void @_Z3barPi(i32* [[ARBP]])
+// CHECK: call{{.*}} @_Z3carINSt14__clang_arb_v13arbIiEEEiRKT_(%"struct.std::__clang_arb_v1::arb"* dereferenceable({{[0-9]+}}) [[ARB]]
+
+void hello(int size) {
+  foo(size);
+  too<int>(size);
+}
+
_______________________________________________
cfe-commits mailing list
cfe-commits@cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to