]> granicus.if.org Git - clang/commitdiff
Introduce a representation for types that we referred to via a
authorDouglas Gregor <dgregor@apple.com>
Thu, 19 Mar 2009 00:18:19 +0000 (00:18 +0000)
committerDouglas Gregor <dgregor@apple.com>
Thu, 19 Mar 2009 00:18:19 +0000 (00:18 +0000)
qualified name, e.g.,

  foo::x

so that we retain the nested-name-specifier as written in the source
code and can reproduce that qualified name when printing the types
back (e.g., in diagnostics). This is PR3493, which won't be complete
until finished the other tasks mentioned near the end of this commit.

The parser's representation of nested-name-specifiers, CXXScopeSpec,
is now a bit fatter, because it needs to contain the scopes that
precede each '::' and keep track of whether the global scoping
operator '::' was at the beginning. For example, we need to keep track
of the leading '::', 'foo', and 'bar' in

  ::foo::bar::x

The Action's CXXScopeTy * is no longer a DeclContext *. It's now the
opaque version of the new NestedNameSpecifier, which contains a single
component of a nested-name-specifier (either a DeclContext * or a Type
*, bitmangled).

The new sugar type QualifiedNameType composes a sequence of
NestedNameSpecifiers with a representation of the type we're actually
referring to. At present, we only build QualifiedNameType nodes within
Sema::getTypeName. This will be extended to other type-constructing
actions (e.g., ActOnClassTemplateId).

Also on the way: QualifiedDeclRefExprs will also store a sequence of
NestedNameSpecifiers, so that we can print out the property
nested-name-specifier. I expect to also use this for handling
dependent names like Fibonacci<I - 1>::value.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@67265 91177308-0d34-0410-b5e6-96231b3b80d8

26 files changed:
include/clang/AST/ASTContext.h
include/clang/AST/NestedNameSpecifier.h [new file with mode: 0644]
include/clang/AST/Type.h
include/clang/AST/TypeNodes.def
include/clang/Parse/DeclSpec.h
lib/AST/ASTContext.cpp
lib/AST/CMakeLists.txt
lib/AST/NestedNameSpecifier.cpp [new file with mode: 0644]
lib/AST/Type.cpp
lib/AST/TypeSerialization.cpp
lib/CodeGen/CGDebugInfo.cpp
lib/Parse/DeclSpec.cpp
lib/Parse/ParseDecl.cpp
lib/Parse/ParseExprCXX.cpp
lib/Parse/Parser.cpp
lib/Sema/Sema.h
lib/Sema/SemaCXXScopeSpec.cpp
lib/Sema/SemaDecl.cpp
lib/Sema/SemaDeclCXX.cpp
lib/Sema/SemaExpr.cpp
lib/Sema/SemaLookup.cpp
lib/Sema/SemaTemplate.cpp
lib/Sema/SemaTemplateInstantiate.cpp
lib/Sema/SemaType.cpp
test/SemaCXX/qualified-names-diag.cpp [new file with mode: 0644]
test/SemaTemplate/instantiate-typedef.cpp

index 124f7db449c3dcbec02a78ee7d507c358fa81888..f4df88c94c484422b6de5b72cef285d59a50df3c 100644 (file)
@@ -72,6 +72,7 @@ class ASTContext {
   llvm::FoldingSet<TemplateTypeParmType> TemplateTypeParmTypes;
   llvm::FoldingSet<ClassTemplateSpecializationType> 
     ClassTemplateSpecializationTypes;
+  llvm::FoldingSet<QualifiedNameType> QualifiedNameTypes;
   llvm::FoldingSet<ObjCQualifiedInterfaceType> ObjCQualifiedInterfaceTypes;
   llvm::FoldingSet<ObjCQualifiedIdType> ObjCQualifiedIdTypes;
   /// ASTRecordLayouts - A cache mapping from RecordDecls to ASTRecordLayouts.
@@ -284,6 +285,10 @@ public:
                                               unsigned NumArgs,
                                               QualType Canon = QualType());
 
+  QualType getQualifiedNameType(const NestedNameSpecifier *Components,
+                                unsigned NumComponents,
+                                QualType NamedType);
+
   /// getObjCQualifiedInterfaceType - Return a 
   /// ObjCQualifiedInterfaceType type for the given interface decl and
   /// the conforming protocol list.
