Author: rsmith Date: Thu Sep 21 21:25:05 2017 New Revision: 313955 URL: http://llvm.org/viewvc/llvm-project?rev=313955&view=rev Log: Give external linkage and mangling to lambdas inside inline variables and variable templates.
This implements the proposed approach in https://github.com/itanium-cxx-abi/cxx-abi/issues/33 This reinstates r313827, reverted in r313856, with a fix for the 'out-of-bounds enumeration value' ubsan error in that change. Modified: cfe/trunk/lib/AST/Decl.cpp cfe/trunk/lib/AST/ItaniumMangle.cpp cfe/trunk/lib/AST/Linkage.h cfe/trunk/lib/Parse/ParseDecl.cpp cfe/trunk/lib/Sema/SemaDeclCXX.cpp cfe/trunk/lib/Sema/SemaLambda.cpp cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp cfe/trunk/test/CodeGenCXX/mangle-lambdas.cpp cfe/trunk/test/SemaCXX/vartemplate-lambda.cpp cfe/trunk/test/SemaTemplate/instantiate-static-var.cpp Modified: cfe/trunk/lib/AST/Decl.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Decl.cpp?rev=313955&r1=313954&r2=313955&view=diff ============================================================================== --- cfe/trunk/lib/AST/Decl.cpp (original) +++ cfe/trunk/lib/AST/Decl.cpp Thu Sep 21 21:25:05 2017 @@ -554,7 +554,8 @@ static LinkageInfo getExternalLinkageFor LinkageInfo LinkageComputer::getLVForNamespaceScopeDecl(const NamedDecl *D, - LVComputationKind computation) { + LVComputationKind computation, + bool IgnoreVarTypeLinkage) { assert(D->getDeclContext()->getRedeclContext()->isFileContext() && "Not a name having namespace scope"); ASTContext &Context = D->getASTContext(); @@ -611,7 +612,7 @@ LinkageComputer::getLVForNamespaceScopeD // - a data member of an anonymous union. const VarDecl *VD = IFD->getVarDecl(); assert(VD && "Expected a VarDecl in this IndirectFieldDecl!"); - return getLVForNamespaceScopeDecl(VD, computation); + return getLVForNamespaceScopeDecl(VD, computation, IgnoreVarTypeLinkage); } assert(!isa<FieldDecl>(D) && "Didn't expect a FieldDecl!"); @@ -700,7 +701,8 @@ LinkageComputer::getLVForNamespaceScopeD // // Note that we don't want to make the variable non-external // because of this, but unique-external linkage suits us. - if (Context.getLangOpts().CPlusPlus && !isFirstInExternCContext(Var)) { + if (Context.getLangOpts().CPlusPlus && !isFirstInExternCContext(Var) && + !IgnoreVarTypeLinkage) { LinkageInfo TypeLV = getLVForType(*Var->getType(), computation); if (!isExternallyVisible(TypeLV.getLinkage())) return LinkageInfo::uniqueExternal(); @@ -740,15 +742,9 @@ LinkageComputer::getLVForNamespaceScopeD // unique-external linkage, it's not legally usable from outside // this translation unit. However, we should use the C linkage // rules instead for extern "C" declarations. - if (Context.getLangOpts().CPlusPlus && - !Function->isInExternCContext()) { - // Only look at the type-as-written. If this function has an auto-deduced - // return type, we can't compute the linkage of that type because it could - // require looking at the linkage of this function, and we don't need this - // for correctness because the type is not part of the function's - // signature. - // FIXME: This is a hack. We should be able to solve this circularity and - // the one in getLVForClassMember for Functions some other way. + if (Context.getLangOpts().CPlusPlus && !Function->isInExternCContext()) { + // Only look at the type-as-written. Otherwise, deducing the return type + // of a function could change its linkage. QualType TypeAsWritten = Function->getType(); if (TypeSourceInfo *TSI = Function->getTypeSourceInfo()) TypeAsWritten = TSI->getType(); @@ -831,7 +827,8 @@ LinkageComputer::getLVForNamespaceScopeD LinkageInfo LinkageComputer::getLVForClassMember(const NamedDecl *D, - LVComputationKind computation) { + LVComputationKind computation, + bool IgnoreVarTypeLinkage) { // Only certain class members have linkage. Note that fields don't // really have linkage, but it's convenient to say they do for the // purposes of calculating linkage of pointer-to-data-member @@ -889,22 +886,14 @@ LinkageComputer::getLVForClassMember(con const NamedDecl *explicitSpecSuppressor = nullptr; if (const auto *MD = dyn_cast<CXXMethodDecl>(D)) { - // If the type of the function uses a type that has non-externally-visible - // linkage, it's not legally usable from outside this translation unit. - // But only look at the type-as-written. If this function has an - // auto-deduced return type, we can't compute the linkage of that type - // because it could require looking at the linkage of this function, and we - // don't need this for correctness because the type is not part of the - // function's signature. - // FIXME: This is a hack. We should be able to solve this circularity and - // the one in getLVForNamespaceScopeDecl for Functions some other way. - { - QualType TypeAsWritten = MD->getType(); - if (TypeSourceInfo *TSI = MD->getTypeSourceInfo()) - TypeAsWritten = TSI->getType(); - if (!isExternallyVisible(TypeAsWritten->getLinkage())) - return LinkageInfo::uniqueExternal(); - } + // Only look at the type-as-written. Otherwise, deducing the return type + // of a function could change its linkage. + QualType TypeAsWritten = MD->getType(); + if (TypeSourceInfo *TSI = MD->getTypeSourceInfo()) + TypeAsWritten = TSI->getType(); + if (!isExternallyVisible(TypeAsWritten->getLinkage())) + return LinkageInfo::uniqueExternal(); + // If this is a method template specialization, use the linkage for // the template parameters and arguments. if (FunctionTemplateSpecializationInfo *spec @@ -941,10 +930,14 @@ LinkageComputer::getLVForClassMember(con // Modify the variable's linkage by its type, but ignore the // type's visibility unless it's a definition. - LinkageInfo typeLV = getLVForType(*VD->getType(), computation); - if (!LV.isVisibilityExplicit() && !classLV.isVisibilityExplicit()) - LV.mergeVisibility(typeLV); - LV.mergeExternalVisibility(typeLV); + if (!IgnoreVarTypeLinkage) { + LinkageInfo typeLV = getLVForType(*VD->getType(), computation); + // FIXME: If the type's linkage is not externally visible, we can + // give this static data member UniqueExternalLinkage. + if (!LV.isVisibilityExplicit() && !classLV.isVisibilityExplicit()) + LV.mergeVisibility(typeLV); + LV.mergeExternalVisibility(typeLV); + } if (isExplicitMemberSpecialization(VD)) { explicitSpecSuppressor = VD; @@ -1102,22 +1095,33 @@ LinkageInfo LinkageComputer::getLVForClo Decl *ContextDecl, LVComputationKind computation) { // This lambda has its linkage/visibility determined by its owner. + const NamedDecl *Owner; + if (!ContextDecl) + Owner = dyn_cast<NamedDecl>(DC); + else if (isa<ParmVarDecl>(ContextDecl)) + Owner = + dyn_cast<NamedDecl>(ContextDecl->getDeclContext()->getRedeclContext()); + else + Owner = cast<NamedDecl>(ContextDecl); + + // FIXME: If there is no owner, the closure should have no linkage. + if (!Owner) + return LinkageInfo::external(); + + // If the owner has a deduced type, we need to skip querying the linkage and + // visibility of that type, because it might involve this closure type. The + // only effect of this is that we might give a lambda VisibleNoLinkage rather + // than NoLinkage when we don't strictly need to, which is benign. + auto *VD = dyn_cast<VarDecl>(Owner); + LinkageInfo OwnerLinkage = + VD && VD->getType()->getContainedDeducedType() + ? computeLVForDecl(Owner, computation, /*IgnoreVarTypeLinkage*/true) + : getLVForDecl(Owner, computation); + // FIXME: This is wrong. A lambda never formally has linkage; if this - // calculation determines the lambda has external linkage, it should be + // calculation determines a lambda has external linkage, it should be // downgraded to VisibleNoLinkage. - if (ContextDecl) { - if (isa<ParmVarDecl>(ContextDecl)) - DC = ContextDecl->getDeclContext()->getRedeclContext(); - else - return getLVForDecl(cast<NamedDecl>(ContextDecl), computation); - } - - if (const auto *ND = dyn_cast<NamedDecl>(DC)) - return getLVForDecl(ND, computation); - - // FIXME: We have a closure at TU scope with no context declaration. This - // should probably have no linkage. - return LinkageInfo::external(); + return OwnerLinkage; } LinkageInfo LinkageComputer::getLVForLocalDecl(const NamedDecl *D, @@ -1215,7 +1219,8 @@ getOutermostEnclosingLambda(const CXXRec } LinkageInfo LinkageComputer::computeLVForDecl(const NamedDecl *D, - LVComputationKind computation) { + LVComputationKind computation, + bool IgnoreVarTypeLinkage) { // Internal_linkage attribute overrides other considerations. if (D->hasAttr<InternalLinkageAttr>()) return getInternalLinkageFor(D); @@ -1303,7 +1308,7 @@ LinkageInfo LinkageComputer::computeLVFo // Handle linkage for namespace-scope names. if (D->getDeclContext()->getRedeclContext()->isFileContext()) - return getLVForNamespaceScopeDecl(D, computation); + return getLVForNamespaceScopeDecl(D, computation, IgnoreVarTypeLinkage); // C++ [basic.link]p5: // In addition, a member function, static data member, a named @@ -1313,7 +1318,7 @@ LinkageInfo LinkageComputer::computeLVFo // purposes (7.1.3), has external linkage if the name of the class // has external linkage. if (D->getDeclContext()->isRecord()) - return getLVForClassMember(D, computation); + return getLVForClassMember(D, computation, IgnoreVarTypeLinkage); // C++ [basic.link]p6: // The name of a function declared in block scope and the name of Modified: cfe/trunk/lib/AST/ItaniumMangle.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ItaniumMangle.cpp?rev=313955&r1=313954&r2=313955&view=diff ============================================================================== --- cfe/trunk/lib/AST/ItaniumMangle.cpp (original) +++ cfe/trunk/lib/AST/ItaniumMangle.cpp Thu Sep 21 21:25:05 2017 @@ -1691,10 +1691,16 @@ void CXXNameMangler::mangleLambda(const // to emit that last part of the prefix here. if (Decl *Context = Lambda->getLambdaContextDecl()) { if ((isa<VarDecl>(Context) || isa<FieldDecl>(Context)) && - Context->getDeclContext()->isRecord()) { + !isa<ParmVarDecl>(Context)) { + // FIXME: 'inline auto [a, b] = []{ return ... };' does not get a + // reasonable mangling here. if (const IdentifierInfo *Name = cast<NamedDecl>(Context)->getIdentifier()) { mangleSourceName(Name); + const TemplateArgumentList *TemplateArgs = nullptr; + if (const TemplateDecl *TD = + isTemplate(cast<NamedDecl>(Context), TemplateArgs)) + mangleTemplateArgs(*TemplateArgs); Out << 'M'; } } Modified: cfe/trunk/lib/AST/Linkage.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Linkage.h?rev=313955&r1=313954&r2=313955&view=diff ============================================================================== --- cfe/trunk/lib/AST/Linkage.h (original) +++ cfe/trunk/lib/AST/Linkage.h Thu Sep 21 21:25:05 2017 @@ -117,10 +117,12 @@ class LinkageComputer { LVComputationKind computation); LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, - LVComputationKind computation); + LVComputationKind computation, + bool IgnoreVarTypeLinkage); LinkageInfo getLVForClassMember(const NamedDecl *D, - LVComputationKind computation); + LVComputationKind computation, + bool IgnoreVarTypeLinkage); LinkageInfo getLVForClosure(const DeclContext *DC, Decl *ContextDecl, LVComputationKind computation); @@ -135,7 +137,8 @@ class LinkageComputer { public: LinkageInfo computeLVForDecl(const NamedDecl *D, - LVComputationKind computation); + LVComputationKind computation, + bool IgnoreVarTypeLinkage = false); LinkageInfo getLVForDecl(const NamedDecl *D, LVComputationKind computation); Modified: cfe/trunk/lib/Parse/ParseDecl.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=313955&r1=313954&r2=313955&view=diff ============================================================================== --- cfe/trunk/lib/Parse/ParseDecl.cpp (original) +++ cfe/trunk/lib/Parse/ParseDecl.cpp Thu Sep 21 21:25:05 2017 @@ -2131,6 +2131,37 @@ Decl *Parser::ParseDeclarationAfterDecla Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes( Declarator &D, const ParsedTemplateInfo &TemplateInfo, ForRangeInit *FRI) { + // RAII type used to track whether we're inside an initializer. + struct InitializerScopeRAII { + Parser &P; + Declarator &D; + Decl *ThisDecl; + + InitializerScopeRAII(Parser &P, Declarator &D, Decl *ThisDecl) + : P(P), D(D), ThisDecl(ThisDecl) { + if (ThisDecl && P.getLangOpts().CPlusPlus) { + Scope *S = nullptr; + if (D.getCXXScopeSpec().isSet()) { + P.EnterScope(0); + S = P.getCurScope(); + } + P.Actions.ActOnCXXEnterDeclInitializer(S, ThisDecl); + } + } + ~InitializerScopeRAII() { pop(); } + void pop() { + if (ThisDecl && P.getLangOpts().CPlusPlus) { + Scope *S = nullptr; + if (D.getCXXScopeSpec().isSet()) + S = P.getCurScope(); + P.Actions.ActOnCXXExitDeclInitializer(S, ThisDecl); + if (S) + P.ExitScope(); + } + ThisDecl = nullptr; + } + }; + // Inform the current actions module that we just parsed this declarator. Decl *ThisDecl = nullptr; switch (TemplateInfo.Kind) { @@ -2208,10 +2239,7 @@ Decl *Parser::ParseDeclarationAfterDecla else Diag(ConsumeToken(), diag::err_default_special_members); } else { - if (getLangOpts().CPlusPlus && D.getCXXScopeSpec().isSet()) { - EnterScope(0); - Actions.ActOnCXXEnterDeclInitializer(getCurScope(), ThisDecl); - } + InitializerScopeRAII InitScope(*this, D, ThisDecl); if (Tok.is(tok::code_completion)) { Actions.CodeCompleteInitializer(getCurScope(), ThisDecl); @@ -2234,10 +2262,7 @@ Decl *Parser::ParseDeclarationAfterDecla FRI->RangeExpr = Init; } - if (getLangOpts().CPlusPlus && D.getCXXScopeSpec().isSet()) { - Actions.ActOnCXXExitDeclInitializer(getCurScope(), ThisDecl); - ExitScope(); - } + InitScope.pop(); if (Init.isInvalid()) { SmallVector<tok::TokenKind, 2> StopTokens; @@ -2259,10 +2284,7 @@ Decl *Parser::ParseDeclarationAfterDecla ExprVector Exprs; CommaLocsTy CommaLocs; - if (getLangOpts().CPlusPlus && D.getCXXScopeSpec().isSet()) { - EnterScope(0); - Actions.ActOnCXXEnterDeclInitializer(getCurScope(), ThisDecl); - } + InitializerScopeRAII InitScope(*this, D, ThisDecl); llvm::function_ref<void()> ExprListCompleter; auto ThisVarDecl = dyn_cast_or_null<VarDecl>(ThisDecl); @@ -2283,11 +2305,6 @@ Decl *Parser::ParseDeclarationAfterDecla if (ParseExpressionList(Exprs, CommaLocs, ExprListCompleter)) { Actions.ActOnInitializerError(ThisDecl); SkipUntil(tok::r_paren, StopAtSemi); - - if (getLangOpts().CPlusPlus && D.getCXXScopeSpec().isSet()) { - Actions.ActOnCXXExitDeclInitializer(getCurScope(), ThisDecl); - ExitScope(); - } } else { // Match the ')'. T.consumeClose(); @@ -2295,10 +2312,7 @@ Decl *Parser::ParseDeclarationAfterDecla assert(!Exprs.empty() && Exprs.size()-1 == CommaLocs.size() && "Unexpected number of commas!"); - if (getLangOpts().CPlusPlus && D.getCXXScopeSpec().isSet()) { - Actions.ActOnCXXExitDeclInitializer(getCurScope(), ThisDecl); - ExitScope(); - } + InitScope.pop(); ExprResult Initializer = Actions.ActOnParenListExpr(T.getOpenLocation(), T.getCloseLocation(), @@ -2311,17 +2325,11 @@ Decl *Parser::ParseDeclarationAfterDecla // Parse C++0x braced-init-list. Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists); - if (D.getCXXScopeSpec().isSet()) { - EnterScope(0); - Actions.ActOnCXXEnterDeclInitializer(getCurScope(), ThisDecl); - } + InitializerScopeRAII InitScope(*this, D, ThisDecl); ExprResult Init(ParseBraceInitializer()); - if (D.getCXXScopeSpec().isSet()) { - Actions.ActOnCXXExitDeclInitializer(getCurScope(), ThisDecl); - ExitScope(); - } + InitScope.pop(); if (Init.isInvalid()) { Actions.ActOnInitializerError(ThisDecl); Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=313955&r1=313954&r2=313955&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original) +++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Thu Sep 21 21:25:05 2017 @@ -14256,21 +14256,22 @@ void Sema::ActOnPureSpecifier(Decl *D, S Diag(D->getLocation(), diag::err_illegal_initializer); } -/// \brief Determine whether the given declaration is a static data member. -static bool isStaticDataMember(const Decl *D) { +/// \brief Determine whether the given declaration is a global variable or +/// static data member. +static bool isNonlocalVariable(const Decl *D) { if (const VarDecl *Var = dyn_cast_or_null<VarDecl>(D)) - return Var->isStaticDataMember(); + return Var->hasGlobalStorage(); return false; } -/// ActOnCXXEnterDeclInitializer - Invoked when we are about to parse -/// an initializer for the out-of-line declaration 'Dcl'. The scope -/// is a fresh scope pushed for just this purpose. +/// Invoked when we are about to parse an initializer for the declaration +/// 'Dcl'. /// /// After this method is called, according to [C++ 3.4.1p13], if 'Dcl' is a /// static data member of class X, names should be looked up in the scope of -/// class X. +/// class X. If the declaration had a scope specifier, a scope will have +/// been created and passed in for this purpose. Otherwise, S will be null. void Sema::ActOnCXXEnterDeclInitializer(Scope *S, Decl *D) { // If there is no declaration, there was an error parsing it. if (!D || D->isInvalidDecl()) @@ -14280,28 +14281,27 @@ void Sema::ActOnCXXEnterDeclInitializer( // might not be out of line if the specifier names the current namespace: // extern int n; // int ::n = 0; - if (D->isOutOfLine()) + if (S && D->isOutOfLine()) EnterDeclaratorContext(S, D->getDeclContext()); // If we are parsing the initializer for a static data member, push a // new expression evaluation context that is associated with this static // data member. - if (isStaticDataMember(D)) + if (isNonlocalVariable(D)) PushExpressionEvaluationContext( ExpressionEvaluationContext::PotentiallyEvaluated, D); } -/// ActOnCXXExitDeclInitializer - Invoked after we are finished parsing an -/// initializer for the out-of-line declaration 'D'. +/// Invoked after we are finished parsing an initializer for the declaration D. void Sema::ActOnCXXExitDeclInitializer(Scope *S, Decl *D) { // If there is no declaration, there was an error parsing it. if (!D || D->isInvalidDecl()) return; - if (isStaticDataMember(D)) + if (isNonlocalVariable(D)) PopExpressionEvaluationContext(); - if (D->isOutOfLine()) + if (S && D->isOutOfLine()) ExitDeclaratorContext(S); } Modified: cfe/trunk/lib/Sema/SemaLambda.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaLambda.cpp?rev=313955&r1=313954&r2=313955&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaLambda.cpp (original) +++ cfe/trunk/lib/Sema/SemaLambda.cpp Thu Sep 21 21:25:05 2017 @@ -288,7 +288,9 @@ Sema::getCurrentMangleNumberContext(cons Normal, DefaultArgument, DataMember, - StaticDataMember + StaticDataMember, + InlineVariable, + VariableTemplate } Kind = Normal; // Default arguments of member function parameters that appear in a class @@ -303,6 +305,14 @@ Sema::getCurrentMangleNumberContext(cons } else if (VarDecl *Var = dyn_cast<VarDecl>(ManglingContextDecl)) { if (Var->getDeclContext()->isRecord()) Kind = StaticDataMember; + else if (Var->getMostRecentDecl()->isInline()) + Kind = InlineVariable; + else if (Var->getDescribedVarTemplate()) + Kind = VariableTemplate; + else if (auto *VTS = dyn_cast<VarTemplateSpecializationDecl>(Var)) { + if (!VTS->isExplicitSpecialization()) + Kind = VariableTemplate; + } } else if (isa<FieldDecl>(ManglingContextDecl)) { Kind = DataMember; } @@ -343,6 +353,10 @@ Sema::getCurrentMangleNumberContext(cons // -- the in-class initializers of class members case DefaultArgument: // -- default arguments appearing in class definitions + case InlineVariable: + // -- the initializers of inline variables + case VariableTemplate: + // -- the initializers of templated variables return &ExprEvalContexts.back().getMangleNumberingContext(Context); } Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=313955&r1=313954&r2=313955&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original) +++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Thu Sep 21 21:25:05 2017 @@ -4140,12 +4140,8 @@ void Sema::InstantiateVariableInitialize Var->setImplicitlyInline(); if (OldVar->getInit()) { - if (Var->isStaticDataMember() && !OldVar->isOutOfLine()) - PushExpressionEvaluationContext( - Sema::ExpressionEvaluationContext::ConstantEvaluated, OldVar); - else - PushExpressionEvaluationContext( - Sema::ExpressionEvaluationContext::PotentiallyEvaluated, OldVar); + EnterExpressionEvaluationContext Evaluated( + *this, Sema::ExpressionEvaluationContext::PotentiallyEvaluated, Var); // Instantiate the initializer. ExprResult Init; @@ -4173,8 +4169,6 @@ void Sema::InstantiateVariableInitialize // because of a bogus initializer. Var->setInvalidDecl(); } - - PopExpressionEvaluationContext(); } else { if (Var->isStaticDataMember()) { if (!Var->isOutOfLine()) Modified: cfe/trunk/test/CodeGenCXX/mangle-lambdas.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/mangle-lambdas.cpp?rev=313955&r1=313954&r2=313955&view=diff ============================================================================== --- cfe/trunk/test/CodeGenCXX/mangle-lambdas.cpp (original) +++ cfe/trunk/test/CodeGenCXX/mangle-lambdas.cpp Thu Sep 21 21:25:05 2017 @@ -26,6 +26,24 @@ void call_inline_func() { inline_func(17); } +// CHECK-LABEL: define linkonce_odr i32* @_ZNK10inline_varMUlvE_clEv( +// CHECK: @_ZZNK10inline_varMUlvE_clEvE1n +inline auto inline_var = [] { + static int n = 5; + return &n; +}; + +int *use_inline_var = inline_var(); + +// CHECK-LABEL: define linkonce_odr i32* @_ZNK12var_templateIiEMUlvE_clEv( +// CHECK: @_ZZNK12var_templateIiEMUlvE_clEvE1n +template<typename T> auto var_template = [] { + static int n = 9; + return &n; +}; + +int *use_var_template = var_template<int>(); + struct S { void f(int = []{return 1;}() + []{return 2;}(), @@ -118,7 +136,7 @@ T StaticMembers<T>::z = accept_lambda([] template<typename T> int (*StaticMembers<T>::f)() = []{return 5;}; -// CHECK-LABEL: define internal void @__cxx_global_var_init() +// CHECK-LABEL: define internal void @__cxx_global_var_init // CHECK: call i32 @_ZNK13StaticMembersIfE1xMUlvE_clEv // CHECK-NEXT: call i32 @_ZNK13StaticMembersIfE1xMUlvE0_clEv // CHECK-NEXT: add nsw @@ -128,23 +146,23 @@ int (*StaticMembers<T>::f)() = []{return // CHECK: ret i32 2 template float StaticMembers<float>::x; -// CHECK-LABEL: define internal void @__cxx_global_var_init.1() +// CHECK-LABEL: define internal void @__cxx_global_var_init // CHECK: call i32 @_ZNK13StaticMembersIfE1yMUlvE_clEv // CHECK-LABEL: define linkonce_odr i32 @_ZNK13StaticMembersIfE1yMUlvE_clEv // CHECK: ret i32 3 template float StaticMembers<float>::y; -// CHECK-LABEL: define internal void @__cxx_global_var_init.2() +// CHECK-LABEL: define internal void @__cxx_global_var_init // CHECK: call i32 @_Z13accept_lambdaIN13StaticMembersIfE1zMUlvE_EEiT_ // CHECK: declare i32 @_Z13accept_lambdaIN13StaticMembersIfE1zMUlvE_EEiT_() template float StaticMembers<float>::z; -// CHECK-LABEL: define internal void @__cxx_global_var_init.3() +// CHECK-LABEL: define internal void @__cxx_global_var_init // CHECK: call {{.*}} @_ZNK13StaticMembersIfE1fMUlvE_cvPFivEEv // CHECK-LABEL: define linkonce_odr i32 ()* @_ZNK13StaticMembersIfE1fMUlvE_cvPFivEEv template int (*StaticMembers<float>::f)(); -// CHECK-LABEL: define internal void @__cxx_global_var_init.4 +// CHECK-LABEL: define internal void @__cxx_global_var_init // CHECK: call i32 @"_ZNK13StaticMembersIdE3$_2clEv" // CHECK-LABEL: define internal i32 @"_ZNK13StaticMembersIdE3$_2clEv" // CHECK: ret i32 42 Modified: cfe/trunk/test/SemaCXX/vartemplate-lambda.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/vartemplate-lambda.cpp?rev=313955&r1=313954&r2=313955&view=diff ============================================================================== --- cfe/trunk/test/SemaCXX/vartemplate-lambda.cpp (original) +++ cfe/trunk/test/SemaCXX/vartemplate-lambda.cpp Thu Sep 21 21:25:05 2017 @@ -8,7 +8,7 @@ template<typename T> auto v1 = [](int a struct S { template<class T> - static constexpr T t = [](int f = T(7)){return f;}(); // expected-error{{constexpr variable 't<int>' must be initialized by a constant expression}} expected-error{{a lambda expression may not appear inside of a constant expression}} expected-note{{cannot be used in a constant expression}} + static constexpr T t = [](int f = T(7)){return f;}(); // expected-error{{constexpr variable 't<int>' must be initialized by a constant expression}} expected-note{{cannot be used in a constant expression}} }; template <typename X> Modified: cfe/trunk/test/SemaTemplate/instantiate-static-var.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/instantiate-static-var.cpp?rev=313955&r1=313954&r2=313955&view=diff ============================================================================== --- cfe/trunk/test/SemaTemplate/instantiate-static-var.cpp (original) +++ cfe/trunk/test/SemaTemplate/instantiate-static-var.cpp Thu Sep 21 21:25:05 2017 @@ -5,7 +5,7 @@ template<typename T, T Divisor> class X { public: - static const T value = 10 / Divisor; // expected-error{{in-class initializer for static data member is not a constant expression}} + static const T value = 10 / Divisor; // expected-error{{in-class initializer for static data member is not a constant expression}} expected-warning {{division by zero}} }; int array1[X<int, 2>::value == 5? 1 : -1]; _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits