1 //===---- SemaInherit.cpp - C++ Inheritance ---------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This file provides Sema routines for C++ inheritance semantics,
11 // including searching the inheritance hierarchy.
13 //===----------------------------------------------------------------------===//
15 #include "SemaInherit.h"
17 #include "clang/AST/ASTContext.h"
18 #include "clang/AST/DeclCXX.h"
19 #include "clang/AST/Type.h"
20 #include "clang/AST/TypeOrdering.h"
26 using namespace clang
;
28 /// \brief Computes the set of declarations referenced by these base
30 void BasePaths::ComputeDeclsFound() {
31 assert(NumDeclsFound
== 0 && !DeclsFound
&&
32 "Already computed the set of declarations");
34 std::set
<NamedDecl
*> Decls
;
35 for (BasePaths::paths_iterator Path
= begin(), PathEnd
= end();
36 Path
!= PathEnd
; ++Path
)
37 Decls
.insert(*Path
->Decls
.first
);
39 NumDeclsFound
= Decls
.size();
40 DeclsFound
= new NamedDecl
* [NumDeclsFound
];
41 std::copy(Decls
.begin(), Decls
.end(), DeclsFound
);
44 BasePaths::decl_iterator
BasePaths::found_decls_begin() {
45 if (NumDeclsFound
== 0)
50 BasePaths::decl_iterator
BasePaths::found_decls_end() {
51 if (NumDeclsFound
== 0)
53 return DeclsFound
+ NumDeclsFound
;
56 /// isAmbiguous - Determines whether the set of paths provided is
57 /// ambiguous, i.e., there are two or more paths that refer to
58 /// different base class subobjects of the same type. BaseType must be
59 /// an unqualified, canonical class type.
60 bool BasePaths::isAmbiguous(QualType BaseType
) {
61 assert(BaseType
->isCanonical() && "Base type must be the canonical type");
62 assert(BaseType
.getCVRQualifiers() == 0 && "Base type must be unqualified");
63 std::pair
<bool, unsigned>& Subobjects
= ClassSubobjects
[BaseType
];
64 return Subobjects
.second
+ (Subobjects
.first
? 1 : 0) > 1;
67 /// clear - Clear out all prior path information.
68 void BasePaths::clear() {
70 ClassSubobjects
.clear();
75 /// @brief Swaps the contents of this BasePaths structure with the
76 /// contents of Other.
77 void BasePaths::swap(BasePaths
&Other
) {
78 std::swap(Origin
, Other
.Origin
);
79 Paths
.swap(Other
.Paths
);
80 ClassSubobjects
.swap(Other
.ClassSubobjects
);
81 std::swap(FindAmbiguities
, Other
.FindAmbiguities
);
82 std::swap(RecordPaths
, Other
.RecordPaths
);
83 std::swap(DetectVirtual
, Other
.DetectVirtual
);
84 std::swap(DetectedVirtual
, Other
.DetectedVirtual
);
87 /// IsDerivedFrom - Determine whether the type Derived is derived from
88 /// the type Base, ignoring qualifiers on Base and Derived. This
89 /// routine does not assess whether an actual conversion from a
90 /// Derived* to a Base* is legal, because it does not account for
91 /// ambiguous conversions or conversions to private/protected bases.
92 bool Sema::IsDerivedFrom(QualType Derived
, QualType Base
) {
93 BasePaths
Paths(/*FindAmbiguities=*/false, /*RecordPaths=*/false,
94 /*DetectVirtual=*/false);
95 return IsDerivedFrom(Derived
, Base
, Paths
);
98 /// IsDerivedFrom - Determine whether the type Derived is derived from
99 /// the type Base, ignoring qualifiers on Base and Derived. This
100 /// routine does not assess whether an actual conversion from a
101 /// Derived* to a Base* is legal, because it does not account for
102 /// ambiguous conversions or conversions to private/protected
103 /// bases. This routine will use Paths to determine if there are
104 /// ambiguous paths (if @c Paths.isFindingAmbiguities()) and record
105 /// information about all of the paths (if @c Paths.isRecordingPaths()).
106 bool Sema::IsDerivedFrom(QualType Derived
, QualType Base
, BasePaths
&Paths
) {
107 Derived
= Context
.getCanonicalType(Derived
).getUnqualifiedType();
108 Base
= Context
.getCanonicalType(Base
).getUnqualifiedType();
110 if (!Derived
->isRecordType() || !Base
->isRecordType())
116 Paths
.setOrigin(Derived
);
117 return LookupInBases(cast
<CXXRecordDecl
>(Derived
->getAsRecordType()->getDecl()),
118 MemberLookupCriteria(Base
), Paths
);
121 /// LookupInBases - Look for something that meets the specified
122 /// Criteria within the base classes of Class (or any of its base
123 /// classes, transitively). This routine populates BasePaths with the
124 /// list of paths that one can take to find the entity that meets the
125 /// search criteria, and returns true if any such entity is found. The
126 /// various options passed to the BasePath constructor will affect the
127 /// behavior of this lookup, e.g., whether it finds ambiguities,
128 /// records paths, or attempts to detect the use of virtual base
130 bool Sema::LookupInBases(CXXRecordDecl
*Class
,
131 const MemberLookupCriteria
& Criteria
,
133 bool FoundPath
= false;
135 for (CXXRecordDecl::base_class_const_iterator BaseSpec
= Class
->bases_begin(),
136 BaseSpecEnd
= Class
->bases_end();
137 BaseSpec
!= BaseSpecEnd
; ++BaseSpec
) {
138 // Find the record of the base class subobjects for this type.
139 QualType BaseType
= Context
.getCanonicalType(BaseSpec
->getType());
140 BaseType
= BaseType
.getUnqualifiedType();
142 // If a base class of the class template depends on a template-parameter,
143 // the base class scope is not examined during unqualified name lookup.
145 if (BaseType
->isDependentType())
148 // Determine whether we need to visit this base class at all,
149 // updating the count of subobjects appropriately.
150 std::pair
<bool, unsigned>& Subobjects
= Paths
.ClassSubobjects
[BaseType
];
151 bool VisitBase
= true;
152 bool SetVirtual
= false;
153 if (BaseSpec
->isVirtual()) {
154 VisitBase
= !Subobjects
.first
;
155 Subobjects
.first
= true;
156 if (Paths
.isDetectingVirtual() && Paths
.DetectedVirtual
== 0) {
157 // If this is the first virtual we find, remember it. If it turns out
158 // there is no base path here, we'll reset it later.
159 Paths
.DetectedVirtual
= BaseType
->getAsRecordType();
165 if (Paths
.isRecordingPaths()) {
166 // Add this base specifier to the current path.
167 BasePathElement Element
;
168 Element
.Base
= &*BaseSpec
;
169 Element
.Class
= Class
;
170 if (BaseSpec
->isVirtual())
171 Element
.SubobjectNumber
= 0;
173 Element
.SubobjectNumber
= Subobjects
.second
;
174 Paths
.ScratchPath
.push_back(Element
);
177 CXXRecordDecl
*BaseRecord
178 = cast
<CXXRecordDecl
>(BaseSpec
->getType()->getAsRecordType()->getDecl());
180 // Either look at the base class type or look into the base class
181 // type to see if we've found a member that meets the search
183 bool FoundPathToThisBase
= false;
184 switch (Criteria
.Kind
) {
185 case MemberLookupCriteria::LK_Base
:
187 = (Context
.getCanonicalType(BaseSpec
->getType()) == Criteria
.Base
);
189 case MemberLookupCriteria::LK_NamedMember
:
190 Paths
.ScratchPath
.Decls
= BaseRecord
->lookup(Criteria
.Name
);
191 while (Paths
.ScratchPath
.Decls
.first
!= Paths
.ScratchPath
.Decls
.second
) {
192 if (isAcceptableLookupResult(*Paths
.ScratchPath
.Decls
.first
,
193 Criteria
.NameKind
, Criteria
.IDNS
)) {
194 FoundPathToThisBase
= true;
197 ++Paths
.ScratchPath
.Decls
.first
;
200 case MemberLookupCriteria::LK_OverriddenMember
:
201 Paths
.ScratchPath
.Decls
=
202 BaseRecord
->lookup(Criteria
.Method
->getDeclName());
203 while (Paths
.ScratchPath
.Decls
.first
!= Paths
.ScratchPath
.Decls
.second
) {
204 if (CXXMethodDecl
*MD
=
205 dyn_cast
<CXXMethodDecl
>(*Paths
.ScratchPath
.Decls
.first
)) {
206 OverloadedFunctionDecl::function_iterator MatchedDecl
;
207 if (MD
->isVirtual() &&
208 !IsOverload(Criteria
.Method
, MD
, MatchedDecl
)) {
209 FoundPathToThisBase
= true;
214 ++Paths
.ScratchPath
.Decls
.first
;
219 if (FoundPathToThisBase
) {
220 // We've found a path that terminates that this base.
222 if (Paths
.isRecordingPaths()) {
223 // We have a path. Make a copy of it before moving on.
224 Paths
.Paths
.push_back(Paths
.ScratchPath
);
225 } else if (!Paths
.isFindingAmbiguities()) {
226 // We found a path and we don't care about ambiguities;
227 // return immediately.
231 // C++ [class.member.lookup]p2:
232 // A member name f in one sub-object B hides a member name f in
233 // a sub-object A if A is a base class sub-object of B. Any
234 // declarations that are so hidden are eliminated from
236 else if (VisitBase
&& LookupInBases(BaseRecord
, Criteria
, Paths
)) {
237 // There is a path to a base class that meets the criteria. If we're not
238 // collecting paths or finding ambiguities, we're done.
240 if (!Paths
.isFindingAmbiguities())
244 // Pop this base specifier off the current path (if we're
245 // collecting paths).
246 if (Paths
.isRecordingPaths())
247 Paths
.ScratchPath
.pop_back();
248 // If we set a virtual earlier, and this isn't a path, forget it again.
249 if (SetVirtual
&& !FoundPath
) {
250 Paths
.DetectedVirtual
= 0;
257 /// CheckDerivedToBaseConversion - Check whether the Derived-to-Base
258 /// conversion (where Derived and Base are class types) is
259 /// well-formed, meaning that the conversion is unambiguous (and
260 /// that all of the base classes are accessible). Returns true
261 /// and emits a diagnostic if the code is ill-formed, returns false
262 /// otherwise. Loc is the location where this routine should point to
263 /// if there is an error, and Range is the source range to highlight
264 /// if there is an error.
266 Sema::CheckDerivedToBaseConversion(QualType Derived
, QualType Base
,
267 unsigned InaccessibleBaseID
,
268 unsigned AmbigiousBaseConvID
,
269 SourceLocation Loc
, SourceRange Range
,
270 DeclarationName Name
) {
271 // First, determine whether the path from Derived to Base is
272 // ambiguous. This is slightly more expensive than checking whether
273 // the Derived to Base conversion exists, because here we need to
274 // explore multiple paths to determine if there is an ambiguity.
275 BasePaths
Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
276 /*DetectVirtual=*/false);
277 bool DerivationOkay
= IsDerivedFrom(Derived
, Base
, Paths
);
278 assert(DerivationOkay
&&
279 "Can only be used with a derived-to-base conversion");
280 (void)DerivationOkay
;
282 if (!Paths
.isAmbiguous(Context
.getCanonicalType(Base
).getUnqualifiedType())) {
283 // Check that the base class can be accessed.
284 return CheckBaseClassAccess(Derived
, Base
, InaccessibleBaseID
, Paths
, Loc
,
288 // We know that the derived-to-base conversion is ambiguous, and
289 // we're going to produce a diagnostic. Perform the derived-to-base
290 // search just one more time to compute all of the possible paths so
291 // that we can print them out. This is more expensive than any of
292 // the previous derived-to-base checks we've done, but at this point
293 // performance isn't as much of an issue.
295 Paths
.setRecordingPaths(true);
296 bool StillOkay
= IsDerivedFrom(Derived
, Base
, Paths
);
297 assert(StillOkay
&& "Can only be used with a derived-to-base conversion");
300 // Build up a textual representation of the ambiguous paths, e.g.,
301 // D -> B -> A, that will be used to illustrate the ambiguous
302 // conversions in the diagnostic. We only print one of the paths
303 // to each base class subobject.
304 std::string PathDisplayStr
= getAmbiguousPathsDisplayString(Paths
);
306 Diag(Loc
, AmbigiousBaseConvID
)
307 << Derived
<< Base
<< PathDisplayStr
<< Range
<< Name
;
312 Sema::CheckDerivedToBaseConversion(QualType Derived
, QualType Base
,
313 SourceLocation Loc
, SourceRange Range
) {
314 return CheckDerivedToBaseConversion(Derived
, Base
,
315 diag::err_conv_to_inaccessible_base
,
316 diag::err_ambiguous_derived_to_base_conv
,
317 Loc
, Range
, DeclarationName());
321 /// @brief Builds a string representing ambiguous paths from a
322 /// specific derived class to different subobjects of the same base
325 /// This function builds a string that can be used in error messages
326 /// to show the different paths that one can take through the
327 /// inheritance hierarchy to go from the derived class to different
328 /// subobjects of a base class. The result looks something like this:
330 /// struct D -> struct B -> struct A
331 /// struct D -> struct C -> struct A
333 std::string
Sema::getAmbiguousPathsDisplayString(BasePaths
&Paths
) {
334 std::string PathDisplayStr
;
335 std::set
<unsigned> DisplayedPaths
;
336 for (BasePaths::paths_iterator Path
= Paths
.begin();
337 Path
!= Paths
.end(); ++Path
) {
338 if (DisplayedPaths
.insert(Path
->back().SubobjectNumber
).second
) {
339 // We haven't displayed a path to this particular base
340 // class subobject yet.
341 PathDisplayStr
+= "\n ";
342 PathDisplayStr
+= Paths
.getOrigin().getAsString();
343 for (BasePath::const_iterator Element
= Path
->begin();
344 Element
!= Path
->end(); ++Element
)
345 PathDisplayStr
+= " -> " + Element
->Base
->getType().getAsString();
349 return PathDisplayStr
;