Skip to content

Commit 649ba4c

Browse files
committed
[clang][AST] enforce the unbraced extern <lang> invariant
Quoting 9.11.8: > A declaration directly contained in a linkage-specification is > treated as if it contains the extern specifier (9.2.2) for the > purpose of determining the linkage of the declared name and whether > it is a definition. Such a declaration shall not specify a storage > class. So, the invariant is that function and variable declarations within an unbraced language linkage specification have `StorageClass` set to `SC_None`. Problem: in several places the invariant was broken. Solution: remove the explicit `SC_Extern` specification. Note, that my changes result in the `extern` being implicit in some functions that are not contained in a language linkage specification.
1 parent 24ee56b commit 649ba4c

File tree

5 files changed

+26
-10
lines changed

5 files changed

+26
-10
lines changed

clang/lib/AST/Decl.cpp

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -576,13 +576,16 @@ template <typename T> static bool isFirstInExternCContext(T *D) {
576576
return First->isInExternCContext();
577577
}
578578

579-
static bool isSingleLineLanguageLinkage(const Decl &D) {
580-
if (const auto *SD = dyn_cast<LinkageSpecDecl>(D.getDeclContext()))
581-
if (!SD->hasBraces())
582-
return true;
579+
static bool isUnbracedLanguageLinkage(const DeclContext *DC) {
580+
if (const auto *SD = dyn_cast_if_present<LinkageSpecDecl>(DC))
581+
return !SD->hasBraces();
583582
return false;
584583
}
585584

585+
static bool hasUnbracedLanguageLinkage(const Decl &D) {
586+
return isUnbracedLanguageLinkage(D.getDeclContext());
587+
}
588+
586589
static bool isDeclaredInModuleInterfaceOrPartition(const NamedDecl *D) {
587590
if (auto *M = D->getOwningModule())
588591
return M->isInterfaceOrPartition();
@@ -651,7 +654,7 @@ LinkageComputer::getLVForNamespaceScopeDecl(const NamedDecl *D,
651654

652655
if (Var->getStorageClass() != SC_Extern &&
653656
Var->getStorageClass() != SC_PrivateExtern &&
654-
!isSingleLineLanguageLinkage(*Var))
657+
!hasUnbracedLanguageLinkage(*Var))
655658
return LinkageInfo::internal();
656659
}
657660

@@ -2125,6 +2128,12 @@ VarDecl::VarDecl(Kind DK, ASTContext &C, DeclContext *DC,
21252128
"ParmVarDeclBitfields too large!");
21262129
static_assert(sizeof(NonParmVarDeclBitfields) <= sizeof(unsigned),
21272130
"NonParmVarDeclBitfields too large!");
2131+
2132+
// The unbraced `extern "C"` invariant is that the storage class
2133+
// specifier is omitted in the source code, i.e. SC_None (but is,
2134+
// implicitly, `extern`).
2135+
assert(!isUnbracedLanguageLinkage(DC) || SC == SC_None);
2136+
21282137
AllBits = 0;
21292138
VarDeclBits.SClass = SC;
21302139
// Everything else is implicitly initialized to false.
@@ -2308,7 +2317,7 @@ VarDecl::isThisDeclarationADefinition(ASTContext &C) const {
23082317
// A declaration directly contained in a linkage-specification is treated
23092318
// as if it contains the extern specifier for the purpose of determining
23102319
// the linkage of the declared name and whether it is a definition.
2311-
if (isSingleLineLanguageLinkage(*this))
2320+
if (hasUnbracedLanguageLinkage(*this))
23122321
return DeclarationOnly;
23132322

23142323
// C99 6.9.2p2:
@@ -3034,6 +3043,12 @@ FunctionDecl::FunctionDecl(Kind DK, ASTContext &C, DeclContext *DC,
30343043
DeclContext(DK), redeclarable_base(C), Body(), ODRHash(0),
30353044
EndRangeLoc(NameInfo.getEndLoc()), DNLoc(NameInfo.getInfo()) {
30363045
assert(T.isNull() || T->isFunctionType());
3046+
3047+
// The unbraced `extern "C"` invariant is that the storage class
3048+
// specifier is omitted in the source code, i.e. SC_None (but is,
3049+
// implicitly, `extern`).
3050+
assert(!isUnbracedLanguageLinkage(DC) || S == SC_None);
3051+
30373052
FunctionDeclBits.SClass = S;
30383053
FunctionDeclBits.IsInline = isInlineSpecified;
30393054
FunctionDeclBits.IsInlineSpecified = isInlineSpecified;

clang/lib/Sema/SemaDecl.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2302,7 +2302,7 @@ FunctionDecl *Sema::CreateBuiltin(IdentifierInfo *II, QualType Type,
23022302
}
23032303

23042304
FunctionDecl *New = FunctionDecl::Create(
2305-
Context, Parent, Loc, Loc, II, Type, /*TInfo=*/nullptr, SC_Extern,
2305+
Context, Parent, Loc, Loc, II, Type, /*TInfo=*/nullptr, SC_None,
23062306
getCurFPFeatures().isFPConstrained(), /*isInlineSpecified=*/false,
23072307
Type->isFunctionProtoType(), ConstexprKind);
23082308
New->setImplicit();

clang/lib/Sema/SemaExpr.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6196,7 +6196,7 @@ static FunctionDecl *rewriteBuiltinFunctionDecl(Sema *Sema, ASTContext &Context,
61966196
FunctionDecl *OverloadDecl = FunctionDecl::Create(
61976197
Context, Parent, FDecl->getLocation(), FDecl->getLocation(),
61986198
FDecl->getIdentifier(), OverloadTy,
6199-
/*TInfo=*/nullptr, SC_Extern, Sema->getCurFPFeatures().isFPConstrained(),
6199+
/*TInfo=*/nullptr, SC_None, Sema->getCurFPFeatures().isFPConstrained(),
62006200
false,
62016201
/*hasPrototype=*/true);
62026202
SmallVector<ParmVarDecl*, 16> Params;

lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -932,7 +932,7 @@ class CodeComplete : public CodeCompleteConsumer {
932932
else
933933
ToInsert += "(";
934934
raw_string_ostream OS(Description);
935-
F->print(OS, m_desc_policy, false);
935+
F->print(OS, m_desc_policy);
936936
OS.flush();
937937
} else if (const VarDecl *V = dyn_cast<VarDecl>(D)) {
938938
Description = V->getType().getAsString(m_desc_policy);

lldb/source/Plugins/ExpressionParser/Clang/NameSearchContext.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,8 @@ clang::NamedDecl *NameSearchContext::AddFunDecl(const CompilerType &type,
7777

7878
clang::FunctionDecl *func_decl = FunctionDecl::Create(
7979
ast, context, SourceLocation(), SourceLocation(), decl_name, qual_type,
80-
nullptr, SC_Extern, /*UsesFPIntrin=*/false, isInlineSpecified, hasWrittenPrototype,
80+
nullptr, SC_None, /*UsesFPIntrin=*/false, isInlineSpecified,
81+
hasWrittenPrototype,
8182
isConstexprSpecified ? ConstexprSpecKind::Constexpr
8283
: ConstexprSpecKind::Unspecified);
8384

0 commit comments

Comments
 (0)