aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.def4
-rw-r--r--lib/Sema/Sema.h2
-rw-r--r--lib/Sema/SemaCXXScopeSpec.cpp30
-rw-r--r--lib/Sema/SemaDecl.cpp2
-rw-r--r--lib/Sema/SemaExpr.cpp2
-rw-r--r--lib/Sema/SemaLookup.cpp2
-rw-r--r--lib/Sema/SemaTemplateInstantiate.cpp35
-rw-r--r--test/SemaCXX/nested-name-spec.cpp8
-rw-r--r--test/SemaTemplate/instantiate-typedef.cpp15
9 files changed, 95 insertions, 5 deletions
diff --git a/include/clang/Basic/DiagnosticSemaKinds.def b/include/clang/Basic/DiagnosticSemaKinds.def
index 4589a97350..2c024de380 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.def
+++ b/include/clang/Basic/DiagnosticSemaKinds.def
@@ -231,6 +231,10 @@ DIAG(error_property_implemented, ERROR,
DIAG(warn_objc_property_attr_mutually_exclusive, WARNING,
"property attributes '%0' and '%1' are mutually exclusive")
+// C++ name lookup
+DIAG(err_incomplete_nested_name_spec, ERROR,
+ "incomplete type %0 named in nested name specifier")
+
// C++ class members
DIAG(err_storageclass_invalid_for_member, ERROR,
"storage class specified for a member declaration")
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index b3669bc74d..2e02004113 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -1394,6 +1394,8 @@ public:
TypeTy *Ty,
SourceLocation RParen);
+ bool RequireCompleteDeclContext(const CXXScopeSpec &SS);
+
/// ActOnCXXGlobalScopeSpecifier - Return the object that represents the
/// global scope ('::').
virtual CXXScopeTy *ActOnCXXGlobalScopeSpecifier(Scope *S,
diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp
index c8a86cfd7d..7773d288ae 100644
--- a/lib/Sema/SemaCXXScopeSpec.cpp
+++ b/lib/Sema/SemaCXXScopeSpec.cpp
@@ -17,6 +17,36 @@
#include "llvm/ADT/STLExtras.h"
using namespace clang;
+/// \brief Require that the context specified by SS be complete.
+///
+/// If SS refers to a type, this routine checks whether the type is
+/// complete enough (or can be made complete enough) for name lookup
+/// into the DeclContext. A type that is not yet completed can be
+/// considered "complete enough" if it is a class/struct/union/enum
+/// that is currently being defined. Or, if we have a type that names
+/// a class template specialization that is not a complete type, we
+/// will attempt to instantiate that class template.
+bool Sema::RequireCompleteDeclContext(const CXXScopeSpec &SS) {
+ if (!SS.isSet() || SS.isInvalid())
+ return false;
+
+ DeclContext *DC = static_cast<DeclContext *>(SS.getScopeRep());
+ if (TagDecl *Tag = dyn_cast<TagDecl>(DC)) {
+ // If we're currently defining this type, then lookup into the
+ // type is okay: don't complain that it isn't complete yet.
+ const TagType *TagT = Context.getTypeDeclType(Tag)->getAsTagType();
+ if (TagT->isBeingDefined())
+ return false;
+
+ // The type must be complete.
+ return RequireCompleteType(SS.getRange().getBegin(),
+ Context.getTypeDeclType(Tag),
+ diag::err_incomplete_nested_name_spec,
+ SS.getRange());
+ }
+
+ return false;
+}
/// ActOnCXXGlobalScopeSpecifier - Return the object that represents the
/// global scope ('::').
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 35573bb33d..03d00b83a3 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -1255,6 +1255,7 @@ Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl,
D.getIdentifierLoc());
} else { // Something like "int foo::x;"
DC = static_cast<DeclContext*>(D.getCXXScopeSpec().getScopeRep());
+ // FIXME: RequireCompleteDeclContext(D.getCXXScopeSpec()); ?
PrevDecl = LookupQualifiedName(DC, Name, LookupOrdinaryName, true);
// C++ 7.3.1.2p2:
@@ -2895,6 +2896,7 @@ Sema::DeclTy *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagKind TK,
goto CreateNewDecl;
}
+ // FIXME: RequireCompleteDeclContext(SS)?
DC = static_cast<DeclContext*>(SS.getScopeRep());
SearchDC = DC;
// Look-up name inside 'foo::'.
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 9a86d65f9a..95c0baae56 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -4344,6 +4344,8 @@ Sema::ExprResult Sema::ActOnBuiltinOffsetOf(Scope *S,
if (!Dependent && !ArgTy->isRecordType())
return Diag(TypeLoc, diag::err_offsetof_record_type) << ArgTy;
+ // FIXME: Does the type need to be complete?
+
// Otherwise, create a null pointer as the base, and iteratively process
// the offsetof designators.
QualType ArgTyPtr = Context.getPointerType(ArgTy);
diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp
index dd9c850d08..a93689c9a0 100644
--- a/lib/Sema/SemaLookup.cpp
+++ b/lib/Sema/SemaLookup.cpp
@@ -1035,7 +1035,7 @@ Sema::LookupParsedName(Scope *S, const CXXScopeSpec *SS,
bool RedeclarationOnly, bool AllowBuiltinCreation,
SourceLocation Loc) {
if (SS) {
- if (SS->isInvalid())
+ if (SS->isInvalid() || RequireCompleteDeclContext(*SS))
return LookupResult::CreateLookupResult(Context, 0);
if (SS->isSet())
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index 21694b2e73..d630e801b0 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -655,13 +655,44 @@ Sema::InstantiateClassTemplateSpecialization(
// Start the definition of this instantiation.
ClassTemplateSpec->startDefinition();
- // FIXME: Create the injected-class-name for the
- // instantiation. Should this be a typedef or something like it?
// Instantiate the base class specifiers.
if (InstantiateBaseSpecifiers(ClassTemplateSpec, Template))
Invalid = true;
+ // FIXME: Create the injected-class-name for the
+ // instantiation. Should this be a typedef or something like it?
+
+ RecordDecl *Pattern = Template->getTemplatedDecl();
+
+ for (RecordDecl::decl_iterator Member = Pattern->decls_begin(),
+ MemberEnd = Pattern->decls_end();
+ Member != MemberEnd; ++Member) {
+ if (TypedefDecl *Typedef = dyn_cast<TypedefDecl>(*Member)) {
+ // FIXME: Simplified instantiation of typedefs needs to be made
+ // "real".
+ QualType T = Typedef->getUnderlyingType();
+ if (T->isDependentType()) {
+ T = InstantiateType(T, ClassTemplateSpec->getTemplateArgs(),
+ ClassTemplateSpec->getNumTemplateArgs(),
+ Typedef->getLocation(),
+ Typedef->getDeclName());
+ if (T.isNull()) {
+ Invalid = true;
+ T = Context.IntTy;
+ }
+ }
+
+ // Create the new typedef
+ TypedefDecl *New
+ = TypedefDecl::Create(Context, ClassTemplateSpec,
+ Typedef->getLocation(),
+ Typedef->getIdentifier(),
+ T);
+ ClassTemplateSpec->addDecl(New);
+ }
+ }
+
// FIXME: Instantiate all of the members.
// Add any implicitly-declared members that we might need.
diff --git a/test/SemaCXX/nested-name-spec.cpp b/test/SemaCXX/nested-name-spec.cpp
index 2b6de3363b..f75b279a44 100644
--- a/test/SemaCXX/nested-name-spec.cpp
+++ b/test/SemaCXX/nested-name-spec.cpp
@@ -1,5 +1,4 @@
-// RUN: clang -fsyntax-only -verify -std=c++98 %s
-// fails due to exact diagnostic matching
+// RUN: clang -fsyntax-only -std=c++98 -verify %s
namespace A {
struct C {
static int cx;
@@ -151,5 +150,10 @@ void ::global_func2(int) { } // expected-error{{definition or redeclaration of '
void N::f() { } // okay
+struct Y; // expected-note{{forward declaration of 'struct Y'}}
+Y::foo y; // expected-error{{incomplete type 'struct Y' named in nested name specifier}} \
+ // FIXME: ugly: expected-error{{invalid token after top level declarator}}
+
X::X() : a(5) { } // expected-error{{use of undeclared identifier 'X'}} \
// expected-error{{expected function body after function declarator}}
+
diff --git a/test/SemaTemplate/instantiate-typedef.cpp b/test/SemaTemplate/instantiate-typedef.cpp
new file mode 100644
index 0000000000..8ecee50502
--- /dev/null
+++ b/test/SemaTemplate/instantiate-typedef.cpp
@@ -0,0 +1,15 @@
+// RUN: clang -fsyntax-only -verify %s
+
+template<typename T>
+struct add_pointer {
+ typedef T* type; // expected-error{{'type' declared as a pointer to a reference}}
+};
+
+add_pointer<int>::type test1(int * ptr) { return ptr; }
+
+add_pointer<float>::type test2(int * ptr) {
+ return ptr; // expected-error{{incompatible type returning 'int *', expected 'type' (aka 'float *')}}
+}
+
+add_pointer<int&>::type // expected-note{{in instantiation of template class 'struct add_pointer<int &>' requested here}}
+test3(); // FIXME: expected-error{{invalid token after top level declarator}}