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