diff --git a/llvm/docs/TableGen/ProgRef.rst b/llvm/docs/TableGen/ProgRef.rst --- a/llvm/docs/TableGen/ProgRef.rst +++ b/llvm/docs/TableGen/ProgRef.rst @@ -1360,15 +1360,23 @@ In addition to defining global variables, the ``defvar`` statement can be used inside the :token:`Body` of a class or record definition to define -local variables. The scope of the variable extends from the ``defvar`` -statement to the end of the body. It cannot be set to a different value -within its scope. The ``defvar`` statement can also be used in the statement +local variables. Template arguments of ``class`` or ``multiclass`` can be +used in the value expression. The scope of the variable extends from the +``defvar`` statement to the end of the body. It cannot be set to a different +value within its scope. The ``defvar`` statement can also be used in the statement list of a ``foreach``, which establishes a scope. A variable named ``V`` in an inner scope shadows (hides) any variables ``V`` -in outer scopes. In particular, ``V`` in a record body shadows a global -``V``, and ``V`` in a ``foreach`` statement list shadows any ``V`` in -surrounding record or global scopes. +in outer scopes. In particular, there are several cases: + +* ``V`` in a record body shadows a global ``V``. + +* ``V`` in a record body shadows template argument ``V``. + +* ``V`` in template arguments shadows a global ``V``. + +* ``V`` in a ``foreach`` statement list shadows any ``V`` in surrounding record or + global scopes. Variables defined in a ``foreach`` go out of scope at the end of each loop iteration, so their value in one iteration is not available in diff --git a/llvm/lib/TableGen/TGParser.h b/llvm/lib/TableGen/TGParser.h --- a/llvm/lib/TableGen/TGParser.h +++ b/llvm/lib/TableGen/TGParser.h @@ -93,12 +93,12 @@ return std::move(parent); } - Init *getVar(StringRef Name) const { + Init *getVar(StringRef Name, bool FindInParent) const { auto It = vars.find(Name); if (It != vars.end()) return It->second; - if (parent) - return parent->getVar(Name); + if (FindInParent && parent) + return parent->getVar(Name, true); return nullptr; } diff --git a/llvm/lib/TableGen/TGParser.cpp b/llvm/lib/TableGen/TGParser.cpp --- a/llvm/lib/TableGen/TGParser.cpp +++ b/llvm/lib/TableGen/TGParser.cpp @@ -903,6 +903,13 @@ } } + // We try to find the ID defined in current local scope only first. + if (CurLocalScope) + if (Init *I = + CurLocalScope->getVar(Name->getValue(), /* FindInParent*/ false)) + return I; + + // The ID is a class/multiclass template argument? if ((CurRec && CurRec->isClass()) || CurMultiClass) { Init *TemplateArgName; if (CurMultiClass) { @@ -924,8 +931,10 @@ } } + // Then, we try to find the ID defined in parent local scope. if (CurLocalScope) - if (Init *I = CurLocalScope->getVar(Name->getValue())) + if (Init *I = + CurLocalScope->getVar(Name->getValue(), /* FindInParent*/ true)) return I; // If this is in a foreach loop, make sure it's not a loop iterator diff --git a/llvm/test/TableGen/defvar.td b/llvm/test/TableGen/defvar.td --- a/llvm/test/TableGen/defvar.td +++ b/llvm/test/TableGen/defvar.td @@ -18,18 +18,6 @@ defvar myvar = "another value"; #endif -// These variables should be overrided by template arguments. -defvar a = 2333; -defvar b = 2333; -class VarScopeTest { - defvar c = !add(a, b); - int value = !add(c, c); -} - -// CHECK: def aaa_scope_test { -// CHECK-NEXT: int value = 10; -def aaa_scope_test: VarScopeTest<2, 3>; - multiclass Test { // Refer to a global variable, while inside a local scope like a multiclass. def _with_global_string { string s = myvar; } @@ -146,6 +134,25 @@ def shadowOuterBelowIf # first { int var = shadowedVariable; } } +// These variables should be shadowed by class/multiclass template arguments. +defvar a = 2333; +defvar b = 2333; +defvar c = 2333; +class ClassShadowTest { + // template argument 'c' has higher priority than global variable 'c' . + int value = !add(c, c); +} + +multiclass MulticlassShadowTest { + // local variable 'c' has higher priority than template argument 'c'. + defvar c = !add(a, b); + def "": ClassShadowTest; +} + +// CHECK: def shadowTemplateArg { +// CHECK-NEXT: int value = 10; +defm shadowTemplateArg: MulticlassShadowTest<2, 3, 3>; + // Test that a top-level let statement also makes a variable scope (on the // general principle of consistency, because it defines a braced sub-block).