[PATCH] Sema: Instantiate local class and their members appropriately
Richard Smith
richard at metafoo.co.uk
Wed Nov 20 17:10:01 PST 2013
Thanks, it'll be great to finally have this bug closed.
================
Comment at: lib/Sema/SemaTemplateInstantiate.cpp:2503-2506
@@ -2496,2 +2502,6 @@
- InstantiateFunctionDefinition(PointOfInstantiation, Function);
+ if (TSK == TSK_ImplicitInstantiation)
+ PendingLocalImplicitInstantiations.push_back(
+ std::make_pair(Function, PointOfInstantiation));
+ else
+ InstantiateFunctionDefinition(PointOfInstantiation, Function);
----------------
Might be clearer to move this into the `else` below? The `Pattern->isDefined()` check and associated comment don't apply here.
================
Comment at: lib/Sema/SemaTemplateInstantiateDecl.cpp:671-672
@@ -659,4 +670,4 @@
- if (D->getDeclContext()->isFunctionOrMethod())
+ if (isDeclWithinFunction(D))
SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, Enum);
----------------
I would expect we need to do this iff we call `InstantiateEnumDefinition`. In all other cases, it'll be done by the caller; we need to push `D` into the `CurrentInstantiationScope` if (and only if) we might instantiate something ourselves that references the enumeration type.
================
Comment at: lib/Sema/SemaTemplateInstantiateDecl.cpp:726-727
@@ -725,4 +735,3 @@
- if (Pattern->getDeclContext()->isFunctionOrMethod() &&
- !Enum->isScoped()) {
// If the enumeration is within a function or method, record the enum
----------------
Is this change necessary? If the enumerator is within a local class, we should (and should be able to) find it by name lookup in the instantiation of the class, rather than through the current instantiation scope.
================
Comment at: lib/Sema/SemaTemplateInstantiateDecl.cpp:1140-1151
@@ -1130,1 +1139,14 @@
+
+ if (CXXRecordDecl *Def = D->getDefinition()) {
+ if (Def->isLocalClass()) {
+ if (SemaRef.InstantiateClass(D->getLocation(), Record, Def, TemplateArgs,
+ TSK_ImplicitInstantiation,
+ /*Complain=*/true)) {
+ llvm_unreachable("InstantiateClass shouldn't fail here!");
+ } else {
+ SemaRef.InstantiateClassMembers(D->getLocation(), Record, TemplateArgs,
+ TSK_ImplicitInstantiation);
+ }
+ }
+ }
return Record;
----------------
I think we should only do this if `D` is the definition. If we have:
template<typename T> void f() {
struct X; // #1
struct X {}; // #2
}
we should instantiate X when we get to #2, not when we get to #1. This is probably even detectable with something like:
template<typename T> void f() {
struct X;
int k = X().n;
struct X { int n; };
}
This is ill-formed, but Clang (and GCC, as it happens) accepts-invalid on it. (I expect we'll still accept-valid even with your patch, because we'll trigger the instantiation of X() on the second line rather than the first/third, but it's a step in the right direction.)
================
Comment at: test/CXX/temp/temp.spec/temp.inst/p1.cpp:36-38
@@ -35,5 +35,5 @@
// The behavior for enums defined within function templates is not clearly
// specified by the standard. We follow the rules for enums defined within
// class templates.
template<typename T>
----------------
Please update this comment to refer to core issue 1484, which explains the rules here.
================
Comment at: test/SemaCXX/local-classes.cpp:1
@@ -1,2 +1,2 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s
// expected-no-diagnostics
----------------
We have a whole bunch of examples on the PRs for this bug; please include a few more of them here.
http://llvm-reviews.chandlerc.com/D2236
More information about the cfe-commits
mailing list