diff --git a/include/clang/AST/NestedNameSpecifier.h b/include/clang/AST/NestedNameSpecifier.h
new file mode 100644 (file)
index 0000000..cdf04b0
--- /dev/null
@@ -0,0 +1,111 @@
+//===--- NestedNameSpecifier.h - C++ nested name specifiers -----*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+//  This file defines the NestedNameSpecifier class, which represents
+//  a C++ nested-name-specifier.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_AST_NESTEDNAMESPECIFIER_H
+#define LLVM_CLANG_AST_NESTEDNAMESPECIFIER_H
+
+#include "llvm/Support/DataTypes.h"
+#include <cassert>
+
+namespace clang {
+
+class ASTContext;
+class DeclContext;
+class Type;
+
+/// \brief Represents a single component in a C++ nested-name-specifier.
+///
+/// C++ nested-name-specifiers are the prefixes to qualified
+/// namespaces. For example, "foo::" in "foo::x" is a
+/// nested-name-specifier. Multiple nested-name-specifiers can be
+/// strung together to build qualified names, e.g., "foo::bar::" in
+/// "foo::bar::x". Each NestedNameSpecifier class contains one of the
+/// terms, e.g., "foo::" or "bar::", which may be represented either
+/// as a type or as a DeclContext.
+class NestedNameSpecifier {
+  /// \brief A DeclContext or Type pointer, depending on whether the
+  /// low bit is set.
+  uintptr_t Data;
+
+public:
+  NestedNameSpecifier() : Data(0) { }
+
+  /// \brief Construct a nested name specifier that refers to a type.
+  NestedNameSpecifier(const Type *T) { 
+    Data = reinterpret_cast<uintptr_t>(T);
+    assert((Data & 0x01) == 0 && "cv-qualified type in nested-name-specifier");
+    Data |= 0x01;
+  }
+
+  /// \brief Construct nested name specifier that refers to a
+  /// DeclContext.
+  NestedNameSpecifier(const DeclContext *DC) {
+    Data = reinterpret_cast<uintptr_t>(DC);
+    assert((Data & 0x01) == 0 && "Badly aligned DeclContext pointer");
+  }
+
+  /// \brief Determines whether this nested-name-specifier refers to a
+  /// type. Otherwise, it refers to a DeclContext.
+  bool isType() const { return Data & 0x01; }
+
+  /// \brief Compute the declaration context to which this
+  /// nested-name-specifier refers.
+  ///
+  /// This routine computes the declaration context referenced by this
+  /// nested-name-specifier. The nested-name-specifier may store
+  /// either a DeclContext (the trivial case) or a non-dependent type
+  /// (which will have an associated DeclContext). It is an error to
+  /// invoke this routine when the nested-name-specifier refers to a
+  /// dependent type.
+  ///
+  /// \returns The stored DeclContext, if the nested-name-specifier
+  /// stores a DeclContext. If the nested-name-specifier stores a
+  /// non-dependent type, returns the DeclContext associated with that
+  /// type.
+  DeclContext *computeDeclContext(ASTContext &Context) const;
+
+  /// \brief Retrieve the nested-name-specifier as a type. 
+  ///
+  /// \returns The stored type. If the nested-name-specifier does not
+  /// store a type, returns NULL.
+  Type *getAsType() const {
+    if (Data & 0x01)
+      return reinterpret_cast<Type *>(Data & ~0x01);
+
+    return 0;
+  }
+
+  /// \brief Retrieves the nested-name-specifier as a DeclContext.
+  ///
+  /// \returns The stored DeclContext. If the nested-name-specifier
+  /// does not store a DeclContext, returns NULL.
+  DeclContext *getAsDeclContext() const {
+    if (Data & 0x01)
+      return 0;
+    return reinterpret_cast<DeclContext *>(Data);
+  }
+
+  /// \brief Retrieve nested name specifier as an opaque pointer.
+  void *getAsOpaquePtr() const { return reinterpret_cast<void *>(Data); }
+
+  /// \brief Reconstruct a nested name specifier from an opaque pointer.
+  static NestedNameSpecifier getFromOpaquePtr(void *Ptr) {
+    NestedNameSpecifier NS;
+    NS.Data = reinterpret_cast<uintptr_t>(Ptr);
+    return NS;
+  }
+};
+
+}
+
+#endif
index 94368b707dc2935a69200588f97f9f45b35798d5..b4e609dc3b872a0e89db970ff6116347b58dcac1 100644 (file)
@@ -15,6 +15,7 @@
 #define LLVM_CLANG_AST_TYPE_H
 
 #include "clang/Basic/Diagnostic.h"
+#include "clang/AST/NestedNameSpecifier.h"
 #include "llvm/Support/Casting.h"
 #include "llvm/ADT/APSInt.h"
 #include "llvm/ADT/FoldingSet.h"
@@ -47,6 +48,7 @@ namespace clang {
   class SourceLocation;
   class StmtIteratorBase;
   class TemplateArgument;
+  class QualifiedNameType;
 
   // Provide forward declarations for all of the *Type classes
 #define TYPE(Class, Base) class Class##Type;
@@ -1357,7 +1359,9 @@ public:
   void setBeingDefined(bool Def) { decl.setInt(Def? 1 : 0); }
 
   virtual void getAsStringInternal(std::string &InnerString) const;
-  
+  void getAsStringInternal(std::string &InnerString,
+                           bool SuppressTagKind) const;
+
   static bool classof(const Type *T) { 
     return T->getTypeClass() >= TagFirst && T->getTypeClass() <= TagLast;
   }
@@ -1548,6 +1552,64 @@ protected:
   friend class Type;
 };
 
+/// \brief Represents a type that was referred to via a qualified
+/// name, e.g., N::M::type.
+///
+/// This type is used to keep track of a type name as written in the
+/// source code, including any nested-name-specifiers.
+class QualifiedNameType : public Type, public llvm::FoldingSetNode {
+  /// \brief The number of components in the qualified name, not
+  /// counting the final type.
+  unsigned NumComponents;
+
+  /// \brief The type that this qualified name refers to.
+  QualType NamedType;
+
+  QualifiedNameType(const NestedNameSpecifier *Components,
+                    unsigned NumComponents, QualType NamedType,
+                    QualType CanonType);
+
+  friend class ASTContext;  // ASTContext creates these
+
+public:
+  typedef const NestedNameSpecifier * iterator;
+
+  iterator begin() const { return getComponents(); }
+  iterator end() const { return getComponents() + getNumComponents(); }
+
+  /// \brief Retrieve the array of nested-name-specifier components.
+  const NestedNameSpecifier *getComponents() const { 
+    return reinterpret_cast<const NestedNameSpecifier *>(this + 1);
+  }
+
+  /// \brief Retrieve the number of nested-name-specifier components.
+  unsigned getNumComponents() const { return NumComponents; }
+
+  /// \brief Retrieve the type named by the qualified-id.
+  QualType getNamedType() const { return NamedType; }
+
+  virtual void getAsStringInternal(std::string &InnerString) const;
+
+  void Profile(llvm::FoldingSetNodeID &ID) {
+    Profile(ID, getComponents(), NumComponents, NamedType);
+  }
+
+  static void Profile(llvm::FoldingSetNodeID &ID, 
+                      const NestedNameSpecifier *Components,
+                      unsigned NumComponents, 
+                      QualType NamedType);
+
+  static bool classof(const Type *T) { 
+    return T->getTypeClass() == QualifiedName; 
+  }
+  static bool classof(const QualifiedNameType *T) { return true; }
+
+protected:
+  virtual void EmitImpl(llvm::Serializer& S) const;
+  static Type* CreateImpl(ASTContext& Context, llvm::Deserializer& D);
+  friend class Type;
+};
+
 /// ObjCInterfaceType - Interfaces are the core concept in Objective-C for
 /// object oriented design.  They basically correspond to C++ classes.  There
 /// are two kinds of interface types, normal interfaces like "NSString" and
index 4c5c02d2a550bc52f5ee186bb6f91e6162c9dc9b..e1e79aab53f07f857ac62987a7abe865a3543eef 100644 (file)
@@ -73,6 +73,7 @@ TYPE(Record, TagType)
 TYPE(Enum, TagType)
 DEPENDENT_TYPE(TemplateTypeParm, Type)
 NON_CANONICAL_TYPE(ClassTemplateSpecialization, Type)
