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();
// - 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!");
//
// 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();
// 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();
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
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
// 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;
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,
}
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);
// 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
// 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
// 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';
}
}
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);
public:
LinkageInfo computeLVForDecl(const NamedDecl *D,
- LVComputationKind computation);
+ LVComputationKind computation,
+ bool IgnoreVarTypeLinkage = false);
LinkageInfo getLVForDecl(const NamedDecl *D, LVComputationKind computation);
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) {
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);
FRI->RangeExpr = Init;
}
- if (getLangOpts().CPlusPlus && D.getCXXScopeSpec().isSet()) {
- Actions.ActOnCXXExitDeclInitializer(getCurScope(), ThisDecl);
- ExitScope();
- }
+ InitScope.pop();
if (Init.isInvalid()) {
SmallVector<tok::TokenKind, 2> StopTokens;
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);
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();
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(),
// 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);
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())
// 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);
}
Normal,
DefaultArgument,
DataMember,
- StaticDataMember
+ StaticDataMember,
+ InlineVariable,
+ VariableTemplate
} Kind = Normal;
// Default arguments of member function parameters that appear in a class
} 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;
}
// -- 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);
}
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;
// because of a bogus initializer.
Var->setInvalidDecl();
}
-
- PopExpressionEvaluationContext();
} else {
if (Var->isStaticDataMember()) {
if (!Var->isOutOfLine())
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;}(),
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
// 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
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>
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];