| Cedric Venet | 08438133 | 2009-02-14 20:20:19 +0000 | [diff] [blame] | 1 | //===--- SemaCXXScopeSpec.cpp - Semantic Analysis for C++ scope specifiers-===// | 
|  | 2 | // | 
|  | 3 | //                     The LLVM Compiler Infrastructure | 
|  | 4 | // | 
|  | 5 | // This file is distributed under the University of Illinois Open Source | 
|  | 6 | // License. See LICENSE.TXT for details. | 
|  | 7 | // | 
|  | 8 | //===----------------------------------------------------------------------===// | 
|  | 9 | // | 
|  | 10 | // This file implements C++ semantic analysis for scope specifiers. | 
|  | 11 | // | 
|  | 12 | //===----------------------------------------------------------------------===// | 
|  | 13 |  | 
|  | 14 | #include "Sema.h" | 
|  | 15 | #include "clang/AST/ASTContext.h" | 
|  | 16 | #include "clang/Parse/DeclSpec.h" | 
|  | 17 | #include "llvm/ADT/STLExtras.h" | 
|  | 18 | using namespace clang; | 
|  | 19 |  | 
|  | 20 |  | 
|  | 21 | /// ActOnCXXGlobalScopeSpecifier - Return the object that represents the | 
|  | 22 | /// global scope ('::'). | 
|  | 23 | Sema::CXXScopeTy *Sema::ActOnCXXGlobalScopeSpecifier(Scope *S, | 
|  | 24 | SourceLocation CCLoc) { | 
|  | 25 | return cast<DeclContext>(Context.getTranslationUnitDecl()); | 
|  | 26 | } | 
|  | 27 |  | 
|  | 28 | /// ActOnCXXNestedNameSpecifier - Called during parsing of a | 
|  | 29 | /// nested-name-specifier. e.g. for "foo::bar::" we parsed "foo::" and now | 
|  | 30 | /// we want to resolve "bar::". 'SS' is empty or the previously parsed | 
|  | 31 | /// nested-name part ("foo::"), 'IdLoc' is the source location of 'bar', | 
|  | 32 | /// 'CCLoc' is the location of '::' and 'II' is the identifier for 'bar'. | 
|  | 33 | /// Returns a CXXScopeTy* object representing the C++ scope. | 
|  | 34 | Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S, | 
|  | 35 | const CXXScopeSpec &SS, | 
|  | 36 | SourceLocation IdLoc, | 
|  | 37 | SourceLocation CCLoc, | 
|  | 38 | IdentifierInfo &II) { | 
|  | 39 | NamedDecl *SD = LookupParsedName(S, &SS, &II, LookupNestedNameSpecifierName); | 
|  | 40 |  | 
|  | 41 | if (SD) { | 
|  | 42 | if (TypedefDecl *TD = dyn_cast<TypedefDecl>(SD)) { | 
|  | 43 | if (const RecordType* Record = TD->getUnderlyingType()->getAsRecordType()) | 
|  | 44 | return cast<DeclContext>(Record->getDecl()); | 
|  | 45 | } else if (isa<NamespaceDecl>(SD) || isa<RecordDecl>(SD)) { | 
|  | 46 | return cast<DeclContext>(SD); | 
|  | 47 | } | 
|  | 48 |  | 
|  | 49 | // FIXME: Template parameters and dependent types. | 
|  | 50 | // FIXME: C++0x scoped enums | 
|  | 51 |  | 
|  | 52 | // Fall through to produce an error: we found something that isn't | 
|  | 53 | // a class or a namespace. | 
|  | 54 | } | 
|  | 55 |  | 
|  | 56 | // If we didn't find anything during our lookup, try again with | 
|  | 57 | // ordinary name lookup, which can help us produce better error | 
|  | 58 | // messages. | 
|  | 59 | if (!SD) | 
|  | 60 | SD = LookupParsedName(S, &SS, &II, LookupOrdinaryName); | 
|  | 61 | unsigned DiagID; | 
|  | 62 | if (SD) | 
|  | 63 | DiagID = diag::err_expected_class_or_namespace; | 
|  | 64 | else if (SS.isSet()) | 
|  | 65 | DiagID = diag::err_typecheck_no_member; | 
|  | 66 | else | 
|  | 67 | DiagID = diag::err_undeclared_var_use; | 
|  | 68 |  | 
|  | 69 | if (SS.isSet()) | 
|  | 70 | Diag(IdLoc, DiagID) << &II << SS.getRange(); | 
|  | 71 | else | 
|  | 72 | Diag(IdLoc, DiagID) << &II; | 
|  | 73 |  | 
|  | 74 | return 0; | 
|  | 75 | } | 
|  | 76 |  | 
| Douglas Gregor | 7f74112 | 2009-02-25 19:37:18 +0000 | [diff] [blame] | 77 | Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S, | 
|  | 78 | const CXXScopeSpec &SS, | 
|  | 79 | TypeTy *Ty, | 
|  | 80 | SourceRange TypeRange, | 
|  | 81 | SourceLocation CCLoc) { | 
|  | 82 | QualType Type = QualType::getFromOpaquePtr(Ty); | 
|  | 83 | assert(Type->isRecordType() && | 
|  | 84 | "Types in a nested-name-specifier always refer to a record type"); | 
|  | 85 | return cast<DeclContext>(Type->getAsRecordType()->getDecl()); | 
|  | 86 | } | 
|  | 87 |  | 
| Cedric Venet | 08438133 | 2009-02-14 20:20:19 +0000 | [diff] [blame] | 88 | /// ActOnCXXEnterDeclaratorScope - Called when a C++ scope specifier (global | 
|  | 89 | /// scope or nested-name-specifier) is parsed, part of a declarator-id. | 
|  | 90 | /// After this method is called, according to [C++ 3.4.3p3], names should be | 
|  | 91 | /// looked up in the declarator-id's scope, until the declarator is parsed and | 
|  | 92 | /// ActOnCXXExitDeclaratorScope is called. | 
|  | 93 | /// The 'SS' should be a non-empty valid CXXScopeSpec. | 
|  | 94 | void Sema::ActOnCXXEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS) { | 
|  | 95 | assert(SS.isSet() && "Parser passed invalid CXXScopeSpec."); | 
|  | 96 | assert(PreDeclaratorDC == 0 && "Previous declarator context not popped?"); | 
|  | 97 | PreDeclaratorDC = static_cast<DeclContext*>(S->getEntity()); | 
|  | 98 | CurContext = static_cast<DeclContext*>(SS.getScopeRep()); | 
|  | 99 | S->setEntity(CurContext); | 
|  | 100 | } | 
|  | 101 |  | 
|  | 102 | /// ActOnCXXExitDeclaratorScope - Called when a declarator that previously | 
|  | 103 | /// invoked ActOnCXXEnterDeclaratorScope(), is finished. 'SS' is the same | 
|  | 104 | /// CXXScopeSpec that was passed to ActOnCXXEnterDeclaratorScope as well. | 
|  | 105 | /// Used to indicate that names should revert to being looked up in the | 
|  | 106 | /// defining scope. | 
|  | 107 | void Sema::ActOnCXXExitDeclaratorScope(Scope *S, const CXXScopeSpec &SS) { | 
|  | 108 | assert(SS.isSet() && "Parser passed invalid CXXScopeSpec."); | 
|  | 109 | assert(S->getEntity() == SS.getScopeRep() && "Context imbalance!"); | 
|  | 110 | S->setEntity(PreDeclaratorDC); | 
|  | 111 | PreDeclaratorDC = 0; | 
|  | 112 |  | 
|  | 113 | // Reset CurContext to the nearest enclosing context. | 
|  | 114 | while (!S->getEntity() && S->getParent()) | 
|  | 115 | S = S->getParent(); | 
|  | 116 | CurContext = static_cast<DeclContext*>(S->getEntity()); | 
|  | 117 | } |