+NON_CANONICAL_TYPE(QualifiedName, Type)
 TYPE(ObjCInterface, Type)
 TYPE(ObjCQualifiedInterface, ObjCInterfaceType)
 TYPE(ObjCQualifiedId, Type)
index 3c6995e50bf02d105ddd8a27ad1777508edb5bc1..9c19a1a2d5b0ae23365cf3516c74c12a98548f42 100644 (file)
@@ -397,10 +397,36 @@ private:
 /// specifier.
 class CXXScopeSpec {
   SourceRange Range;
-  Action::CXXScopeTy *ScopeRep;
+
+  /// Storage containing the scope representations for up to four
+  /// levels of nested-name-specifier. NumScopeReps specifiers how
+  /// many levels there are. If there are more than four, we use
+  /// ManyScopeReps.
+  Action::CXXScopeTy *InlineScopeReps[4];
+
+  /// The number of scope representations we've stored.
+  unsigned NumScopeReps;
+
+  /// The number of scope representations we can store without
+  /// allocating new memory.
+  unsigned Capacity;
+
+  // If there are > 4 scope representations, a pointer to those scope
+  // representations.
+  Action::CXXScopeTy **ManyScopeReps;
+
+  void reallocate();
 
 public:
-  CXXScopeSpec() : ScopeRep(0) {}
+  CXXScopeSpec() : NumScopeReps(0), Capacity(4) { }
+
+  CXXScopeSpec(const CXXScopeSpec &SS);
+
+  CXXScopeSpec &operator=(const CXXScopeSpec &SS);
+
+  ~CXXScopeSpec() {
+    clear();
+  }
 
   const SourceRange &getRange() const { return Range; }
   void setRange(const SourceRange &R) { Range = R; }
@@ -409,21 +435,82 @@ public:
   SourceLocation getBeginLoc() const { return Range.getBegin(); }
   SourceLocation getEndLoc() const { return Range.getEnd(); }
 
-  Action::CXXScopeTy *getScopeRep() const { return ScopeRep; }
-  void setScopeRep(Action::CXXScopeTy *S) { ScopeRep = S; }
+  typedef Action::CXXScopeTy * const * iterator;
+
+  iterator begin() const { 
+    if (NumScopeReps > 4)
+      return ManyScopeReps;
+    else
+      return &InlineScopeReps[0];
+  }
+
+  iterator end() const { 
+    return begin() + NumScopeReps;
+  }
+
+  Action::CXXScopeTy *getScopeRep(unsigned I) const {
+    assert(I < size() && "Out-of-range scope index");
+    return begin()[I];
+  }
+  unsigned size() const { return NumScopeReps; }
+
+  void addScopeRep(Action::CXXScopeTy *S) {
+    if (!S)
+      return;
+
+    if (NumScopeReps >= Capacity)
+      reallocate();
+
+    if (Capacity == 4)
+      InlineScopeReps[NumScopeReps++] = S;
+    else
+      ManyScopeReps[NumScopeReps++] = S;
+  }
+
+  Action::CXXScopeTy *getCurrentScopeRep() const { 
+    if (size() == 0)
+      return 0;
+    return begin()[size() - 1];
+  }
+
+  void setScopeRep(Action::CXXScopeTy *S) { 
+    if (Capacity > 4)
+      delete [] ManyScopeReps;
+    Capacity = 4;
+    NumScopeReps = 0;
+    addScopeRep(S);
+  }
 
   bool isEmpty() const { return !Range.isValid(); }
   bool isNotEmpty() const { return !isEmpty(); }
 
   /// isInvalid - An error occured during parsing of the scope specifier.
-  bool isInvalid() const { return isNotEmpty() && ScopeRep == 0; }
+  bool isInvalid() const { return isNotEmpty() && NumScopeReps == 0; }
 
   /// isSet - A scope specifier was resolved to a valid C++ scope.
-  bool isSet() const { return getScopeRep() != 0; }
+  bool isSet() const { return getCurrentScopeRep() != 0; }
 
   void clear() {
     Range = SourceRange();
-    ScopeRep = 0;
+    if (NumScopeReps > 4) 
+      delete [] ManyScopeReps;
+    NumScopeReps = 0;
+    Capacity = 4;
+  }
+
+  /// \brief Allocate and build the information that will be attached
+  /// to a scope-annotation token.
+  void *buildAnnotationData() const;
+
+  /// \brief Reconstruct a scope specifier from the annotation data. 
+  ///
+  /// This routine does not free the annotation data; call
+  /// freeAnnotationData for that.
+  void setFromAnnotationData(void *Data);
+
+  /// Frees the annotation data.
+  static void freeAnnotationData(void *Data) { 
+    delete [] (uintptr_t *) Data; 
   }
 };
   
index c318107dab324479d2954ca23a195794c4f8282f..c5441dd3041bccfa03e8308aab1430f6367f3626 100644 (file)
@@ -1375,6 +1375,29 @@ ASTContext::getClassTemplateSpecializationType(TemplateDecl *Template,
   return QualType(Spec, 0);  
 }
 
