Doubt about Decl::getDeclContext()

I've just noted that unexpectedly (at least for me) getDeclContext()
applied to an extern VarDecl returns the FunctionDecl instead of the

int f() {
  extern int a;

Is this expected or a symptom of a bug?

The documentation say that getDeclContext() should return the semantic
DC of the declaration and I was using this to get the decl of parent
object of the declared object.

Should I do something different?

Expected; even though "a" is a global in the sense of linkage, it
isn't actually part of the global scope. It is only visible within
the function "f".


This means that in this source:

int f() {
  extern int a;
int a;

for the two declarations getDeclContext() returns two different results
and that D->getCanonicalDecl()->getDeclContext() could return a
different result from D->getDeclContext().

But once understood that the so called "semantic" context is the
"lookup" context everything might be fine, *but* if I extend your
definition above I don't understand why a block scoped variable has the
full function as its Decl Context, also if it is only visible inside its

That apart, do we have a way to get the declaration context of the
declared entity i.e. something that is consistent for each redeclaration
and refers to the parent scope of the declared entity?

I agree with Abramo that the semantic DC here should be the translation unit.
There's probably a non-trivial amount of code assuming otherwise, but that
code can be fixed.


I've attached a candidate incomplete patch for your review and comments.

The semantic DC of an extern local variable I've assumed is either the
translation unit or the first linkage specification ancestor or the
first namespace ancestor. In this last case if there is a C linkage
specification as ancestor of the namespace this node is used instead of
the namespace.

Probably I'd have preferred to have the TranslationUnit as semantic DC
for extern C VarDecl (so to have always the same semantic DC for every
declaration of the same variable) and to never have linkage specificaton
as semantic DC, but this would break implementation of
VarDecl::isExternC() that is based on semantic DC and I've not seen an
alternative way to implement it.

The patch passes all tests, but:

Failing Tests (3):
    Clang :: CodeGenCXX/mangle.cpp
    Clang :: Index/usrs.m
    Clang :: Sema/vla.c

The failure in CodeGenCXX/mangle.cpp is related to differences between C
and C++ about this kind of code (illegal in C while legal in C++)

int f() {
  extern int i;
  return i;

static int i;

I've failed to understand the failure in Index/usrs.m probably because
my relative ignorance about Objective C

The failure in Sema/vla.c is due to modified diagnostic

error: 'error' diagnostics expected but not seen:
  Line 22: variable length array declaration can not have 'extern' linkage
  Line 38: variable length array declaration can not have 'extern' linkage
  Line 40: variably modified type declaration can not have 'extern' linkage
error: 'error' diagnostics seen but not expected:
  Line 22: variable length array declaration not allowed at file scope
  Line 38: variable length array declaration not allowed at file scope
  Line 40: variably modified type declaration not allowed at file scope

but I think to prefer the new one to the old.

LocalExternDeclContext.patch (4.62 KB)