forked from OSchip/llvm-project
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. llvm-svn: 313955
This commit is contained in:
parent
83e2838d03
commit
c95d2c5dda
|
@ -554,7 +554,8 @@ static LinkageInfo getExternalLinkageFor(const NamedDecl *D) {
|
|||
|
||||
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::getLVForNamespaceScopeDecl(const NamedDecl *D,
|
|||
// - 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::getLVForNamespaceScopeDecl(const NamedDecl *D,
|
|||
//
|
||||
// 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::getLVForNamespaceScopeDecl(const NamedDecl *D,
|
|||
// 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::getLVForNamespaceScopeDecl(const NamedDecl *D,
|
|||
|
||||
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(const NamedDecl *D,
|
|||
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(const NamedDecl *D,
|
|||
|
||||
// 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::getLVForClosure(const DeclContext *DC,
|
|||
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 CXXRecordDecl *Record) {
|
|||
}
|
||||
|
||||
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::computeLVForDecl(const NamedDecl *D,
|
|||
|
||||
// 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::computeLVForDecl(const NamedDecl *D,
|
|||
// 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
|
||||
|
|
|
@ -1691,10 +1691,16 @@ void CXXNameMangler::mangleLambda(const CXXRecordDecl *Lambda) {
|
|||
// 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';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -2131,6 +2131,37 @@ Decl *Parser::ParseDeclarationAfterDeclarator(
|
|||
|
||||
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::ParseDeclarationAfterDeclaratorAndAttributes(
|
|||
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::ParseDeclarationAfterDeclaratorAndAttributes(
|
|||
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::ParseDeclarationAfterDeclaratorAndAttributes(
|
|||
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::ParseDeclarationAfterDeclaratorAndAttributes(
|
|||
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::ParseDeclarationAfterDeclaratorAndAttributes(
|
|||
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::ParseDeclarationAfterDeclaratorAndAttributes(
|
|||
// 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);
|
||||
|
|
|
@ -14256,21 +14256,22 @@ void Sema::ActOnPureSpecifier(Decl *D, SourceLocation ZeroLoc) {
|
|||
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(Scope *S, Decl *D) {
|
|||
// 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);
|
||||
}
|
||||
|
||||
|
|
|
@ -288,7 +288,9 @@ Sema::getCurrentMangleNumberContext(const DeclContext *DC,
|
|||
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(const DeclContext *DC,
|
|||
} 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(const DeclContext *DC,
|
|||
// -- 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);
|
||||
}
|
||||
|
||||
|
|
|
@ -4140,12 +4140,8 @@ void Sema::InstantiateVariableInitializer(
|
|||
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::InstantiateVariableInitializer(
|
|||
// because of a bogus initializer.
|
||||
Var->setInvalidDecl();
|
||||
}
|
||||
|
||||
PopExpressionEvaluationContext();
|
||||
} else {
|
||||
if (Var->isStaticDataMember()) {
|
||||
if (!Var->isOutOfLine())
|
||||
|
|
|
@ -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([]{return 4;});
|
|||
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 5;};
|
|||
// 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
|
||||
|
|
|
@ -8,7 +8,7 @@ template<typename T> auto v1 = [](int a = T(1)) { return 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>
|
||||
|
|
|
@ -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];
|
||||
|
|
Loading…
Reference in New Issue