+QualType 
+ASTContext::getQualifiedNameType(const NestedNameSpecifier *Components,
+                                 unsigned NumComponents,
+                                 QualType NamedType) {
+  llvm::FoldingSetNodeID ID;
+  QualifiedNameType::Profile(ID, Components, NumComponents, NamedType);
+
+  void *InsertPos = 0;
+  QualifiedNameType *T 
+    = QualifiedNameTypes.FindNodeOrInsertPos(ID, InsertPos);
+  if (T)
+    return QualType(T, 0);
+
+  void *Mem = Allocate((sizeof(QualifiedNameType) +
+                        sizeof(NestedNameSpecifier) * NumComponents), 
+                       8);
+  T = new (Mem) QualifiedNameType(Components, NumComponents, NamedType,
+                                  getCanonicalType(NamedType));
+  Types.push_back(T);
+  QualifiedNameTypes.InsertNode(T, InsertPos);
+  return QualType(T, 0);
+}
+
 /// CmpProtocolNames - Comparison predicate for sorting protocols
 /// alphabetically.
 static bool CmpProtocolNames(const ObjCProtocolDecl *LHS,
index 48b19711127ba3abea19ad93c1617ec2522d26c3..5ea7a47fd6028af4f56e0cf48dd195a6c5ada984 100644 (file)
@@ -18,6 +18,7 @@ add_clang_library(clangAST
   Expr.cpp
   ExprCXX.cpp
   InheritViz.cpp
+  NestedNameSpecifier.cpp
   ParentMap.cpp
   Stmt.cpp
   StmtDumper.cpp
diff --git a/lib/AST/NestedNameSpecifier.cpp b/lib/AST/NestedNameSpecifier.cpp
new file mode 100644 (file)
index 0000000..318c05f
--- /dev/null
@@ -0,0 +1,34 @@
+//===--- NestedNameSpecifier.cpp - C++ nested name specifiers -----*- C++ -*-=//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+//  This file defines the NestedNameSpecifier class, which represents
+//  a C++ nested-name-specifier.
+//
+//===----------------------------------------------------------------------===//
+#include "clang/AST/NestedNameSpecifier.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/Type.h"
+using namespace clang;
+
+DeclContext *
+NestedNameSpecifier::computeDeclContext(ASTContext &Context) const {
+  // The simple case: we're storing a DeclContext
+  if ((Data & 0x01) == 0)
+    return reinterpret_cast<DeclContext *>(Data);
+
+  Type *T = getAsType();
+  if (!T)
+    return 0;
+
+  // Retrieve the DeclContext associated with this type.
+  const TagType *TagT = T->getAsTagType();
+  assert(TagT && "No DeclContext from a non-tag type");
+  return TagT->getDecl();
+}
index bb3df0882ff836fc8f858f8ad31ab8e5cff02688..b066802c67abf99bcfe71cd0ba4b3370f800d9dd 100644 (file)
@@ -96,6 +96,8 @@ QualType Type::getDesugaredType() const {
   if (const ClassTemplateSpecializationType *Spec 
         = dyn_cast<ClassTemplateSpecializationType>(this))
     return Spec->getCanonicalTypeInternal().getDesugaredType();
+  if (const QualifiedNameType *QualName  = dyn_cast<QualifiedNameType>(this))
+    return QualName->getNamedType().getDesugaredType();
 
   // FIXME: remove this cast.
   return QualType(const_cast<Type*>(this), 0);
@@ -1045,6 +1047,28 @@ ClassTemplateSpecializationType::Profile(llvm::FoldingSetNodeID &ID,
     Args[Idx].Profile(ID);
 }
 
+QualifiedNameType::QualifiedNameType(const NestedNameSpecifier *Components,
+                                     unsigned NumComponents, 
+                                     QualType NamedType,
+                                     QualType CanonType)
+  : Type(QualifiedName, CanonType, NamedType->isDependentType()),
+    NumComponents(NumComponents), NamedType(NamedType) {
+  NestedNameSpecifier *InitComponents 
+    = reinterpret_cast<NestedNameSpecifier *>(this + 1);
+  for (unsigned I = 0; I < NumComponents; ++I)
+    new (InitComponents + I) NestedNameSpecifier(Components[I]);
+}
+
+void QualifiedNameType::Profile(llvm::FoldingSetNodeID &ID, 
+                                const NestedNameSpecifier *Components,
+                                unsigned NumComponents, 
+                                QualType NamedType) {
+  ID.AddInteger(NumComponents);
+  for (unsigned I = 0; I < NumComponents; ++I)
+    ID.AddPointer(Components[I].getAsOpaquePtr());
+  NamedType.Profile(ID);
+}
+
 //===----------------------------------------------------------------------===//
 // Type Printing
 //===----------------------------------------------------------------------===//
@@ -1411,6 +1435,38 @@ getAsStringInternal(std::string &InnerString) const {
     InnerString = SpecString + ' ' + InnerString;
 }
 
+void QualifiedNameType::getAsStringInternal(std::string &InnerString) const {
+  std::string MyString;
+
+  for (iterator Comp = begin(), CompEnd = end(); Comp != CompEnd; ++Comp) {
+    if (Type *T = Comp->getAsType()) {
+      std::string TypeStr;
+      if (const TagType *TagT = dyn_cast<TagType>(T))
+        TagT->getAsStringInternal(TypeStr, true);
+      else
+        T->getAsStringInternal(TypeStr);
+
+      MyString += TypeStr;
+    } else if (NamedDecl *NamedDC 
+               = dyn_cast_or_null<NamedDecl>(Comp->getAsDeclContext()))
+      MyString += NamedDC->getNameAsString();
+    MyString += "::";
+  }
+  
+  std::string TypeStr;
+  if (const TagType *TagT = dyn_cast<TagType>(NamedType.getTypePtr())) {
+    // Suppress printing of 'enum', 'struct', 'union', or 'class'.
+    TagT->getAsStringInternal(TypeStr, true);
+  } else
+    NamedType.getAsStringInternal(TypeStr);
+
+  MyString += TypeStr;
+  if (InnerString.empty())
+    InnerString.swap(MyString);
+  else
+    InnerString = MyString + ' ' + InnerString;
+}
+
 void ObjCInterfaceType::getAsStringInternal(std::string &InnerString) const {
   if (!InnerString.empty())    // Prefix the basic type, e.g. 'typedefname X'.
     InnerString = ' ' + InnerString;
@@ -1451,10 +1507,15 @@ void ObjCQualifiedIdType::getAsStringInternal(std::string &InnerString) const {
 }
 
 void TagType::getAsStringInternal(std::string &InnerString) const {
+  getAsStringInternal(InnerString, false);
+}
+
+void TagType::getAsStringInternal(std::string &InnerString,
+                                  bool SuppressTagKind) const {
   if (!InnerString.empty())    // Prefix the basic type, e.g. 'typedefname X'.
     InnerString = ' ' + InnerString;
   
-  const char *Kind = getDecl()->getKindName();
+  const char *Kind = SuppressTagKind? 0 : getDecl()->getKindName();
   const char *ID;
   if (const IdentifierInfo *II = getDecl()->getIdentifier())
     ID = II->getName();
index 8498e0123e66c12ce6c2836aeec9662195d7a984..6f93a1859fe462f39e15a0a7c8e2befac3943cf2 100644 (file)
@@ -417,6 +417,21 @@ CreateImpl(ASTContext& Context, Deserializer& D) {
   return 0;
 }
 
+//===----------------------------------------------------------------------===//
+// QualifiedNameType
+//===----------------------------------------------------------------------===//
+void QualifiedNameType::EmitImpl(llvm::Serializer& S) const {
+  S.EmitInt(NumComponents);
+  // FIXME: Serialize the actual components
+  S.Emit(NamedType);
+}
+
+Type* 
+QualifiedNameType::CreateImpl(ASTContext& Context, llvm::Deserializer& D) {
+  // FIXME: Implement de-serialization
+  return 0;
+}
+
 //===----------------------------------------------------------------------===//
 // VariableArrayType
 //===----------------------------------------------------------------------===//
index b0cf07789b5711ba089253f0149bbf4325da8675..cec39fd71a22524f56ef88c7aeae096312146bcb 100644 (file)
@@ -525,6 +525,7 @@ llvm::DIType CGDebugInfo::getOrCreateType(QualType Ty,
   case Type::BlockPointer:
   case Type::MemberPointer:
   case Type::ClassTemplateSpecialization:
+  case Type::QualifiedName:
   case Type::ObjCQualifiedClass:
     // Unsupported types
     return llvm::DIType();
index a498182df71a18a867e96fe5d05de43cfa669e89..72ac3112f9dcf8bb0175734f1f9d050579c90b5d 100644 (file)
@@ -15,6 +15,7 @@
 #include "clang/Parse/ParseDiagnostic.h"
 #include "clang/Basic/LangOptions.h"
 #include "llvm/ADT/STLExtras.h"
+#include <cstring>
 using namespace clang;
 
 
@@ -23,6 +24,66 @@ static DiagnosticBuilder Diag(Diagnostic &D, SourceLocation Loc,
   return D.Report(FullSourceLoc(Loc, SrcMgr), DiagID);
 }
 
+/// \brief Double the capacity of this scope specifier.
+void CXXScopeSpec::reallocate() {
+  Action::CXXScopeTy **Data = new Action::CXXScopeTy *[Capacity * 2];
+
+  Action::CXXScopeTy **From 
+    = Capacity == 4? &InlineScopeReps[0] : ManyScopeReps;
+  std::memcpy(Data, From, Capacity * sizeof(Action::CXXScopeTy *));
+  
+  if (Capacity > 4)
+    delete [] ManyScopeReps;
+  ManyScopeReps = Data;
+  Capacity *= 2;
+}
+
+CXXScopeSpec::CXXScopeSpec(const CXXScopeSpec &SS) 
+  : Range(SS.Range), NumScopeReps(SS.NumScopeReps), Capacity(SS.Capacity) {
+
+  if (Capacity > 4) {
+    ManyScopeReps = new Action::CXXScopeTy *[Capacity];
+    memcpy(ManyScopeReps, SS.ManyScopeReps, 
+           Capacity * sizeof(Action::CXXScopeTy *));
+  } else {
+    memcpy(InlineScopeReps, SS.InlineScopeReps, 
+           Capacity * sizeof(Action::CXXScopeTy *));
+  }
+}
+
+CXXScopeSpec &CXXScopeSpec::operator=(const CXXScopeSpec &SS) {
+  // FIXME: Does not provide the strong exception safety guarantee.
+  this->~CXXScopeSpec();
+  new (this) CXXScopeSpec(SS);
+  return *this;
+}
+
+void *CXXScopeSpec::buildAnnotationData() const {
+  uintptr_t *Data = (uintptr_t *)malloc(sizeof(uintptr_t) * (size() + 1));
+  Data[0] = size();
+  for (unsigned I = 0; I < size(); ++I)
+    Data[I + 1] = reinterpret_cast<uintptr_t>(getScopeRep(I));
+  return Data;
+}
+
+void CXXScopeSpec::setFromAnnotationData(void *DataIn) {
+  uintptr_t *Data = static_cast<uintptr_t *>(DataIn);
+  NumScopeReps = *Data;
+
+  // Allocate enough space for the annotation data.
+  if (NumScopeReps > Capacity) {
+    if (Capacity > 4)
+      delete [] ManyScopeReps;
+    
+    Capacity = NumScopeReps;
+    ManyScopeReps = new Action::CXXScopeTy *[Capacity];
+  }
+
+  if (Capacity > 4)
+    std::memcpy(ManyScopeReps, Data + 1, sizeof(uintptr_t) * NumScopeReps);
+  else
+    std::memcpy(InlineScopeReps, Data + 1, sizeof(uintptr_t) * NumScopeReps);
+}
 
 /// DeclaratorChunk::getFunction - Return a DeclaratorChunk for a function.
 /// "TheDeclarator" is the declarator that this will be added to.
index 25565e657687dd092d550f6e0fdab58ee09700a1..0dddfdff7942ae5df566c0883b03c1a5679eefbf 100644 (file)
@@ -491,7 +491,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
         goto DoneWithDeclSpec;
 
       CXXScopeSpec SS;
-      SS.setScopeRep(Tok.getAnnotationValue());
+      SS.setFromAnnotationData(Tok.getAnnotationValue());
       SS.setRange(Tok.getAnnotationRange());
 
       // If the next token is the name of the class type that the C++ scope
@@ -508,7 +508,8 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
 
       if (TypeRep == 0)
         goto DoneWithDeclSpec;
-
+      
+      CXXScopeSpec::freeAnnotationData(Tok.getAnnotationValue());
       ConsumeToken(); // The C++ scope.
 
       isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec,
index e1b5db9c4405b3f50830dab6032df1852d86b5c6..731f4c7957fadb29f9dce895a5c2af1d5e334472 100644 (file)
@@ -36,7 +36,8 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS) {
          "Call sites of this function should be guarded by checking for C++");
 
   if (Tok.is(tok::annot_cxxscope)) {
-    SS.setScopeRep(Tok.getAnnotationValue());
+    SS.setFromAnnotationData(Tok.getAnnotationValue());
+    CXXScopeSpec::freeAnnotationData(Tok.getAnnotationValue());
     SS.setRange(Tok.getAnnotationRange());
     ConsumeToken();
     return true;
@@ -53,7 +54,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS) {
     // '::' - Global scope qualifier.
     SourceLocation CCLoc = ConsumeToken();
     SS.setBeginLoc(CCLoc);
-    SS.setScopeRep(Actions.ActOnCXXGlobalScopeSpecifier(CurScope, CCLoc));
+    SS.addScopeRep(Actions.ActOnCXXGlobalScopeSpecifier(CurScope, CCLoc));
     SS.setEndLoc(CCLoc);
     HasScopeSpecifier = true;
   }
@@ -79,7 +80,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS) {
       if (SS.isInvalid())
         continue;
       
-      SS.setScopeRep(
+      SS.addScopeRep(
         Actions.ActOnCXXNestedNameSpecifier(CurScope, SS, IdLoc, CCLoc, *II));
       SS.setEndLoc(CCLoc);
       continue;
@@ -149,7 +150,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS) {
 
       if (TemplateId->Kind == TNK_Class_template) {
         if (AnnotateTemplateIdTokenAsType(&SS))
-          SS.setScopeRep(0);
+          SS.clear();
 
         assert(Tok.is(tok::annot_typename) && 
                "AnnotateTemplateIdTokenAsType isn't working");
@@ -164,7 +165,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS) {
           HasScopeSpecifier = true;
         }
 
-        SS.setScopeRep(
+        SS.addScopeRep(
           Actions.ActOnCXXNestedNameSpecifier(CurScope, SS, 
                                               TypeToken.getAnnotationValue(),
                                               TypeToken.getAnnotationRange(),
index 5666051fe59639e1807942f8c8323a0f7911e3d7..8c3ff443f155f84f837e903fa220fab3cd23aee4 100644 (file)
@@ -856,7 +856,7 @@ bool Parser::TryAnnotateTypeOrScopeToken() {
   else
     PP.EnterToken(Tok);
   Tok.setKind(tok::annot_cxxscope);
-  Tok.setAnnotationValue(SS.getScopeRep());
+  Tok.setAnnotationValue(SS.buildAnnotationData());
   Tok.setAnnotationRange(SS.getRange());
 
   // In case the tokens were cached, have Preprocessor replace them with the
@@ -888,7 +888,7 @@ bool Parser::TryAnnotateCXXScopeToken() {
   else
     PP.EnterToken(Tok);
   Tok.setKind(tok::annot_cxxscope);
-  Tok.setAnnotationValue(SS.getScopeRep());
+  Tok.setAnnotationValue(SS.buildAnnotationData());
   Tok.setAnnotationRange(SS.getRange());
 
   // In case the tokens were cached, have Preprocessor replace them with the
index d84829a0c7c71049844df4cf36bc05921f497dd6..5106a54f952e181b21379948feb99622e0378db3 100644 (file)
@@ -1451,21 +1451,8 @@ public:
                                                SourceLocation RParen);
 
   bool RequireCompleteDeclContext(const CXXScopeSpec &SS);
-
-  /// \brief Build a scope representation from a declaration context.
-  CXXScopeTy *createScopeRep(DeclContext *DC) {
-    return static_cast<CXXScopeTy *>(DC);
-  }
-
-  /// \brief Build a scope representation from a type.
-  CXXScopeTy *createScopeRep(QualType T);
-
-  DeclContext *getScopeRepAsDeclContext(const CXXScopeSpec &SS);
-  QualType getScopeRepAsType(const CXXScopeSpec &SS);
-
-  /// \brief Determines whether this scope specifier is represented as
-  /// a type.
-  bool isScopeRepType(const CXXScopeSpec &SS);
+  
+  DeclContext *computeDeclContext(const CXXScopeSpec &SS);
 
   /// ActOnCXXGlobalScopeSpecifier - Return the object that represents the
   /// global scope ('::').
index e30ec2adcf275bb7225df2ce7dd4cbbfc42a69c5..156f3a12fbb44073d4dcfd0dbe119f9c299614dd 100644 (file)
 
 #include "Sema.h"
 #include "clang/AST/ASTContext.h"
+#include "clang/AST/NestedNameSpecifier.h"
 #include "clang/Parse/DeclSpec.h"
 #include "llvm/ADT/STLExtras.h"
 using namespace clang;
 
-/// \brief Retrieve the scope represented by this scope specifier as a
-/// DeclContext.
-DeclContext *Sema::getScopeRepAsDeclContext(const CXXScopeSpec &SS) {
-  if (SS.isInvalid() || !SS.getScopeRep())
-    return 0;
-  uintptr_t Rep = reinterpret_cast<uintptr_t>(SS.getScopeRep());
-  if ((Rep & 0x01) == 0)
-    return reinterpret_cast<DeclContext *>(Rep);
-
-  // Retrieve the DeclContext associated with this type.
-  QualType T = QualType(reinterpret_cast<Type *>(Rep & ~0x01), 0);
-  const TagType *TagT = T->getAsTagType();
-  assert(TagT && "No DeclContext from a non-tag type");
-  return TagT->getDecl();
-}
-
-/// \brief Retrieve the scope represented by this scope specifier as a
-/// type.
-QualType Sema::getScopeRepAsType(const CXXScopeSpec &SS) {
-  if (SS.isInvalid() || !SS.getScopeRep())
-    return QualType();
-  
-  uintptr_t Rep = reinterpret_cast<uintptr_t>(SS.getScopeRep());
-  if ((Rep & 0x01) == 0)
-    return QualType();
-  return QualType(reinterpret_cast<Type *>(Rep & ~0x01), 0);
-}
-
-Action::CXXScopeTy *Sema::createScopeRep(QualType T) {
-  assert(((reinterpret_cast<uintptr_t>(T.getAsOpaquePtr()) & 0x01) == 0) && 
-         "Scope type with cv-qualifiers");
-  if (T.isNull())
+/// \brief Compute the DeclContext that is associated with the given
+/// scope specifier.
+DeclContext *Sema::computeDeclContext(const CXXScopeSpec &SS) {
+  if (!SS.isSet() || SS.isInvalid())
     return 0;
-  
-  return reinterpret_cast<CXXScopeTy *>(
-           reinterpret_cast<uintptr_t>(T.getAsOpaquePtr()) | 0x01);
-}
 
-bool Sema::isScopeRepType(const CXXScopeSpec &SS) {
-  uintptr_t Rep = reinterpret_cast<uintptr_t>(SS.getScopeRep());
-  return Rep & 0x01;
+  NestedNameSpecifier NNS
+    = NestedNameSpecifier::getFromOpaquePtr(SS.getCurrentScopeRep());
+  return NNS.computeDeclContext(Context);
 }
 
 /// \brief Require that the context specified by SS be complete.
@@ -73,7 +42,7 @@ bool Sema::RequireCompleteDeclContext(const CXXScopeSpec &SS) {
   if (!SS.isSet() || SS.isInvalid())
     return false;
   
-  DeclContext *DC = getScopeRepAsDeclContext(SS);
+  DeclContext *DC = computeDeclContext(SS);
   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.
@@ -95,7 +64,7 @@ bool Sema::RequireCompleteDeclContext(const CXXScopeSpec &SS) {
 /// global scope ('::').
 Sema::CXXScopeTy *Sema::ActOnCXXGlobalScopeSpecifier(Scope *S,
                                                      SourceLocation CCLoc) {
-  return createScopeRep(Context.getTranslationUnitDecl());
+  return NestedNameSpecifier(Context.getTranslationUnitDecl()).getAsOpaquePtr();
 }
 
 /// ActOnCXXNestedNameSpecifier - Called during parsing of a
@@ -114,9 +83,10 @@ Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S,
   if (SD) {
     if (TypedefDecl *TD = dyn_cast<TypedefDecl>(SD)) {
       if (TD->getUnderlyingType()->isRecordType())
-        return createScopeRep(Context.getTypeDeclType(TD));
+        return NestedNameSpecifier(Context.getTypeDeclType(TD).getTypePtr())
+                .getAsOpaquePtr();
     } else if (isa<NamespaceDecl>(SD) || isa<RecordDecl>(SD)) {
-      return createScopeRep(cast<DeclContext>(SD));
+      return NestedNameSpecifier(cast<DeclContext>(SD)).getAsOpaquePtr();
     }
 
     // FIXME: Template parameters and dependent types.
@@ -152,7 +122,8 @@ Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S,
                                                     TypeTy *Ty,
                                                     SourceRange TypeRange,
                                                     SourceLocation CCLoc) {
-  return createScopeRep(QualType::getFromOpaquePtr(Ty));
+  return NestedNameSpecifier(QualType::getFromOpaquePtr(Ty).getTypePtr())
+           .getAsOpaquePtr();
 }
 
 /// ActOnCXXEnterDeclaratorScope - Called when a C++ scope specifier (global
@@ -165,7 +136,7 @@ void Sema::ActOnCXXEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS) {
   assert(SS.isSet() && "Parser passed invalid CXXScopeSpec.");
   assert(PreDeclaratorDC == 0 && "Previous declarator context not popped?");
   PreDeclaratorDC = static_cast<DeclContext*>(S->getEntity());
-  CurContext = getScopeRepAsDeclContext(SS);
+  CurContext = computeDeclContext(SS);
   S->setEntity(CurContext);
 }
 
@@ -176,8 +147,7 @@ void Sema::ActOnCXXEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS) {
 /// defining scope.
 void Sema::ActOnCXXExitDeclaratorScope(Scope *S, const CXXScopeSpec &SS) {
   assert(SS.isSet() && "Parser passed invalid CXXScopeSpec.");
-  assert(S->getEntity() == getScopeRepAsDeclContext(SS) && 
-         "Context imbalance!");
+  assert(S->getEntity() == computeDeclContext(SS) && "Context imbalance!");
   S->setEntity(PreDeclaratorDC);
   PreDeclaratorDC = 0;
 
index c3dfd19be4b84fe152e6ba4910f3ec8514d931c2..63d446f70c03df7e54fee23cb6a545e1cd2098dd 100644 (file)
@@ -72,22 +72,32 @@ Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc,
   }
 
   if (IIDecl) {
+    QualType T;
+  
     if (TypeDecl *TD = dyn_cast<TypeDecl>(IIDecl)) {
       // Check whether we can use this type
       (void)DiagnoseUseOfDecl(IIDecl, NameLoc);
       
-      return Context.getTypeDeclType(TD).getAsOpaquePtr();
-    }
-    
-    if (ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(IIDecl)) {
+      T = Context.getTypeDeclType(TD);
+    } else if (ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(IIDecl)) {
       // Check whether we can use this interface.
       (void)DiagnoseUseOfDecl(IIDecl, NameLoc);
       
-      return Context.getObjCInterfaceType(IDecl).getAsOpaquePtr();
+      T = Context.getObjCInterfaceType(IDecl);
+    } else
+      return 0;
+
+    if (SS && SS->isNotEmpty() && SS->isSet()) {
+      llvm::SmallVector<NestedNameSpecifier, 4> TNNs;
+      for (CXXScopeSpec::iterator TNN = SS->begin(), TNNEnd = SS->end();
+           TNN != TNNEnd; ++TNN)
+        TNNs.push_back(NestedNameSpecifier::getFromOpaquePtr(*TNN));
+      T = Context.getQualifiedNameType(&TNNs[0], TNNs.size(), T);
     }
 
-    // Otherwise, could be a variable, function etc.
+    return T.getAsOpaquePtr();
   }
+
   return 0;
 }
 
@@ -1257,7 +1267,7 @@ Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl,
                             DeclSpec::SCS_static,
                           D.getIdentifierLoc());
   } else { // Something like "int foo::x;"
-    DC = getScopeRepAsDeclContext(D.getCXXScopeSpec());
+    DC = computeDeclContext(D.getCXXScopeSpec());
     // FIXME: RequireCompleteDeclContext(D.getCXXScopeSpec()); ?
     PrevDecl = LookupQualifiedName(DC, Name, LookupOrdinaryName, true);
 
@@ -3020,7 +3030,7 @@ Sema::DeclTy *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagKind TK,
     }
 
     // FIXME: RequireCompleteDeclContext(SS)?
-    DC = getScopeRepAsDeclContext(SS);
+    DC = computeDeclContext(SS);
     SearchDC = DC;
     // Look-up name inside 'foo::'.
     PrevDecl = dyn_cast_or_null<TagDecl>(
index 3307dd0cc45d32f47fb757810aa67657784a404a..10e7bd4c97323e9f4e865ce6952e3b06d2e8f486 100644 (file)
@@ -299,8 +299,8 @@ void Sema::CheckCXXDefaultArguments(FunctionDecl *FD) {
 bool Sema::isCurrentClassName(const IdentifierInfo &II, Scope *,
                               const CXXScopeSpec *SS) {
   CXXRecordDecl *CurDecl;
-  if (SS) {
-    DeclContext *DC = getScopeRepAsDeclContext(*SS);
+  if (SS && SS->isSet() && !SS->isInvalid()) {
+    DeclContext *DC = computeDeclContext(*SS);
     CurDecl = dyn_cast_or_null<CXXRecordDecl>(DC);
   } else
     CurDecl = dyn_cast_or_null<CXXRecordDecl>(CurContext);
index 1e184d0349b97e6b74ae6beccc2cd89df8a3aca3..cec94cfdf064792630d613bd163c30bbffd408b7 100644 (file)
@@ -727,7 +727,7 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc,
   // implicit member ref, because we want a pointer to the member in general,
   // not any specific instance's member.
   if (isAddressOfOperand && SS && !SS->isEmpty() && !HasTrailingLParen) {
-    DeclContext *DC = getScopeRepAsDeclContext(*SS);
+    DeclContext *DC = computeDeclContext(*SS);
     if (D && isa<CXXRecordDecl>(DC)) {
       QualType DType;
       if (FieldDecl *FD = dyn_cast<FieldDecl>(D)) {
@@ -942,7 +942,7 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc,
     //     - a nested-name-specifier that contains a class-name that
     //       names a dependent type.
     else if (SS && !SS->isEmpty()) {
-      for (DeclContext *DC = getScopeRepAsDeclContext(*SS);
+      for (DeclContext *DC = computeDeclContext(*SS);
            DC; DC = DC->getParent()) {
         // FIXME: could stop early at namespace scope.
         if (DC->isRecord()) {
index d6c36d44a9db3bf0d0ab810d28a31414953cf459..616ee3dd932ea6e43d070c43ccd401362bd09f52 100644 (file)
@@ -1038,9 +1038,10 @@ Sema::LookupParsedName(Scope *S, const CXXScopeSpec *SS,
     if (SS->isInvalid() || RequireCompleteDeclContext(*SS))
       return LookupResult::CreateLookupResult(Context, 0);
 
-    if (SS->isSet())
-      return LookupQualifiedName(getScopeRepAsDeclContext(*SS),
+    if (SS->isSet()) {
+      return LookupQualifiedName(computeDeclContext(*SS),
                                  Name, NameKind, RedeclarationOnly);
+    }
   }
 
   return LookupName(S, Name, NameKind, RedeclarationOnly, 
index 6277d9e51227ee3a5bb23326ebd9b7e38c4f1878..f5317787bac2993ab94d66562c72ad8bbf7ddd50 100644 (file)
@@ -399,7 +399,7 @@ Sema::ActOnClassTemplate(Scope *S, unsigned TagSpec, TagKind TK,
 
   DeclContext *SemanticContext = CurContext;
   if (SS.isNotEmpty() && !SS.isInvalid()) {
-    SemanticContext = getScopeRepAsDeclContext(SS);
+    SemanticContext = computeDeclContext(SS);
 
     // FIXME: need to match up several levels of template parameter
     // lists here.
index 4341fc94f90718550f11f308b9cbd2d30c5a9ef6..7df9941aa5b9b1ae3d946ac46391ebc4b5aad24c 100644 (file)
@@ -490,6 +490,14 @@ InstantiateClassTemplateSpecializationType(
                                       SourceLocation());
 }
 
+QualType 
+TemplateTypeInstantiator::
+InstantiateQualifiedNameType(const QualifiedNameType *T, 
+                             unsigned Quals) const {
+  assert(false && "Cannot have dependent qualified name types (yet)");
+  return QualType();
+}
+
 QualType 
 TemplateTypeInstantiator::
 InstantiateObjCInterfaceType(const ObjCInterfaceType *T,
index c52f64055b85c0ee0166f0a4e07a55e2f3e4cc75..a8be924fc881e4bab944dfda59c5ddf5634e1b84 100644 (file)
@@ -742,7 +742,7 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip) {
     }
     case DeclaratorChunk::MemberPointer:
       // The scope spec must refer to a class, or be dependent.
-      DeclContext *DC = getScopeRepAsDeclContext(DeclType.Mem.Scope());
+      DeclContext *DC = computeDeclContext(DeclType.Mem.Scope());
       QualType ClsType;
       // FIXME: Extend for dependent types when it's actually supported.
       // See ActOnCXXNestedNameSpecifier.
@@ -810,8 +810,7 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip) {
         D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef &&
         ((D.getContext() != Declarator::MemberContext &&
           (!D.getCXXScopeSpec().isSet() ||
-           !static_cast<DeclContext*>(D.getCXXScopeSpec().getScopeRep())
-              ->isRecord())) ||
+           !computeDeclContext(D.getCXXScopeSpec())->isRecord())) ||
          D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static)) {
       if (D.isFunctionDeclarator())
         Diag(D.getIdentifierLoc(), diag::err_invalid_qualified_function_type);
diff --git a/test/SemaCXX/qualified-names-diag.cpp b/test/SemaCXX/qualified-names-diag.cpp
new file mode 100644 (file)
index 0000000..151b924
--- /dev/null
@@ -0,0 +1,28 @@
+// RUN: clang -fsyntax-only -verify %s
+namespace foo {
+  namespace wibble {
+    struct x { int y; };
+
+    namespace bar {
+      namespace wonka {
+        struct x {
+          struct y { };
+        };
+      }
+    }
+  }
+}
+
+namespace bar {
+  typedef int y;
+}
+void test() {
+  foo::wibble::x a;
+  ::bar::y b;
+  a + b; // expected-error{{invalid operands to binary expression ('foo::wibble::x' (aka 'struct x') and '::bar::y' (aka 'int'))}}
+
+  ::foo::wibble::bar::wonka::x::y c;
+  c + b; // expected-error{{invalid operands to binary expression ('::foo::wibble::bar::wonka::x::y' (aka 'struct y') and '::bar::y' (aka 'int'))}}
+}
+
+int ::foo::wibble::bar::wonka::x::y::* ptrmem;
index 8ecee50502765b7c2c5cec19fe512da987ef6754..3e7c464d2cf8babb54183ce73fd12a97b7d545f2 100644 (file)
@@ -8,7 +8,7 @@ struct add_pointer {
 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 *')}}
+  return ptr; // expected-error{{incompatible type returning 'int *', expected 'add_pointer<float>::type' (aka 'float *')}}
 }
 
 add_pointer<int&>::type // expected-note{{in instantiation of template class 'struct add_pointer<int &>' requested here}}