blob: c48e3bc79eb1b1950ce0f70dca07ea24467808ec [file] [log] [blame]
Douglas Gregorbc0805a2008-10-23 00:40:37 +00001//===---- SemaInherit.cpp - C++ Inheritance ---------------------*- C++ -*-===//
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 provides Sema routines for C++ inheritance semantics,
Anders Carlsson60d6b0d2009-03-27 04:43:36 +000011// including searching the inheritance hierarchy.
Douglas Gregorbc0805a2008-10-23 00:40:37 +000012//
13//===----------------------------------------------------------------------===//
14
Douglas Gregor94b1dd22008-10-24 04:54:22 +000015#include "SemaInherit.h"
Sebastian Redl7c8bd602009-02-07 20:10:22 +000016#include "Sema.h"
Douglas Gregorbc0805a2008-10-23 00:40:37 +000017#include "clang/AST/ASTContext.h"
18#include "clang/AST/DeclCXX.h"
Douglas Gregor94b1dd22008-10-24 04:54:22 +000019#include "clang/AST/Type.h"
20#include "clang/AST/TypeOrdering.h"
Douglas Gregor7176fff2009-01-15 00:26:24 +000021#include <algorithm>
Douglas Gregor94b1dd22008-10-24 04:54:22 +000022#include <memory>
23#include <set>
24#include <string>
Douglas Gregorbc0805a2008-10-23 00:40:37 +000025
Douglas Gregor0575d4a2008-10-24 16:17:19 +000026using namespace clang;
Douglas Gregorbc0805a2008-10-23 00:40:37 +000027
Douglas Gregor31a19b62009-04-01 21:51:26 +000028/// \brief Computes the set of declarations referenced by these base
29/// paths.
30void BasePaths::ComputeDeclsFound() {
31 assert(NumDeclsFound == 0 && !DeclsFound &&
32 "Already computed the set of declarations");
33
34 std::set<NamedDecl *> Decls;
35 for (BasePaths::paths_iterator Path = begin(), PathEnd = end();
36 Path != PathEnd; ++Path)
37 Decls.insert(*Path->Decls.first);
38
39 NumDeclsFound = Decls.size();
40 DeclsFound = new NamedDecl * [NumDeclsFound];
41 std::copy(Decls.begin(), Decls.end(), DeclsFound);
42}
43
Anders Carlsson6a502a32009-05-13 21:22:06 +000044BasePaths::decl_iterator BasePaths::found_decls_begin() {
Douglas Gregor31a19b62009-04-01 21:51:26 +000045 if (NumDeclsFound == 0)
46 ComputeDeclsFound();
47 return DeclsFound;
48}
49
Anders Carlsson6a502a32009-05-13 21:22:06 +000050BasePaths::decl_iterator BasePaths::found_decls_end() {
Douglas Gregor31a19b62009-04-01 21:51:26 +000051 if (NumDeclsFound == 0)
52 ComputeDeclsFound();
53 return DeclsFound + NumDeclsFound;
54}
55
Douglas Gregor94b1dd22008-10-24 04:54:22 +000056/// 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.
60bool BasePaths::isAmbiguous(QualType BaseType) {
Douglas Gregor0575d4a2008-10-24 16:17:19 +000061 assert(BaseType->isCanonical() && "Base type must be the canonical type");
62 assert(BaseType.getCVRQualifiers() == 0 && "Base type must be unqualified");
Douglas Gregor94b1dd22008-10-24 04:54:22 +000063 std::pair<bool, unsigned>& Subobjects = ClassSubobjects[BaseType];
64 return Subobjects.second + (Subobjects.first? 1 : 0) > 1;
65}
66
67/// clear - Clear out all prior path information.
68void BasePaths::clear() {
69 Paths.clear();
70 ClassSubobjects.clear();
71 ScratchPath.clear();
Sebastian Redl07779722008-10-31 14:43:28 +000072 DetectedVirtual = 0;
Douglas Gregor94b1dd22008-10-24 04:54:22 +000073}
74
Douglas Gregor7176fff2009-01-15 00:26:24 +000075/// @brief Swaps the contents of this BasePaths structure with the
76/// contents of Other.
77void BasePaths::swap(BasePaths &Other) {
Douglas Gregor4dc6b1c2009-01-16 00:38:09 +000078 std::swap(Origin, Other.Origin);
Douglas Gregor7176fff2009-01-15 00:26:24 +000079 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);
85}
86
Douglas Gregor27c8dc02008-10-29 00:13:59 +000087/// 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.
Douglas Gregor94b1dd22008-10-24 04:54:22 +000092bool Sema::IsDerivedFrom(QualType Derived, QualType Base) {
Sebastian Redl07779722008-10-31 14:43:28 +000093 BasePaths Paths(/*FindAmbiguities=*/false, /*RecordPaths=*/false,
94 /*DetectVirtual=*/false);
Douglas Gregor94b1dd22008-10-24 04:54:22 +000095 return IsDerivedFrom(Derived, Base, Paths);
96}
97
Douglas Gregor27c8dc02008-10-29 00:13:59 +000098/// 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
Douglas Gregor94b1dd22008-10-24 04:54:22 +0000103/// bases. This routine will use Paths to determine if there are
104/// ambiguous paths (if @c Paths.isFindingAmbiguities()) and record
Douglas Gregor27c8dc02008-10-29 00:13:59 +0000105/// information about all of the paths (if @c Paths.isRecordingPaths()).
Douglas Gregor94b1dd22008-10-24 04:54:22 +0000106bool Sema::IsDerivedFrom(QualType Derived, QualType Base, BasePaths &Paths) {
Douglas Gregorbc0805a2008-10-23 00:40:37 +0000107 Derived = Context.getCanonicalType(Derived).getUnqualifiedType();
108 Base = Context.getCanonicalType(Base).getUnqualifiedType();
Sebastian Redl07779722008-10-31 14:43:28 +0000109
Douglas Gregor27c8dc02008-10-29 00:13:59 +0000110 if (!Derived->isRecordType() || !Base->isRecordType())
111 return false;
Douglas Gregorbc0805a2008-10-23 00:40:37 +0000112
113 if (Derived == Base)
114 return false;
115
Douglas Gregor4dc6b1c2009-01-16 00:38:09 +0000116 Paths.setOrigin(Derived);
Ted Kremenek6217b802009-07-29 21:53:49 +0000117 return LookupInBases(cast<CXXRecordDecl>(Derived->getAs<RecordType>()->getDecl()),
Douglas Gregor7176fff2009-01-15 00:26:24 +0000118 MemberLookupCriteria(Base), Paths);
119}
Douglas Gregor94b1dd22008-10-24 04:54:22 +0000120
Douglas Gregor7176fff2009-01-15 00:26:24 +0000121/// 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
129/// classes.
130bool Sema::LookupInBases(CXXRecordDecl *Class,
131 const MemberLookupCriteria& Criteria,
132 BasePaths &Paths) {
133 bool FoundPath = false;
134
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();
Anders Carlsson1d79faf2009-06-12 18:53:02 +0000141
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.
144 // [temp.dep]p3.
145 if (BaseType->isDependentType())
146 continue;
Douglas Gregor7176fff2009-01-15 00:26:24 +0000147
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.
Ted Kremenek6217b802009-07-29 21:53:49 +0000159 Paths.DetectedVirtual = BaseType->getAs<RecordType>();
Douglas Gregor7176fff2009-01-15 00:26:24 +0000160 SetVirtual = true;
161 }
162 } else
163 ++Subobjects.second;
164
165 if (Paths.isRecordingPaths()) {
166 // Add this base specifier to the current path.
167 BasePathElement Element;
168 Element.Base = &*BaseSpec;
Anders Carlsson77bd57c2009-03-27 18:54:29 +0000169 Element.Class = Class;
Douglas Gregor7176fff2009-01-15 00:26:24 +0000170 if (BaseSpec->isVirtual())
171 Element.SubobjectNumber = 0;
172 else
173 Element.SubobjectNumber = Subobjects.second;
174 Paths.ScratchPath.push_back(Element);
175 }
176
177 CXXRecordDecl *BaseRecord
Ted Kremenek6217b802009-07-29 21:53:49 +0000178 = cast<CXXRecordDecl>(BaseSpec->getType()->getAs<RecordType>()->getDecl());
Douglas Gregor7176fff2009-01-15 00:26:24 +0000179
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
182 // criteria.
183 bool FoundPathToThisBase = false;
Anders Carlsson9e8a7222009-05-29 23:42:05 +0000184 switch (Criteria.Kind) {
185 case MemberLookupCriteria::LK_Base:
Douglas Gregor7176fff2009-01-15 00:26:24 +0000186 FoundPathToThisBase
187 = (Context.getCanonicalType(BaseSpec->getType()) == Criteria.Base);
Anders Carlsson9e8a7222009-05-29 23:42:05 +0000188 break;
189 case MemberLookupCriteria::LK_NamedMember:
Argyrios Kyrtzidis17945a02009-06-30 02:36:12 +0000190 Paths.ScratchPath.Decls = BaseRecord->lookup(Criteria.Name);
Douglas Gregor7176fff2009-01-15 00:26:24 +0000191 while (Paths.ScratchPath.Decls.first != Paths.ScratchPath.Decls.second) {
Douglas Gregor4c921ae2009-01-30 01:04:22 +0000192 if (isAcceptableLookupResult(*Paths.ScratchPath.Decls.first,
193 Criteria.NameKind, Criteria.IDNS)) {
Douglas Gregor7176fff2009-01-15 00:26:24 +0000194 FoundPathToThisBase = true;
195 break;
196 }
197 ++Paths.ScratchPath.Decls.first;
198 }
Anders Carlsson9e8a7222009-05-29 23:42:05 +0000199 break;
Anders Carlssond12ef8d2009-05-30 00:52:53 +0000200 case MemberLookupCriteria::LK_OverriddenMember:
201 Paths.ScratchPath.Decls =
Argyrios Kyrtzidis17945a02009-06-30 02:36:12 +0000202 BaseRecord->lookup(Criteria.Method->getDeclName());
Anders Carlssond12ef8d2009-05-30 00:52:53 +0000203 while (Paths.ScratchPath.Decls.first != Paths.ScratchPath.Decls.second) {
Anders Carlssonf89bb0f2009-05-30 17:26:39 +0000204 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;
210 break;
211 }
Anders Carlssond12ef8d2009-05-30 00:52:53 +0000212 }
213
214 ++Paths.ScratchPath.Decls.first;
215 }
216 break;
Douglas Gregor7176fff2009-01-15 00:26:24 +0000217 }
218
219 if (FoundPathToThisBase) {
220 // We've found a path that terminates that this base.
221 FoundPath = true;
Douglas Gregor94b1dd22008-10-24 04:54:22 +0000222 if (Paths.isRecordingPaths()) {
Douglas Gregor7176fff2009-01-15 00:26:24 +0000223 // 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.
228 return FoundPath;
Douglas Gregor94b1dd22008-10-24 04:54:22 +0000229 }
Mike Stumpac5fc7c2009-08-04 21:02:39 +0000230 } else if (VisitBase && LookupInBases(BaseRecord, Criteria, Paths)) {
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
235 // consideration.
236
Douglas Gregor7176fff2009-01-15 00:26:24 +0000237 // 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.
239 FoundPath = true;
240 if (!Paths.isFindingAmbiguities())
241 return FoundPath;
242 }
Douglas Gregor94b1dd22008-10-24 04:54:22 +0000243
Douglas Gregor7176fff2009-01-15 00:26:24 +0000244 // 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;
Douglas Gregorbc0805a2008-10-23 00:40:37 +0000251 }
252 }
253
Douglas Gregor94b1dd22008-10-24 04:54:22 +0000254 return FoundPath;
255}
256
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
Anders Carlsson29f006b2009-03-27 05:05:05 +0000260/// that all of the base classes are accessible). Returns true
Douglas Gregor94b1dd22008-10-24 04:54:22 +0000261/// 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.
Anders Carlssond8f9cb02009-05-13 21:11:42 +0000265bool
Douglas Gregor0575d4a2008-10-24 16:17:19 +0000266Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base,
Anders Carlssond8f9cb02009-05-13 21:11:42 +0000267 unsigned InaccessibleBaseID,
268 unsigned AmbigiousBaseConvID,
269 SourceLocation Loc, SourceRange Range,
270 DeclarationName Name) {
Douglas Gregor94b1dd22008-10-24 04:54:22 +0000271 // 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.
Anders Carlsson29f006b2009-03-27 05:05:05 +0000275 BasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
Sebastian Redl07779722008-10-31 14:43:28 +0000276 /*DetectVirtual=*/false);
Douglas Gregor94b1dd22008-10-24 04:54:22 +0000277 bool DerivationOkay = IsDerivedFrom(Derived, Base, Paths);
Sebastian Redl21593ac2009-01-28 18:33:18 +0000278 assert(DerivationOkay &&
279 "Can only be used with a derived-to-base conversion");
280 (void)DerivationOkay;
Douglas Gregor94b1dd22008-10-24 04:54:22 +0000281
Anders Carlsson29f006b2009-03-27 05:05:05 +0000282 if (!Paths.isAmbiguous(Context.getCanonicalType(Base).getUnqualifiedType())) {
283 // Check that the base class can be accessed.
Anders Carlssond8f9cb02009-05-13 21:11:42 +0000284 return CheckBaseClassAccess(Derived, Base, InaccessibleBaseID, Paths, Loc,
285 Name);
Anders Carlsson29f006b2009-03-27 05:05:05 +0000286 }
Douglas Gregor94b1dd22008-10-24 04:54:22 +0000287
Douglas Gregor0575d4a2008-10-24 16:17:19 +0000288 // 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.
294 Paths.clear();
295 Paths.setRecordingPaths(true);
296 bool StillOkay = IsDerivedFrom(Derived, Base, Paths);
297 assert(StillOkay && "Can only be used with a derived-to-base conversion");
Sebastian Redl21593ac2009-01-28 18:33:18 +0000298 (void)StillOkay;
Douglas Gregor0575d4a2008-10-24 16:17:19 +0000299
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.
Douglas Gregor4dc6b1c2009-01-16 00:38:09 +0000304 std::string PathDisplayStr = getAmbiguousPathsDisplayString(Paths);
305
Anders Carlssond8f9cb02009-05-13 21:11:42 +0000306 Diag(Loc, AmbigiousBaseConvID)
307 << Derived << Base << PathDisplayStr << Range << Name;
Douglas Gregor4dc6b1c2009-01-16 00:38:09 +0000308 return true;
309}
310
Anders Carlssond8f9cb02009-05-13 21:11:42 +0000311bool
312Sema::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());
318}
319
320
Douglas Gregor4dc6b1c2009-01-16 00:38:09 +0000321/// @brief Builds a string representing ambiguous paths from a
322/// specific derived class to different subobjects of the same base
323/// class.
324///
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:
329/// @code
330/// struct D -> struct B -> struct A
331/// struct D -> struct C -> struct A
332/// @endcode
333std::string Sema::getAmbiguousPathsDisplayString(BasePaths &Paths) {
Douglas Gregor0575d4a2008-10-24 16:17:19 +0000334 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 ";
Douglas Gregor4dc6b1c2009-01-16 00:38:09 +0000342 PathDisplayStr += Paths.getOrigin().getAsString();
Douglas Gregor0575d4a2008-10-24 16:17:19 +0000343 for (BasePath::const_iterator Element = Path->begin();
344 Element != Path->end(); ++Element)
345 PathDisplayStr += " -> " + Element->Base->getType().getAsString();
346 }
Douglas Gregor94b1dd22008-10-24 04:54:22 +0000347 }
Douglas Gregor4dc6b1c2009-01-16 00:38:09 +0000348
349 return PathDisplayStr;
Douglas Gregorbc0805a2008-10-23 00:40:37 +0000350}