[cfe-commits] r133674 - in /cfe/trunk: include/clang/AST/Type.h include/clang/Sema/Sema.h lib/Sema/CMakeLists.txt lib/Sema/SemaExpr.cpp lib/Sema/SemaExprMember.cpp
Douglas Gregor
dgregor at apple.com
Wed Jun 22 17:49:39 PDT 2011
Author: dgregor
Date: Wed Jun 22 19:49:38 2011
New Revision: 133674
URL: http://llvm.org/viewvc/llvm-project?rev=133674&view=rev
Log:
Move all of Sema's member-access-related checking out of SemaExpr.cpp
and into a new file, SemaExprMember.cpp, bringing SemaExpr.cpp just
under 10,000 lines of code (ugh). No functionality change, although I
intend to do some refactoring of this code to address PR8368 at some
point in the "near" future.
Added:
cfe/trunk/lib/Sema/SemaExprMember.cpp (with props)
Modified:
cfe/trunk/include/clang/AST/Type.h
cfe/trunk/include/clang/Sema/Sema.h
cfe/trunk/lib/Sema/CMakeLists.txt
cfe/trunk/lib/Sema/SemaExpr.cpp
Modified: cfe/trunk/include/clang/AST/Type.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Type.h?rev=133674&r1=133673&r2=133674&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Type.h (original)
+++ cfe/trunk/include/clang/AST/Type.h Wed Jun 22 19:49:38 2011
@@ -849,6 +849,18 @@
return isDestructedTypeImpl(*this);
}
+ /// \brief Determine whether expressions of the given type are forbidden
+ /// from being lvalues in C.
+ ///
+ /// The expression types that are forbidden to be lvalues are:
+ /// - 'void', but not qualified void
+ /// - function types
+ ///
+ /// The exact rule here is C99 6.3.2.1:
+ /// An lvalue is an expression with an object type or an incomplete
+ /// type other than void.
+ bool isCForbiddenLValueType() const;
+
/// \brief Determine whether this type has trivial copy-assignment semantics.
bool hasTrivialCopyAssignment(ASTContext &Context) const;
@@ -1457,7 +1469,7 @@
bool isElaboratedTypeSpecifier() const;
bool canDecayToPointerType() const;
-
+
/// hasPointerRepresentation - Whether this type is represented
/// natively as a pointer; this includes pointers, references, block
/// pointers, and Objective-C interface, qualified id, and qualified
@@ -4473,6 +4485,11 @@
return *this;
}
+inline bool QualType::isCForbiddenLValueType() const {
+ return ((getTypePtr()->isVoidType() && !hasQualifiers()) ||
+ getTypePtr()->isFunctionType());
+}
+
/// \brief Tests whether the type is categorized as a fundamental type.
///
/// \returns True for types specified in C++0x [basic.fundamental].
Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=133674&r1=133673&r2=133674&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Wed Jun 22 19:49:38 2011
@@ -2215,6 +2215,11 @@
ExprResult ActOnIdExpression(Scope *S, CXXScopeSpec &SS, UnqualifiedId &Name,
bool HasTrailingLParen, bool IsAddressOfOperand);
+ void DecomposeUnqualifiedId(const UnqualifiedId &Id,
+ TemplateArgumentListInfo &Buffer,
+ DeclarationNameInfo &NameInfo,
+ const TemplateArgumentListInfo *&TemplateArgs);
+
bool DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
CorrectTypoContext CTC = CTC_Unknown);
Modified: cfe/trunk/lib/Sema/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/CMakeLists.txt?rev=133674&r1=133673&r2=133674&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/CMakeLists.txt (original)
+++ cfe/trunk/lib/Sema/CMakeLists.txt Wed Jun 22 19:49:38 2011
@@ -23,6 +23,7 @@
SemaExceptionSpec.cpp
SemaExpr.cpp
SemaExprCXX.cpp
+ SemaExprMember.cpp
SemaExprObjC.cpp
SemaInit.cpp
SemaLookup.cpp
Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=133674&r1=133673&r2=133674&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Wed Jun 22 19:49:38 2011
@@ -1282,125 +1282,6 @@
return Owned(E);
}
-static ExprResult
-BuildFieldReferenceExpr(Sema &S, Expr *BaseExpr, bool IsArrow,
- const CXXScopeSpec &SS, FieldDecl *Field,
- DeclAccessPair FoundDecl,
- const DeclarationNameInfo &MemberNameInfo);
-
-ExprResult
-Sema::BuildAnonymousStructUnionMemberReference(const CXXScopeSpec &SS,
- SourceLocation loc,
- IndirectFieldDecl *indirectField,
- Expr *baseObjectExpr,
- SourceLocation opLoc) {
- // First, build the expression that refers to the base object.
-
- bool baseObjectIsPointer = false;
- Qualifiers baseQuals;
-
- // Case 1: the base of the indirect field is not a field.
- VarDecl *baseVariable = indirectField->getVarDecl();
- CXXScopeSpec EmptySS;
- if (baseVariable) {
- assert(baseVariable->getType()->isRecordType());
-
- // In principle we could have a member access expression that
- // accesses an anonymous struct/union that's a static member of
- // the base object's class. However, under the current standard,
- // static data members cannot be anonymous structs or unions.
- // Supporting this is as easy as building a MemberExpr here.
- assert(!baseObjectExpr && "anonymous struct/union is static data member?");
-
- DeclarationNameInfo baseNameInfo(DeclarationName(), loc);
-
- ExprResult result =
- BuildDeclarationNameExpr(EmptySS, baseNameInfo, baseVariable);
- if (result.isInvalid()) return ExprError();
-
- baseObjectExpr = result.take();
- baseObjectIsPointer = false;
- baseQuals = baseObjectExpr->getType().getQualifiers();
-
- // Case 2: the base of the indirect field is a field and the user
- // wrote a member expression.
- } else if (baseObjectExpr) {
- // The caller provided the base object expression. Determine
- // whether its a pointer and whether it adds any qualifiers to the
- // anonymous struct/union fields we're looking into.
- QualType objectType = baseObjectExpr->getType();
-
- if (const PointerType *ptr = objectType->getAs<PointerType>()) {
- baseObjectIsPointer = true;
- objectType = ptr->getPointeeType();
- } else {
- baseObjectIsPointer = false;
- }
- baseQuals = objectType.getQualifiers();
-
- // Case 3: the base of the indirect field is a field and we should
- // build an implicit member access.
- } else {
- // We've found a member of an anonymous struct/union that is
- // inside a non-anonymous struct/union, so in a well-formed
- // program our base object expression is "this".
- QualType ThisTy = getAndCaptureCurrentThisType();
- if (ThisTy.isNull()) {
- Diag(loc, diag::err_invalid_member_use_in_static_method)
- << indirectField->getDeclName();
- return ExprError();
- }
-
- // Our base object expression is "this".
- baseObjectExpr =
- new (Context) CXXThisExpr(loc, ThisTy, /*isImplicit=*/ true);
- baseObjectIsPointer = true;
- baseQuals = ThisTy->castAs<PointerType>()->getPointeeType().getQualifiers();
- }
-
- // Build the implicit member references to the field of the
- // anonymous struct/union.
- Expr *result = baseObjectExpr;
- IndirectFieldDecl::chain_iterator
- FI = indirectField->chain_begin(), FEnd = indirectField->chain_end();
-
- // Build the first member access in the chain with full information.
- if (!baseVariable) {
- FieldDecl *field = cast<FieldDecl>(*FI);
-
- // FIXME: use the real found-decl info!
- DeclAccessPair foundDecl = DeclAccessPair::make(field, field->getAccess());
-
- // Make a nameInfo that properly uses the anonymous name.
- DeclarationNameInfo memberNameInfo(field->getDeclName(), loc);
-
- result = BuildFieldReferenceExpr(*this, result, baseObjectIsPointer,
- EmptySS, field, foundDecl,
- memberNameInfo).take();
- baseObjectIsPointer = false;
-
- // FIXME: check qualified member access
- }
-
- // In all cases, we should now skip the first declaration in the chain.
- ++FI;
-
- while (FI != FEnd) {
- FieldDecl *field = cast<FieldDecl>(*FI++);
-
- // FIXME: these are somewhat meaningless
- DeclarationNameInfo memberNameInfo(field->getDeclName(), loc);
- DeclAccessPair foundDecl = DeclAccessPair::make(field, field->getAccess());
-
- result = BuildFieldReferenceExpr(*this, result, /*isarrow*/ false,
- (FI == FEnd? SS : EmptySS), field,
- foundDecl, memberNameInfo)
- .take();
- }
-
- return Owned(result);
-}
-
/// Decomposes the given name into a DeclarationNameInfo, its location, and
/// possibly a list of template arguments.
///
@@ -1410,217 +1291,30 @@
/// This actually loses a lot of source location information for
/// non-standard name kinds; we should consider preserving that in
/// some way.
-static void DecomposeUnqualifiedId(Sema &SemaRef,
- const UnqualifiedId &Id,
- TemplateArgumentListInfo &Buffer,
- DeclarationNameInfo &NameInfo,
- const TemplateArgumentListInfo *&TemplateArgs) {
+void Sema::DecomposeUnqualifiedId(const UnqualifiedId &Id,
+ TemplateArgumentListInfo &Buffer,
+ DeclarationNameInfo &NameInfo,
+ const TemplateArgumentListInfo *&TemplateArgs) {
if (Id.getKind() == UnqualifiedId::IK_TemplateId) {
Buffer.setLAngleLoc(Id.TemplateId->LAngleLoc);
Buffer.setRAngleLoc(Id.TemplateId->RAngleLoc);
- ASTTemplateArgsPtr TemplateArgsPtr(SemaRef,
+ ASTTemplateArgsPtr TemplateArgsPtr(*this,
Id.TemplateId->getTemplateArgs(),
Id.TemplateId->NumArgs);
- SemaRef.translateTemplateArguments(TemplateArgsPtr, Buffer);
+ translateTemplateArguments(TemplateArgsPtr, Buffer);
TemplateArgsPtr.release();
TemplateName TName = Id.TemplateId->Template.get();
SourceLocation TNameLoc = Id.TemplateId->TemplateNameLoc;
- NameInfo = SemaRef.Context.getNameForTemplate(TName, TNameLoc);
+ NameInfo = Context.getNameForTemplate(TName, TNameLoc);
TemplateArgs = &Buffer;
} else {
- NameInfo = SemaRef.GetNameFromUnqualifiedId(Id);
+ NameInfo = GetNameFromUnqualifiedId(Id);
TemplateArgs = 0;
}
}
-/// Determines if the given class is provably not derived from all of
-/// the prospective base classes.
-static bool IsProvablyNotDerivedFrom(Sema &SemaRef,
- CXXRecordDecl *Record,
- const llvm::SmallPtrSet<CXXRecordDecl*, 4> &Bases) {
- if (Bases.count(Record->getCanonicalDecl()))
- return false;
-
- RecordDecl *RD = Record->getDefinition();
- if (!RD) return false;
- Record = cast<CXXRecordDecl>(RD);
-
- for (CXXRecordDecl::base_class_iterator I = Record->bases_begin(),
- E = Record->bases_end(); I != E; ++I) {
- CanQualType BaseT = SemaRef.Context.getCanonicalType((*I).getType());
- CanQual<RecordType> BaseRT = BaseT->getAs<RecordType>();
- if (!BaseRT) return false;
-
- CXXRecordDecl *BaseRecord = cast<CXXRecordDecl>(BaseRT->getDecl());
- if (!IsProvablyNotDerivedFrom(SemaRef, BaseRecord, Bases))
- return false;
- }
-
- return true;
-}
-
-enum IMAKind {
- /// The reference is definitely not an instance member access.
- IMA_Static,
-
- /// The reference may be an implicit instance member access.
- IMA_Mixed,
-
- /// The reference may be to an instance member, but it is invalid if
- /// so, because the context is not an instance method.
- IMA_Mixed_StaticContext,
-
- /// The reference may be to an instance member, but it is invalid if
- /// so, because the context is from an unrelated class.
- IMA_Mixed_Unrelated,
-
- /// The reference is definitely an implicit instance member access.
- IMA_Instance,
-
- /// The reference may be to an unresolved using declaration.
- IMA_Unresolved,
-
- /// The reference may be to an unresolved using declaration and the
- /// context is not an instance method.
- IMA_Unresolved_StaticContext,
-
- /// All possible referrents are instance members and the current
- /// context is not an instance method.
- IMA_Error_StaticContext,
-
- /// All possible referrents are instance members of an unrelated
- /// class.
- IMA_Error_Unrelated
-};
-
-/// The given lookup names class member(s) and is not being used for
-/// an address-of-member expression. Classify the type of access
-/// according to whether it's possible that this reference names an
-/// instance member. This is best-effort; it is okay to
-/// conservatively answer "yes", in which case some errors will simply
-/// not be caught until template-instantiation.
-static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef,
- Scope *CurScope,
- const LookupResult &R) {
- assert(!R.empty() && (*R.begin())->isCXXClassMember());
-
- DeclContext *DC = SemaRef.getFunctionLevelDeclContext();
-
- bool isStaticContext =
- (!isa<CXXMethodDecl>(DC) ||
- cast<CXXMethodDecl>(DC)->isStatic());
-
- // C++0x [expr.prim]p4:
- // Otherwise, if a member-declarator declares a non-static data member
- // of a class X, the expression this is a prvalue of type "pointer to X"
- // within the optional brace-or-equal-initializer.
- if (CurScope->getFlags() & Scope::ThisScope)
- isStaticContext = false;
-
- if (R.isUnresolvableResult())
- return isStaticContext ? IMA_Unresolved_StaticContext : IMA_Unresolved;
-
- // Collect all the declaring classes of instance members we find.
- bool hasNonInstance = false;
- bool hasField = false;
- llvm::SmallPtrSet<CXXRecordDecl*, 4> Classes;
- for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) {
- NamedDecl *D = *I;
-
- if (D->isCXXInstanceMember()) {
- if (dyn_cast<FieldDecl>(D))
- hasField = true;
-
- CXXRecordDecl *R = cast<CXXRecordDecl>(D->getDeclContext());
- Classes.insert(R->getCanonicalDecl());
- }
- else
- hasNonInstance = true;
- }
-
- // If we didn't find any instance members, it can't be an implicit
- // member reference.
- if (Classes.empty())
- return IMA_Static;
-
- // If the current context is not an instance method, it can't be
- // an implicit member reference.
- if (isStaticContext) {
- if (hasNonInstance)
- return IMA_Mixed_StaticContext;
-
- if (SemaRef.getLangOptions().CPlusPlus0x && hasField) {
- // C++0x [expr.prim.general]p10:
- // An id-expression that denotes a non-static data member or non-static
- // member function of a class can only be used:
- // (...)
- // - if that id-expression denotes a non-static data member and it
- // appears in an unevaluated operand.
- const Sema::ExpressionEvaluationContextRecord& record
- = SemaRef.ExprEvalContexts.back();
- bool isUnevaluatedExpression = (record.Context == Sema::Unevaluated);
- if (isUnevaluatedExpression)
- return IMA_Mixed_StaticContext;
- }
-
- return IMA_Error_StaticContext;
- }
-
- CXXRecordDecl *contextClass;
- if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(DC))
- contextClass = MD->getParent()->getCanonicalDecl();
- else
- contextClass = cast<CXXRecordDecl>(DC);
-
- // [class.mfct.non-static]p3:
- // ...is used in the body of a non-static member function of class X,
- // if name lookup (3.4.1) resolves the name in the id-expression to a
- // non-static non-type member of some class C [...]
- // ...if C is not X or a base class of X, the class member access expression
- // is ill-formed.
- if (R.getNamingClass() &&
- contextClass != R.getNamingClass()->getCanonicalDecl() &&
- contextClass->isProvablyNotDerivedFrom(R.getNamingClass()))
- return (hasNonInstance ? IMA_Mixed_Unrelated : IMA_Error_Unrelated);
-
- // If we can prove that the current context is unrelated to all the
- // declaring classes, it can't be an implicit member reference (in
- // which case it's an error if any of those members are selected).
- if (IsProvablyNotDerivedFrom(SemaRef, contextClass, Classes))
- return (hasNonInstance ? IMA_Mixed_Unrelated : IMA_Error_Unrelated);
-
- return (hasNonInstance ? IMA_Mixed : IMA_Instance);
-}
-
-/// Diagnose a reference to a field with no object available.
-static void DiagnoseInstanceReference(Sema &SemaRef,
- const CXXScopeSpec &SS,
- NamedDecl *rep,
- const DeclarationNameInfo &nameInfo) {
- SourceLocation Loc = nameInfo.getLoc();
- SourceRange Range(Loc);
- if (SS.isSet()) Range.setBegin(SS.getRange().getBegin());
-
- if (isa<FieldDecl>(rep) || isa<IndirectFieldDecl>(rep)) {
- if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(SemaRef.CurContext)) {
- if (MD->isStatic()) {
- // "invalid use of member 'x' in static member function"
- SemaRef.Diag(Loc, diag::err_invalid_member_use_in_static_method)
- << Range << nameInfo.getName();
- return;
- }
- }
-
- SemaRef.Diag(Loc, diag::err_invalid_non_static_member_use)
- << nameInfo.getName() << Range;
- return;
- }
-
- SemaRef.Diag(Loc, diag::err_member_call_without_object) << Range;
-}
-
/// Diagnose an empty lookup.
///
/// \return false if new lookup candidates were found
@@ -1869,7 +1563,7 @@
// Decompose the UnqualifiedId into the following data.
DeclarationNameInfo NameInfo;
const TemplateArgumentListInfo *TemplateArgs;
- DecomposeUnqualifiedId(*this, Id, TemplateArgsBuffer, NameInfo, TemplateArgs);
+ DecomposeUnqualifiedId(Id, TemplateArgsBuffer, NameInfo, TemplateArgs);
DeclarationName Name = NameInfo.getName();
IdentifierInfo *II = Name.getAsIdentifierInfo();
@@ -2045,38 +1739,6 @@
return BuildDeclarationNameExpr(SS, R, ADL);
}
-/// Builds an expression which might be an implicit member expression.
-ExprResult
-Sema::BuildPossibleImplicitMemberExpr(const CXXScopeSpec &SS,
- LookupResult &R,
- const TemplateArgumentListInfo *TemplateArgs) {
- switch (ClassifyImplicitMemberAccess(*this, CurScope, R)) {
- case IMA_Instance:
- return BuildImplicitMemberExpr(SS, R, TemplateArgs, true);
-
- case IMA_Mixed:
- case IMA_Mixed_Unrelated:
- case IMA_Unresolved:
- return BuildImplicitMemberExpr(SS, R, TemplateArgs, false);
-
- case IMA_Static:
- case IMA_Mixed_StaticContext:
- case IMA_Unresolved_StaticContext:
- if (TemplateArgs)
- return BuildTemplateIdExpr(SS, R, false, *TemplateArgs);
- return BuildDeclarationNameExpr(SS, R, false);
-
- case IMA_Error_StaticContext:
- case IMA_Error_Unrelated:
- DiagnoseInstanceReference(*this, SS, R.getRepresentativeDecl(),
- R.getLookupNameInfo());
- return ExprError();
- }
-
- llvm_unreachable("unexpected instance member access kind");
- return ExprError();
-}
-
/// BuildQualifiedDeclarationNameExpr - Build a C++ qualified
/// declaration name, generally during template instantiation.
/// There's a large number of things which don't need to be done along
@@ -2398,120 +2060,6 @@
VK, &BasePath);
}
-/// \brief Build a MemberExpr AST node.
-static MemberExpr *BuildMemberExpr(ASTContext &C, Expr *Base, bool isArrow,
- const CXXScopeSpec &SS, ValueDecl *Member,
- DeclAccessPair FoundDecl,
- const DeclarationNameInfo &MemberNameInfo,
- QualType Ty,
- ExprValueKind VK, ExprObjectKind OK,
- const TemplateArgumentListInfo *TemplateArgs = 0) {
- return MemberExpr::Create(C, Base, isArrow, SS.getWithLocInContext(C),
- Member, FoundDecl, MemberNameInfo,
- TemplateArgs, Ty, VK, OK);
-}
-
-static ExprResult
-BuildFieldReferenceExpr(Sema &S, Expr *BaseExpr, bool IsArrow,
- const CXXScopeSpec &SS, FieldDecl *Field,
- DeclAccessPair FoundDecl,
- const DeclarationNameInfo &MemberNameInfo) {
- // x.a is an l-value if 'a' has a reference type. Otherwise:
- // x.a is an l-value/x-value/pr-value if the base is (and note
- // that *x is always an l-value), except that if the base isn't
- // an ordinary object then we must have an rvalue.
- ExprValueKind VK = VK_LValue;
- ExprObjectKind OK = OK_Ordinary;
- if (!IsArrow) {
- if (BaseExpr->getObjectKind() == OK_Ordinary)
- VK = BaseExpr->getValueKind();
- else
- VK = VK_RValue;
- }
- if (VK != VK_RValue && Field->isBitField())
- OK = OK_BitField;
-
- // Figure out the type of the member; see C99 6.5.2.3p3, C++ [expr.ref]
- QualType MemberType = Field->getType();
- if (const ReferenceType *Ref = MemberType->getAs<ReferenceType>()) {
- MemberType = Ref->getPointeeType();
- VK = VK_LValue;
- } else {
- QualType BaseType = BaseExpr->getType();
- if (IsArrow) BaseType = BaseType->getAs<PointerType>()->getPointeeType();
-
- Qualifiers BaseQuals = BaseType.getQualifiers();
-
- // GC attributes are never picked up by members.
- BaseQuals.removeObjCGCAttr();
-
- // CVR attributes from the base are picked up by members,
- // except that 'mutable' members don't pick up 'const'.
- if (Field->isMutable()) BaseQuals.removeConst();
-
- Qualifiers MemberQuals
- = S.Context.getCanonicalType(MemberType).getQualifiers();
-
- // TR 18037 does not allow fields to be declared with address spaces.
- assert(!MemberQuals.hasAddressSpace());
-
- Qualifiers Combined = BaseQuals + MemberQuals;
- if (Combined != MemberQuals)
- MemberType = S.Context.getQualifiedType(MemberType, Combined);
- }
-
- S.MarkDeclarationReferenced(MemberNameInfo.getLoc(), Field);
- ExprResult Base =
- S.PerformObjectMemberConversion(BaseExpr, SS.getScopeRep(),
- FoundDecl, Field);
- if (Base.isInvalid())
- return ExprError();
- return S.Owned(BuildMemberExpr(S.Context, Base.take(), IsArrow, SS,
- Field, FoundDecl, MemberNameInfo,
- MemberType, VK, OK));
-}
-
-/// Builds an implicit member access expression. The current context
-/// is known to be an instance method, and the given unqualified lookup
-/// set is known to contain only instance members, at least one of which
-/// is from an appropriate type.
-ExprResult
-Sema::BuildImplicitMemberExpr(const CXXScopeSpec &SS,
- LookupResult &R,
- const TemplateArgumentListInfo *TemplateArgs,
- bool IsKnownInstance) {
- assert(!R.empty() && !R.isAmbiguous());
-
- SourceLocation loc = R.getNameLoc();
-
- // We may have found a field within an anonymous union or struct
- // (C++ [class.union]).
- // FIXME: template-ids inside anonymous structs?
- if (IndirectFieldDecl *FD = R.getAsSingle<IndirectFieldDecl>())
- return BuildAnonymousStructUnionMemberReference(SS, R.getNameLoc(), FD);
-
- // If this is known to be an instance access, go ahead and build an
- // implicit 'this' expression now.
- // 'this' expression now.
- QualType ThisTy = getAndCaptureCurrentThisType();
- assert(!ThisTy.isNull() && "didn't correctly pre-flight capture of 'this'");
-
- Expr *baseExpr = 0; // null signifies implicit access
- if (IsKnownInstance) {
- SourceLocation Loc = R.getNameLoc();
- if (SS.getRange().isValid())
- Loc = SS.getRange().getBegin();
- baseExpr = new (Context) CXXThisExpr(loc, ThisTy, /*isImplicit=*/true);
- }
-
- return BuildMemberReferenceExpr(baseExpr, ThisTy,
- /*OpLoc*/ SourceLocation(),
- /*IsArrow*/ true,
- SS,
- /*FirstQualifierInScope*/ 0,
- R, TemplateArgs);
-}
-
bool Sema::UseArgumentDependentLookup(const CXXScopeSpec &SS,
const LookupResult &R,
bool HasTrailingLParen) {
@@ -3401,19 +2949,6 @@
return BuildUnaryOp(S, OpLoc, Opc, Input);
}
-/// Expressions of certain arbitrary types are forbidden by C from
-/// having l-value type. These are:
-/// - 'void', but not qualified void
-/// - function types
-///
-/// The exact rule here is C99 6.3.2.1:
-/// An lvalue is an expression with an object type or an incomplete
-/// type other than void.
-static bool IsCForbiddenLValueType(ASTContext &C, QualType T) {
- return ((T->isVoidType() && !T.hasQualifiers()) ||
- T->isFunctionType());
-}
-
ExprResult
Sema::ActOnArraySubscriptExpr(Scope *S, Expr *Base, SourceLocation LLoc,
Expr *Idx, SourceLocation RLoc) {
@@ -3577,1122 +3112,12 @@
}
assert(VK == VK_RValue || LangOpts.CPlusPlus ||
- !IsCForbiddenLValueType(Context, ResultType));
+ !ResultType.isCForbiddenLValueType());
return Owned(new (Context) ArraySubscriptExpr(LHSExp, RHSExp,
ResultType, VK, OK, RLoc));
}
-/// Check an ext-vector component access expression.
-///
-/// VK should be set in advance to the value kind of the base
-/// expression.
-static QualType
-CheckExtVectorComponent(Sema &S, QualType baseType, ExprValueKind &VK,
- SourceLocation OpLoc, const IdentifierInfo *CompName,
- SourceLocation CompLoc) {
- // FIXME: Share logic with ExtVectorElementExpr::containsDuplicateElements,
- // see FIXME there.
- //
- // FIXME: This logic can be greatly simplified by splitting it along
- // halving/not halving and reworking the component checking.
- const ExtVectorType *vecType = baseType->getAs<ExtVectorType>();
-
- // The vector accessor can't exceed the number of elements.
- const char *compStr = CompName->getNameStart();
-
- // This flag determines whether or not the component is one of the four
- // special names that indicate a subset of exactly half the elements are
- // to be selected.
- bool HalvingSwizzle = false;
-
- // This flag determines whether or not CompName has an 's' char prefix,
- // indicating that it is a string of hex values to be used as vector indices.
- bool HexSwizzle = *compStr == 's' || *compStr == 'S';
-
- bool HasRepeated = false;
- bool HasIndex[16] = {};
-
- int Idx;
-
- // Check that we've found one of the special components, or that the component
- // names must come from the same set.
- if (!strcmp(compStr, "hi") || !strcmp(compStr, "lo") ||
- !strcmp(compStr, "even") || !strcmp(compStr, "odd")) {
- HalvingSwizzle = true;
- } else if (!HexSwizzle &&
- (Idx = vecType->getPointAccessorIdx(*compStr)) != -1) {
- do {
- if (HasIndex[Idx]) HasRepeated = true;
- HasIndex[Idx] = true;
- compStr++;
- } while (*compStr && (Idx = vecType->getPointAccessorIdx(*compStr)) != -1);
- } else {
- if (HexSwizzle) compStr++;
- while ((Idx = vecType->getNumericAccessorIdx(*compStr)) != -1) {
- if (HasIndex[Idx]) HasRepeated = true;
- HasIndex[Idx] = true;
- compStr++;
- }
- }
-
- if (!HalvingSwizzle && *compStr) {
- // We didn't get to the end of the string. This means the component names
- // didn't come from the same set *or* we encountered an illegal name.
- S.Diag(OpLoc, diag::err_ext_vector_component_name_illegal)
- << llvm::StringRef(compStr, 1) << SourceRange(CompLoc);
- return QualType();
- }
-
- // Ensure no component accessor exceeds the width of the vector type it
- // operates on.
- if (!HalvingSwizzle) {
- compStr = CompName->getNameStart();
-
- if (HexSwizzle)
- compStr++;
-
- while (*compStr) {
- if (!vecType->isAccessorWithinNumElements(*compStr++)) {
- S.Diag(OpLoc, diag::err_ext_vector_component_exceeds_length)
- << baseType << SourceRange(CompLoc);
- return QualType();
- }
- }
- }
-
- // The component accessor looks fine - now we need to compute the actual type.
- // The vector type is implied by the component accessor. For example,
- // vec4.b is a float, vec4.xy is a vec2, vec4.rgb is a vec3, etc.
- // vec4.s0 is a float, vec4.s23 is a vec3, etc.
- // vec4.hi, vec4.lo, vec4.e, and vec4.o all return vec2.
- unsigned CompSize = HalvingSwizzle ? (vecType->getNumElements() + 1) / 2
- : CompName->getLength();
- if (HexSwizzle)
- CompSize--;
-
- if (CompSize == 1)
- return vecType->getElementType();
-
- if (HasRepeated) VK = VK_RValue;
-
- QualType VT = S.Context.getExtVectorType(vecType->getElementType(), CompSize);
- // Now look up the TypeDefDecl from the vector type. Without this,
- // diagostics look bad. We want extended vector types to appear built-in.
- for (unsigned i = 0, E = S.ExtVectorDecls.size(); i != E; ++i) {
- if (S.ExtVectorDecls[i]->getUnderlyingType() == VT)
- return S.Context.getTypedefType(S.ExtVectorDecls[i]);
- }
- return VT; // should never get here (a typedef type should always be found).
-}
-
-static Decl *FindGetterSetterNameDeclFromProtocolList(const ObjCProtocolDecl*PDecl,
- IdentifierInfo *Member,
- const Selector &Sel,
- ASTContext &Context) {
- if (Member)
- if (ObjCPropertyDecl *PD = PDecl->FindPropertyDeclaration(Member))
- return PD;
- if (ObjCMethodDecl *OMD = PDecl->getInstanceMethod(Sel))
- return OMD;
-
- for (ObjCProtocolDecl::protocol_iterator I = PDecl->protocol_begin(),
- E = PDecl->protocol_end(); I != E; ++I) {
- if (Decl *D = FindGetterSetterNameDeclFromProtocolList(*I, Member, Sel,
- Context))
- return D;
- }
- return 0;
-}
-
-static Decl *FindGetterSetterNameDecl(const ObjCObjectPointerType *QIdTy,
- IdentifierInfo *Member,
- const Selector &Sel,
- ASTContext &Context) {
- // Check protocols on qualified interfaces.
- Decl *GDecl = 0;
- for (ObjCObjectPointerType::qual_iterator I = QIdTy->qual_begin(),
- E = QIdTy->qual_end(); I != E; ++I) {
- if (Member)
- if (ObjCPropertyDecl *PD = (*I)->FindPropertyDeclaration(Member)) {
- GDecl = PD;
- break;
- }
- // Also must look for a getter or setter name which uses property syntax.
- if (ObjCMethodDecl *OMD = (*I)->getInstanceMethod(Sel)) {
- GDecl = OMD;
- break;
- }
- }
- if (!GDecl) {
- for (ObjCObjectPointerType::qual_iterator I = QIdTy->qual_begin(),
- E = QIdTy->qual_end(); I != E; ++I) {
- // Search in the protocol-qualifier list of current protocol.
- GDecl = FindGetterSetterNameDeclFromProtocolList(*I, Member, Sel,
- Context);
- if (GDecl)
- return GDecl;
- }
- }
- return GDecl;
-}
-
-ExprResult
-Sema::ActOnDependentMemberExpr(Expr *BaseExpr, QualType BaseType,
- bool IsArrow, SourceLocation OpLoc,
- const CXXScopeSpec &SS,
- NamedDecl *FirstQualifierInScope,
- const DeclarationNameInfo &NameInfo,
- const TemplateArgumentListInfo *TemplateArgs) {
- // Even in dependent contexts, try to diagnose base expressions with
- // obviously wrong types, e.g.:
- //
- // T* t;
- // t.f;
- //
- // In Obj-C++, however, the above expression is valid, since it could be
- // accessing the 'f' property if T is an Obj-C interface. The extra check
- // allows this, while still reporting an error if T is a struct pointer.
- if (!IsArrow) {
- const PointerType *PT = BaseType->getAs<PointerType>();
- if (PT && (!getLangOptions().ObjC1 ||
- PT->getPointeeType()->isRecordType())) {
- assert(BaseExpr && "cannot happen with implicit member accesses");
- Diag(NameInfo.getLoc(), diag::err_typecheck_member_reference_struct_union)
- << BaseType << BaseExpr->getSourceRange();
- return ExprError();
- }
- }
-
- assert(BaseType->isDependentType() ||
- NameInfo.getName().isDependentName() ||
- isDependentScopeSpecifier(SS));
-
- // Get the type being accessed in BaseType. If this is an arrow, the BaseExpr
- // must have pointer type, and the accessed type is the pointee.
- return Owned(CXXDependentScopeMemberExpr::Create(Context, BaseExpr, BaseType,
- IsArrow, OpLoc,
- SS.getWithLocInContext(Context),
- FirstQualifierInScope,
- NameInfo, TemplateArgs));
-}
-
-/// We know that the given qualified member reference points only to
-/// declarations which do not belong to the static type of the base
-/// expression. Diagnose the problem.
-static void DiagnoseQualifiedMemberReference(Sema &SemaRef,
- Expr *BaseExpr,
- QualType BaseType,
- const CXXScopeSpec &SS,
- NamedDecl *rep,
- const DeclarationNameInfo &nameInfo) {
- // If this is an implicit member access, use a different set of
- // diagnostics.
- if (!BaseExpr)
- return DiagnoseInstanceReference(SemaRef, SS, rep, nameInfo);
-
- SemaRef.Diag(nameInfo.getLoc(), diag::err_qualified_member_of_unrelated)
- << SS.getRange() << rep << BaseType;
-}
-
-// Check whether the declarations we found through a nested-name
-// specifier in a member expression are actually members of the base
-// type. The restriction here is:
-//
-// C++ [expr.ref]p2:
-// ... In these cases, the id-expression shall name a
-// member of the class or of one of its base classes.
-//
-// So it's perfectly legitimate for the nested-name specifier to name
-// an unrelated class, and for us to find an overload set including
-// decls from classes which are not superclasses, as long as the decl
-// we actually pick through overload resolution is from a superclass.
-bool Sema::CheckQualifiedMemberReference(Expr *BaseExpr,
- QualType BaseType,
- const CXXScopeSpec &SS,
- const LookupResult &R) {
- const RecordType *BaseRT = BaseType->getAs<RecordType>();
- if (!BaseRT) {
- // We can't check this yet because the base type is still
- // dependent.
- assert(BaseType->isDependentType());
- return false;
- }
- CXXRecordDecl *BaseRecord = cast<CXXRecordDecl>(BaseRT->getDecl());
-
- for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) {
- // If this is an implicit member reference and we find a
- // non-instance member, it's not an error.
- if (!BaseExpr && !(*I)->isCXXInstanceMember())
- return false;
-
- // Note that we use the DC of the decl, not the underlying decl.
- DeclContext *DC = (*I)->getDeclContext();
- while (DC->isTransparentContext())
- DC = DC->getParent();
-
- if (!DC->isRecord())
- continue;
-
- llvm::SmallPtrSet<CXXRecordDecl*,4> MemberRecord;
- MemberRecord.insert(cast<CXXRecordDecl>(DC)->getCanonicalDecl());
-
- if (!IsProvablyNotDerivedFrom(*this, BaseRecord, MemberRecord))
- return false;
- }
-
- DiagnoseQualifiedMemberReference(*this, BaseExpr, BaseType, SS,
- R.getRepresentativeDecl(),
- R.getLookupNameInfo());
- return true;
-}
-
-static bool
-LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
- SourceRange BaseRange, const RecordType *RTy,
- SourceLocation OpLoc, CXXScopeSpec &SS,
- bool HasTemplateArgs) {
- RecordDecl *RDecl = RTy->getDecl();
- if (SemaRef.RequireCompleteType(OpLoc, QualType(RTy, 0),
- SemaRef.PDiag(diag::err_typecheck_incomplete_tag)
- << BaseRange))
- return true;
-
- if (HasTemplateArgs) {
- // LookupTemplateName doesn't expect these both to exist simultaneously.
- QualType ObjectType = SS.isSet() ? QualType() : QualType(RTy, 0);
-
- bool MOUS;
- SemaRef.LookupTemplateName(R, 0, SS, ObjectType, false, MOUS);
- return false;
- }
-
- DeclContext *DC = RDecl;
- if (SS.isSet()) {
- // If the member name was a qualified-id, look into the
- // nested-name-specifier.
- DC = SemaRef.computeDeclContext(SS, false);
-
- if (SemaRef.RequireCompleteDeclContext(SS, DC)) {
- SemaRef.Diag(SS.getRange().getEnd(), diag::err_typecheck_incomplete_tag)
- << SS.getRange() << DC;
- return true;
- }
-
- assert(DC && "Cannot handle non-computable dependent contexts in lookup");
-
- if (!isa<TypeDecl>(DC)) {
- SemaRef.Diag(R.getNameLoc(), diag::err_qualified_member_nonclass)
- << DC << SS.getRange();
- return true;
- }
- }
-
- // The record definition is complete, now look up the member.
- SemaRef.LookupQualifiedName(R, DC);
-
- if (!R.empty())
- return false;
-
- // We didn't find anything with the given name, so try to correct
- // for typos.
- DeclarationName Name = R.getLookupName();
- if (SemaRef.CorrectTypo(R, 0, &SS, DC, false, Sema::CTC_MemberLookup) &&
- !R.empty() &&
- (isa<ValueDecl>(*R.begin()) || isa<FunctionTemplateDecl>(*R.begin()))) {
- SemaRef.Diag(R.getNameLoc(), diag::err_no_member_suggest)
- << Name << DC << R.getLookupName() << SS.getRange()
- << FixItHint::CreateReplacement(R.getNameLoc(),
- R.getLookupName().getAsString());
- if (NamedDecl *ND = R.getAsSingle<NamedDecl>())
- SemaRef.Diag(ND->getLocation(), diag::note_previous_decl)
- << ND->getDeclName();
- return false;
- } else {
- R.clear();
- R.setLookupName(Name);
- }
-
- return false;
-}
-
-ExprResult
-Sema::BuildMemberReferenceExpr(Expr *Base, QualType BaseType,
- SourceLocation OpLoc, bool IsArrow,
- CXXScopeSpec &SS,
- NamedDecl *FirstQualifierInScope,
- const DeclarationNameInfo &NameInfo,
- const TemplateArgumentListInfo *TemplateArgs) {
- if (BaseType->isDependentType() ||
- (SS.isSet() && isDependentScopeSpecifier(SS)))
- return ActOnDependentMemberExpr(Base, BaseType,
- IsArrow, OpLoc,
- SS, FirstQualifierInScope,
- NameInfo, TemplateArgs);
-
- LookupResult R(*this, NameInfo, LookupMemberName);
-
- // Implicit member accesses.
- if (!Base) {
- QualType RecordTy = BaseType;
- if (IsArrow) RecordTy = RecordTy->getAs<PointerType>()->getPointeeType();
- if (LookupMemberExprInRecord(*this, R, SourceRange(),
- RecordTy->getAs<RecordType>(),
- OpLoc, SS, TemplateArgs != 0))
- return ExprError();
-
- // Explicit member accesses.
- } else {
- ExprResult BaseResult = Owned(Base);
- ExprResult Result =
- LookupMemberExpr(R, BaseResult, IsArrow, OpLoc,
- SS, /*ObjCImpDecl*/ 0, TemplateArgs != 0);
-
- if (BaseResult.isInvalid())
- return ExprError();
- Base = BaseResult.take();
-
- if (Result.isInvalid()) {
- Owned(Base);
- return ExprError();
- }
-
- if (Result.get())
- return move(Result);
-
- // LookupMemberExpr can modify Base, and thus change BaseType
- BaseType = Base->getType();
- }
-
- return BuildMemberReferenceExpr(Base, BaseType,
- OpLoc, IsArrow, SS, FirstQualifierInScope,
- R, TemplateArgs);
-}
-
-ExprResult
-Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
- SourceLocation OpLoc, bool IsArrow,
- const CXXScopeSpec &SS,
- NamedDecl *FirstQualifierInScope,
- LookupResult &R,
- const TemplateArgumentListInfo *TemplateArgs,
- bool SuppressQualifierCheck) {
- QualType BaseType = BaseExprType;
- if (IsArrow) {
- assert(BaseType->isPointerType());
- BaseType = BaseType->getAs<PointerType>()->getPointeeType();
- }
- R.setBaseObjectType(BaseType);
-
- const DeclarationNameInfo &MemberNameInfo = R.getLookupNameInfo();
- DeclarationName MemberName = MemberNameInfo.getName();
- SourceLocation MemberLoc = MemberNameInfo.getLoc();
-
- if (R.isAmbiguous())
- return ExprError();
-
- if (R.empty()) {
- // Rederive where we looked up.
- DeclContext *DC = (SS.isSet()
- ? computeDeclContext(SS, false)
- : BaseType->getAs<RecordType>()->getDecl());
-
- Diag(R.getNameLoc(), diag::err_no_member)
- << MemberName << DC
- << (BaseExpr ? BaseExpr->getSourceRange() : SourceRange());
- return ExprError();
- }
-
- // Diagnose lookups that find only declarations from a non-base
- // type. This is possible for either qualified lookups (which may
- // have been qualified with an unrelated type) or implicit member
- // expressions (which were found with unqualified lookup and thus
- // may have come from an enclosing scope). Note that it's okay for
- // lookup to find declarations from a non-base type as long as those
- // aren't the ones picked by overload resolution.
- if ((SS.isSet() || !BaseExpr ||
- (isa<CXXThisExpr>(BaseExpr) &&
- cast<CXXThisExpr>(BaseExpr)->isImplicit())) &&
- !SuppressQualifierCheck &&
- CheckQualifiedMemberReference(BaseExpr, BaseType, SS, R))
- return ExprError();
-
- // Construct an unresolved result if we in fact got an unresolved
- // result.
- if (R.isOverloadedResult() || R.isUnresolvableResult()) {
- // Suppress any lookup-related diagnostics; we'll do these when we
- // pick a member.
- R.suppressDiagnostics();
-
- UnresolvedMemberExpr *MemExpr
- = UnresolvedMemberExpr::Create(Context, R.isUnresolvableResult(),
- BaseExpr, BaseExprType,
- IsArrow, OpLoc,
- SS.getWithLocInContext(Context),
- MemberNameInfo,
- TemplateArgs, R.begin(), R.end());
-
- return Owned(MemExpr);
- }
-
- assert(R.isSingleResult());
- DeclAccessPair FoundDecl = R.begin().getPair();
- NamedDecl *MemberDecl = R.getFoundDecl();
-
- // FIXME: diagnose the presence of template arguments now.
-
- // If the decl being referenced had an error, return an error for this
- // sub-expr without emitting another error, in order to avoid cascading
- // error cases.
- if (MemberDecl->isInvalidDecl())
- return ExprError();
-
- // Handle the implicit-member-access case.
- if (!BaseExpr) {
- // If this is not an instance member, convert to a non-member access.
- if (!MemberDecl->isCXXInstanceMember())
- return BuildDeclarationNameExpr(SS, R.getLookupNameInfo(), MemberDecl);
-
- SourceLocation Loc = R.getNameLoc();
- if (SS.getRange().isValid())
- Loc = SS.getRange().getBegin();
- BaseExpr = new (Context) CXXThisExpr(Loc, BaseExprType,/*isImplicit=*/true);
- }
-
- bool ShouldCheckUse = true;
- if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(MemberDecl)) {
- // Don't diagnose the use of a virtual member function unless it's
- // explicitly qualified.
- if (MD->isVirtual() && !SS.isSet())
- ShouldCheckUse = false;
- }
-
- // Check the use of this member.
- if (ShouldCheckUse && DiagnoseUseOfDecl(MemberDecl, MemberLoc)) {
- Owned(BaseExpr);
- return ExprError();
- }
-
- // Perform a property load on the base regardless of whether we
- // actually need it for the declaration.
- if (BaseExpr->getObjectKind() == OK_ObjCProperty) {
- ExprResult Result = ConvertPropertyForRValue(BaseExpr);
- if (Result.isInvalid())
- return ExprError();
- BaseExpr = Result.take();
- }
-
- if (FieldDecl *FD = dyn_cast<FieldDecl>(MemberDecl))
- return BuildFieldReferenceExpr(*this, BaseExpr, IsArrow,
- SS, FD, FoundDecl, MemberNameInfo);
-
- if (IndirectFieldDecl *FD = dyn_cast<IndirectFieldDecl>(MemberDecl))
- // We may have found a field within an anonymous union or struct
- // (C++ [class.union]).
- return BuildAnonymousStructUnionMemberReference(SS, MemberLoc, FD,
- BaseExpr, OpLoc);
-
- if (VarDecl *Var = dyn_cast<VarDecl>(MemberDecl)) {
- MarkDeclarationReferenced(MemberLoc, Var);
- return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS,
- Var, FoundDecl, MemberNameInfo,
- Var->getType().getNonReferenceType(),
- VK_LValue, OK_Ordinary));
- }
-
- if (CXXMethodDecl *MemberFn = dyn_cast<CXXMethodDecl>(MemberDecl)) {
- ExprValueKind valueKind;
- QualType type;
- if (MemberFn->isInstance()) {
- valueKind = VK_RValue;
- type = Context.BoundMemberTy;
- } else {
- valueKind = VK_LValue;
- type = MemberFn->getType();
- }
-
- MarkDeclarationReferenced(MemberLoc, MemberDecl);
- return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS,
- MemberFn, FoundDecl, MemberNameInfo,
- type, valueKind, OK_Ordinary));
- }
- assert(!isa<FunctionDecl>(MemberDecl) && "member function not C++ method?");
-
- if (EnumConstantDecl *Enum = dyn_cast<EnumConstantDecl>(MemberDecl)) {
- MarkDeclarationReferenced(MemberLoc, MemberDecl);
- return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS,
- Enum, FoundDecl, MemberNameInfo,
- Enum->getType(), VK_RValue, OK_Ordinary));
- }
-
- Owned(BaseExpr);
-
- // We found something that we didn't expect. Complain.
- if (isa<TypeDecl>(MemberDecl))
- Diag(MemberLoc, diag::err_typecheck_member_reference_type)
- << MemberName << BaseType << int(IsArrow);
- else
- Diag(MemberLoc, diag::err_typecheck_member_reference_unknown)
- << MemberName << BaseType << int(IsArrow);
-
- Diag(MemberDecl->getLocation(), diag::note_member_declared_here)
- << MemberName;
- R.suppressDiagnostics();
- return ExprError();
-}
-
-/// Given that normal member access failed on the given expression,
-/// and given that the expression's type involves builtin-id or
-/// builtin-Class, decide whether substituting in the redefinition
-/// types would be profitable. The redefinition type is whatever
-/// this translation unit tried to typedef to id/Class; we store
-/// it to the side and then re-use it in places like this.
-static bool ShouldTryAgainWithRedefinitionType(Sema &S, ExprResult &base) {
- const ObjCObjectPointerType *opty
- = base.get()->getType()->getAs<ObjCObjectPointerType>();
- if (!opty) return false;
-
- const ObjCObjectType *ty = opty->getObjectType();
-
- QualType redef;
- if (ty->isObjCId()) {
- redef = S.Context.ObjCIdRedefinitionType;
- } else if (ty->isObjCClass()) {
- redef = S.Context.ObjCClassRedefinitionType;
- } else {
- return false;
- }
-
- // Do the substitution as long as the redefinition type isn't just a
- // possibly-qualified pointer to builtin-id or builtin-Class again.
- opty = redef->getAs<ObjCObjectPointerType>();
- if (opty && !opty->getObjectType()->getInterface() != 0)
- return false;
-
- base = S.ImpCastExprToType(base.take(), redef, CK_BitCast);
- return true;
-}
-
-/// Look up the given member of the given non-type-dependent
-/// expression. This can return in one of two ways:
-/// * If it returns a sentinel null-but-valid result, the caller will
-/// assume that lookup was performed and the results written into
-/// the provided structure. It will take over from there.
-/// * Otherwise, the returned expression will be produced in place of
-/// an ordinary member expression.
-///
-/// The ObjCImpDecl bit is a gross hack that will need to be properly
-/// fixed for ObjC++.
-ExprResult
-Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr,
- bool &IsArrow, SourceLocation OpLoc,
- CXXScopeSpec &SS,
- Decl *ObjCImpDecl, bool HasTemplateArgs) {
- assert(BaseExpr.get() && "no base expression");
-
- // Perform default conversions.
- BaseExpr = DefaultFunctionArrayConversion(BaseExpr.take());
-
- if (IsArrow) {
- BaseExpr = DefaultLvalueConversion(BaseExpr.take());
- if (BaseExpr.isInvalid())
- return ExprError();
- }
-
- QualType BaseType = BaseExpr.get()->getType();
- assert(!BaseType->isDependentType());
-
- DeclarationName MemberName = R.getLookupName();
- SourceLocation MemberLoc = R.getNameLoc();
-
- // For later type-checking purposes, turn arrow accesses into dot
- // accesses. The only access type we support that doesn't follow
- // the C equivalence "a->b === (*a).b" is ObjC property accesses,
- // and those never use arrows, so this is unaffected.
- if (IsArrow) {
- if (const PointerType *Ptr = BaseType->getAs<PointerType>())
- BaseType = Ptr->getPointeeType();
- else if (const ObjCObjectPointerType *Ptr
- = BaseType->getAs<ObjCObjectPointerType>())
- BaseType = Ptr->getPointeeType();
- else if (BaseType->isRecordType()) {
- // Recover from arrow accesses to records, e.g.:
- // struct MyRecord foo;
- // foo->bar
- // This is actually well-formed in C++ if MyRecord has an
- // overloaded operator->, but that should have been dealt with
- // by now.
- Diag(OpLoc, diag::err_typecheck_member_reference_suggestion)
- << BaseType << int(IsArrow) << BaseExpr.get()->getSourceRange()
- << FixItHint::CreateReplacement(OpLoc, ".");
- IsArrow = false;
- } else if (BaseType == Context.BoundMemberTy) {
- goto fail;
- } else {
- Diag(MemberLoc, diag::err_typecheck_member_reference_arrow)
- << BaseType << BaseExpr.get()->getSourceRange();
- return ExprError();
- }
- }
-
- // Handle field access to simple records.
- if (const RecordType *RTy = BaseType->getAs<RecordType>()) {
- if (LookupMemberExprInRecord(*this, R, BaseExpr.get()->getSourceRange(),
- RTy, OpLoc, SS, HasTemplateArgs))
- return ExprError();
-
- // Returning valid-but-null is how we indicate to the caller that
- // the lookup result was filled in.
- return Owned((Expr*) 0);
- }
-
- // Handle ivar access to Objective-C objects.
- if (const ObjCObjectType *OTy = BaseType->getAs<ObjCObjectType>()) {
- IdentifierInfo *Member = MemberName.getAsIdentifierInfo();
-
- // There are three cases for the base type:
- // - builtin id (qualified or unqualified)
- // - builtin Class (qualified or unqualified)
- // - an interface
- ObjCInterfaceDecl *IDecl = OTy->getInterface();
- if (!IDecl) {
- if (getLangOptions().ObjCAutoRefCount &&
- (OTy->isObjCId() || OTy->isObjCClass()))
- goto fail;
- // There's an implicit 'isa' ivar on all objects.
- // But we only actually find it this way on objects of type 'id',
- // apparently.
- if (OTy->isObjCId() && Member->isStr("isa"))
- return Owned(new (Context) ObjCIsaExpr(BaseExpr.take(), IsArrow, MemberLoc,
- Context.getObjCClassType()));
-
- if (ShouldTryAgainWithRedefinitionType(*this, BaseExpr))
- return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS,
- ObjCImpDecl, HasTemplateArgs);
- goto fail;
- }
-
- ObjCInterfaceDecl *ClassDeclared;
- ObjCIvarDecl *IV = IDecl->lookupInstanceVariable(Member, ClassDeclared);
-
- if (!IV) {
- // Attempt to correct for typos in ivar names.
- LookupResult Res(*this, R.getLookupName(), R.getNameLoc(),
- LookupMemberName);
- if (CorrectTypo(Res, 0, 0, IDecl, false,
- IsArrow ? CTC_ObjCIvarLookup
- : CTC_ObjCPropertyLookup) &&
- (IV = Res.getAsSingle<ObjCIvarDecl>())) {
- Diag(R.getNameLoc(),
- diag::err_typecheck_member_reference_ivar_suggest)
- << IDecl->getDeclName() << MemberName << IV->getDeclName()
- << FixItHint::CreateReplacement(R.getNameLoc(),
- IV->getNameAsString());
- Diag(IV->getLocation(), diag::note_previous_decl)
- << IV->getDeclName();
- } else {
- Res.clear();
- Res.setLookupName(Member);
-
- Diag(MemberLoc, diag::err_typecheck_member_reference_ivar)
- << IDecl->getDeclName() << MemberName
- << BaseExpr.get()->getSourceRange();
- return ExprError();
- }
- }
-
- // If the decl being referenced had an error, return an error for this
- // sub-expr without emitting another error, in order to avoid cascading
- // error cases.
- if (IV->isInvalidDecl())
- return ExprError();
-
- // Check whether we can reference this field.
- if (DiagnoseUseOfDecl(IV, MemberLoc))
- return ExprError();
- if (IV->getAccessControl() != ObjCIvarDecl::Public &&
- IV->getAccessControl() != ObjCIvarDecl::Package) {
- ObjCInterfaceDecl *ClassOfMethodDecl = 0;
- if (ObjCMethodDecl *MD = getCurMethodDecl())
- ClassOfMethodDecl = MD->getClassInterface();
- else if (ObjCImpDecl && getCurFunctionDecl()) {
- // Case of a c-function declared inside an objc implementation.
- // FIXME: For a c-style function nested inside an objc implementation
- // class, there is no implementation context available, so we pass
- // down the context as argument to this routine. Ideally, this context
- // need be passed down in the AST node and somehow calculated from the
- // AST for a function decl.
- if (ObjCImplementationDecl *IMPD =
- dyn_cast<ObjCImplementationDecl>(ObjCImpDecl))
- ClassOfMethodDecl = IMPD->getClassInterface();
- else if (ObjCCategoryImplDecl* CatImplClass =
- dyn_cast<ObjCCategoryImplDecl>(ObjCImpDecl))
- ClassOfMethodDecl = CatImplClass->getClassInterface();
- }
-
- if (IV->getAccessControl() == ObjCIvarDecl::Private) {
- if (ClassDeclared != IDecl ||
- ClassOfMethodDecl != ClassDeclared)
- Diag(MemberLoc, diag::error_private_ivar_access)
- << IV->getDeclName();
- } else if (!IDecl->isSuperClassOf(ClassOfMethodDecl))
- // @protected
- Diag(MemberLoc, diag::error_protected_ivar_access)
- << IV->getDeclName();
- }
- if (getLangOptions().ObjCAutoRefCount) {
- Expr *BaseExp = BaseExpr.get()->IgnoreParenImpCasts();
- if (UnaryOperator *UO = dyn_cast<UnaryOperator>(BaseExp))
- if (UO->getOpcode() == UO_Deref)
- BaseExp = UO->getSubExpr()->IgnoreParenCasts();
-
- if (DeclRefExpr *DE = dyn_cast<DeclRefExpr>(BaseExp))
- if (DE->getType().getObjCLifetime() == Qualifiers::OCL_Weak)
- Diag(DE->getLocation(), diag::error_arc_weak_ivar_access);
- }
-
- return Owned(new (Context) ObjCIvarRefExpr(IV, IV->getType(),
- MemberLoc, BaseExpr.take(),
- IsArrow));
- }
-
- // Objective-C property access.
- const ObjCObjectPointerType *OPT;
- if (!IsArrow && (OPT = BaseType->getAs<ObjCObjectPointerType>())) {
- // This actually uses the base as an r-value.
- BaseExpr = DefaultLvalueConversion(BaseExpr.take());
- if (BaseExpr.isInvalid())
- return ExprError();
-
- assert(Context.hasSameUnqualifiedType(BaseType, BaseExpr.get()->getType()));
-
- IdentifierInfo *Member = MemberName.getAsIdentifierInfo();
-
- const ObjCObjectType *OT = OPT->getObjectType();
-
- // id, with and without qualifiers.
- if (OT->isObjCId()) {
- // Check protocols on qualified interfaces.
- Selector Sel = PP.getSelectorTable().getNullarySelector(Member);
- if (Decl *PMDecl = FindGetterSetterNameDecl(OPT, Member, Sel, Context)) {
- if (ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(PMDecl)) {
- // Check the use of this declaration
- if (DiagnoseUseOfDecl(PD, MemberLoc))
- return ExprError();
-
- QualType T = PD->getType();
- if (ObjCMethodDecl *Getter = PD->getGetterMethodDecl())
- T = getMessageSendResultType(BaseType, Getter, false, false);
-
- return Owned(new (Context) ObjCPropertyRefExpr(PD, T,
- VK_LValue,
- OK_ObjCProperty,
- MemberLoc,
- BaseExpr.take()));
- }
-
- if (ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(PMDecl)) {
- // Check the use of this method.
- if (DiagnoseUseOfDecl(OMD, MemberLoc))
- return ExprError();
- Selector SetterSel =
- SelectorTable::constructSetterName(PP.getIdentifierTable(),
- PP.getSelectorTable(), Member);
- ObjCMethodDecl *SMD = 0;
- if (Decl *SDecl = FindGetterSetterNameDecl(OPT, /*Property id*/0,
- SetterSel, Context))
- SMD = dyn_cast<ObjCMethodDecl>(SDecl);
- QualType PType = getMessageSendResultType(BaseType, OMD, false,
- false);
-
- ExprValueKind VK = VK_LValue;
- if (!getLangOptions().CPlusPlus &&
- IsCForbiddenLValueType(Context, PType))
- VK = VK_RValue;
- ExprObjectKind OK = (VK == VK_RValue ? OK_Ordinary : OK_ObjCProperty);
-
- return Owned(new (Context) ObjCPropertyRefExpr(OMD, SMD, PType,
- VK, OK,
- MemberLoc, BaseExpr.take()));
- }
- }
- // Use of id.member can only be for a property reference. Do not
- // use the 'id' redefinition in this case.
- if (IsArrow && ShouldTryAgainWithRedefinitionType(*this, BaseExpr))
- return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS,
- ObjCImpDecl, HasTemplateArgs);
-
- return ExprError(Diag(MemberLoc, diag::err_property_not_found)
- << MemberName << BaseType);
- }
-
- // 'Class', unqualified only.
- if (OT->isObjCClass()) {
- // Only works in a method declaration (??!).
- ObjCMethodDecl *MD = getCurMethodDecl();
- if (!MD) {
- if (ShouldTryAgainWithRedefinitionType(*this, BaseExpr))
- return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS,
- ObjCImpDecl, HasTemplateArgs);
-
- goto fail;
- }
-
- // Also must look for a getter name which uses property syntax.
- Selector Sel = PP.getSelectorTable().getNullarySelector(Member);
- ObjCInterfaceDecl *IFace = MD->getClassInterface();
- ObjCMethodDecl *Getter;
- if ((Getter = IFace->lookupClassMethod(Sel))) {
- // Check the use of this method.
- if (DiagnoseUseOfDecl(Getter, MemberLoc))
- return ExprError();
- } else
- Getter = IFace->lookupPrivateMethod(Sel, false);
- // If we found a getter then this may be a valid dot-reference, we
- // will look for the matching setter, in case it is needed.
- Selector SetterSel =
- SelectorTable::constructSetterName(PP.getIdentifierTable(),
- PP.getSelectorTable(), Member);
- ObjCMethodDecl *Setter = IFace->lookupClassMethod(SetterSel);
- if (!Setter) {
- // If this reference is in an @implementation, also check for 'private'
- // methods.
- Setter = IFace->lookupPrivateMethod(SetterSel, false);
- }
- // Look through local category implementations associated with the class.
- if (!Setter)
- Setter = IFace->getCategoryClassMethod(SetterSel);
-
- if (Setter && DiagnoseUseOfDecl(Setter, MemberLoc))
- return ExprError();
-
- if (Getter || Setter) {
- QualType PType;
-
- ExprValueKind VK = VK_LValue;
- if (Getter) {
- PType = getMessageSendResultType(QualType(OT, 0), Getter, true,
- false);
- if (!getLangOptions().CPlusPlus &&
- IsCForbiddenLValueType(Context, PType))
- VK = VK_RValue;
- } else {
- // Get the expression type from Setter's incoming parameter.
- PType = (*(Setter->param_end() -1))->getType();
- }
- ExprObjectKind OK = (VK == VK_RValue ? OK_Ordinary : OK_ObjCProperty);
-
- // FIXME: we must check that the setter has property type.
- return Owned(new (Context) ObjCPropertyRefExpr(Getter, Setter,
- PType, VK, OK,
- MemberLoc, BaseExpr.take()));
- }
-
- if (ShouldTryAgainWithRedefinitionType(*this, BaseExpr))
- return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS,
- ObjCImpDecl, HasTemplateArgs);
-
- return ExprError(Diag(MemberLoc, diag::err_property_not_found)
- << MemberName << BaseType);
- }
-
- // Normal property access.
- return HandleExprPropertyRefExpr(OPT, BaseExpr.get(), MemberName, MemberLoc,
- SourceLocation(), QualType(), false);
- }
-
- // Handle 'field access' to vectors, such as 'V.xx'.
- if (BaseType->isExtVectorType()) {
- // FIXME: this expr should store IsArrow.
- IdentifierInfo *Member = MemberName.getAsIdentifierInfo();
- ExprValueKind VK = (IsArrow ? VK_LValue : BaseExpr.get()->getValueKind());
- QualType ret = CheckExtVectorComponent(*this, BaseType, VK, OpLoc,
- Member, MemberLoc);
- if (ret.isNull())
- return ExprError();
-
- return Owned(new (Context) ExtVectorElementExpr(ret, VK, BaseExpr.take(),
- *Member, MemberLoc));
- }
-
- // Adjust builtin-sel to the appropriate redefinition type if that's
- // not just a pointer to builtin-sel again.
- if (IsArrow &&
- BaseType->isSpecificBuiltinType(BuiltinType::ObjCSel) &&
- !Context.ObjCSelRedefinitionType->isObjCSelType()) {
- BaseExpr = ImpCastExprToType(BaseExpr.take(), Context.ObjCSelRedefinitionType,
- CK_BitCast);
- return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS,
- ObjCImpDecl, HasTemplateArgs);
- }
-
- // Failure cases.
- fail:
-
- // Recover from dot accesses to pointers, e.g.:
- // type *foo;
- // foo.bar
- // This is actually well-formed in two cases:
- // - 'type' is an Objective C type
- // - 'bar' is a pseudo-destructor name which happens to refer to
- // the appropriate pointer type
- if (const PointerType *Ptr = BaseType->getAs<PointerType>()) {
- if (!IsArrow && Ptr->getPointeeType()->isRecordType() &&
- MemberName.getNameKind() != DeclarationName::CXXDestructorName) {
- Diag(OpLoc, diag::err_typecheck_member_reference_suggestion)
- << BaseType << int(IsArrow) << BaseExpr.get()->getSourceRange()
- << FixItHint::CreateReplacement(OpLoc, "->");
-
- // Recurse as an -> access.
- IsArrow = true;
- return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS,
- ObjCImpDecl, HasTemplateArgs);
- }
- }
-
- // If the user is trying to apply -> or . to a function name, it's probably
- // because they forgot parentheses to call that function.
- QualType ZeroArgCallTy;
- UnresolvedSet<4> Overloads;
- if (isExprCallable(*BaseExpr.get(), ZeroArgCallTy, Overloads)) {
- if (ZeroArgCallTy.isNull()) {
- Diag(BaseExpr.get()->getExprLoc(), diag::err_member_reference_needs_call)
- << (Overloads.size() > 1) << 0 << BaseExpr.get()->getSourceRange();
- UnresolvedSet<2> PlausibleOverloads;
- for (OverloadExpr::decls_iterator It = Overloads.begin(),
- DeclsEnd = Overloads.end(); It != DeclsEnd; ++It) {
- const FunctionDecl *OverloadDecl = cast<FunctionDecl>(*It);
- QualType OverloadResultTy = OverloadDecl->getResultType();
- if ((!IsArrow && OverloadResultTy->isRecordType()) ||
- (IsArrow && OverloadResultTy->isPointerType() &&
- OverloadResultTy->getPointeeType()->isRecordType()))
- PlausibleOverloads.addDecl(It.getDecl());
- }
- NoteOverloads(PlausibleOverloads, BaseExpr.get()->getExprLoc());
- return ExprError();
- }
- if ((!IsArrow && ZeroArgCallTy->isRecordType()) ||
- (IsArrow && ZeroArgCallTy->isPointerType() &&
- ZeroArgCallTy->getPointeeType()->isRecordType())) {
- // At this point, we know BaseExpr looks like it's potentially callable
- // with 0 arguments, and that it returns something of a reasonable type,
- // so we can emit a fixit and carry on pretending that BaseExpr was
- // actually a CallExpr.
- SourceLocation ParenInsertionLoc =
- PP.getLocForEndOfToken(BaseExpr.get()->getLocEnd());
- Diag(BaseExpr.get()->getExprLoc(), diag::err_member_reference_needs_call)
- << (Overloads.size() > 1) << 1 << BaseExpr.get()->getSourceRange()
- << FixItHint::CreateInsertion(ParenInsertionLoc, "()");
- // FIXME: Try this before emitting the fixit, and suppress diagnostics
- // while doing so.
- ExprResult NewBase =
- ActOnCallExpr(0, BaseExpr.take(), ParenInsertionLoc,
- MultiExprArg(*this, 0, 0),
- ParenInsertionLoc.getFileLocWithOffset(1));
- if (NewBase.isInvalid())
- return ExprError();
- BaseExpr = NewBase;
- BaseExpr = DefaultFunctionArrayConversion(BaseExpr.take());
- return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS,
- ObjCImpDecl, HasTemplateArgs);
- }
- }
-
- Diag(MemberLoc, diag::err_typecheck_member_reference_struct_union)
- << BaseType << BaseExpr.get()->getSourceRange();
-
- return ExprError();
-}
-
-/// The main callback when the parser finds something like
-/// expression . [nested-name-specifier] identifier
-/// expression -> [nested-name-specifier] identifier
-/// where 'identifier' encompasses a fairly broad spectrum of
-/// possibilities, including destructor and operator references.
-///
-/// \param OpKind either tok::arrow or tok::period
-/// \param HasTrailingLParen whether the next token is '(', which
-/// is used to diagnose mis-uses of special members that can
-/// only be called
-/// \param ObjCImpDecl the current ObjC @implementation decl;
-/// this is an ugly hack around the fact that ObjC @implementations
-/// aren't properly put in the context chain
-ExprResult Sema::ActOnMemberAccessExpr(Scope *S, Expr *Base,
- SourceLocation OpLoc,
- tok::TokenKind OpKind,
- CXXScopeSpec &SS,
- UnqualifiedId &Id,
- Decl *ObjCImpDecl,
- bool HasTrailingLParen) {
- if (SS.isSet() && SS.isInvalid())
- return ExprError();
-
- // Warn about the explicit constructor calls Microsoft extension.
- if (getLangOptions().Microsoft &&
- Id.getKind() == UnqualifiedId::IK_ConstructorName)
- Diag(Id.getSourceRange().getBegin(),
- diag::ext_ms_explicit_constructor_call);
-
- TemplateArgumentListInfo TemplateArgsBuffer;
-
- // Decompose the name into its component parts.
- DeclarationNameInfo NameInfo;
- const TemplateArgumentListInfo *TemplateArgs;
- DecomposeUnqualifiedId(*this, Id, TemplateArgsBuffer,
- NameInfo, TemplateArgs);
-
- DeclarationName Name = NameInfo.getName();
- bool IsArrow = (OpKind == tok::arrow);
-
- NamedDecl *FirstQualifierInScope
- = (!SS.isSet() ? 0 : FindFirstQualifierInScope(S,
- static_cast<NestedNameSpecifier*>(SS.getScopeRep())));
-
- // This is a postfix expression, so get rid of ParenListExprs.
- ExprResult Result = MaybeConvertParenListExprToParenExpr(S, Base);
- if (Result.isInvalid()) return ExprError();
- Base = Result.take();
-
- if (Base->getType()->isDependentType() || Name.isDependentName() ||
- isDependentScopeSpecifier(SS)) {
- Result = ActOnDependentMemberExpr(Base, Base->getType(),
- IsArrow, OpLoc,
- SS, FirstQualifierInScope,
- NameInfo, TemplateArgs);
- } else {
- LookupResult R(*this, NameInfo, LookupMemberName);
- ExprResult BaseResult = Owned(Base);
- Result = LookupMemberExpr(R, BaseResult, IsArrow, OpLoc,
- SS, ObjCImpDecl, TemplateArgs != 0);
- if (BaseResult.isInvalid())
- return ExprError();
- Base = BaseResult.take();
-
- if (Result.isInvalid()) {
- Owned(Base);
- return ExprError();
- }
-
- if (Result.get()) {
- // The only way a reference to a destructor can be used is to
- // immediately call it, which falls into this case. If the
- // next token is not a '(', produce a diagnostic and build the
- // call now.
- if (!HasTrailingLParen &&
- Id.getKind() == UnqualifiedId::IK_DestructorName)
- return DiagnoseDtorReference(NameInfo.getLoc(), Result.get());
-
- return move(Result);
- }
-
- Result = BuildMemberReferenceExpr(Base, Base->getType(),
- OpLoc, IsArrow, SS, FirstQualifierInScope,
- R, TemplateArgs);
- }
-
- return move(Result);
-}
-
ExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc,
FunctionDecl *FD,
ParmVarDecl *Param) {
@@ -8804,8 +7229,7 @@
VK = VK_LValue;
// ...except that certain expressions are never l-values in C.
- if (!S.getLangOptions().CPlusPlus &&
- IsCForbiddenLValueType(S.Context, Result))
+ if (!S.getLangOptions().CPlusPlus && Result.isCForbiddenLValueType())
VK = VK_RValue;
return Result;
Added: cfe/trunk/lib/Sema/SemaExprMember.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprMember.cpp?rev=133674&view=auto
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprMember.cpp (added)
+++ cfe/trunk/lib/Sema/SemaExprMember.cpp Wed Jun 22 19:49:38 2011
@@ -0,0 +1,1582 @@
+//===--- SemaExprMember.cpp - Semantic Analysis for Expressions -----------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements semantic analysis member access expressions.
+//
+//===----------------------------------------------------------------------===//
+#include "clang/Sema/SemaInternal.h"
+#include "clang/Sema/Lookup.h"
+#include "clang/Sema/Scope.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/AST/ExprObjC.h"
+#include "clang/Lex/Preprocessor.h"
+
+using namespace clang;
+using namespace sema;
+
+/// Determines if the given class is provably not derived from all of
+/// the prospective base classes.
+static bool IsProvablyNotDerivedFrom(Sema &SemaRef,
+ CXXRecordDecl *Record,
+ const llvm::SmallPtrSet<CXXRecordDecl*, 4> &Bases) {
+ if (Bases.count(Record->getCanonicalDecl()))
+ return false;
+
+ RecordDecl *RD = Record->getDefinition();
+ if (!RD) return false;
+ Record = cast<CXXRecordDecl>(RD);
+
+ for (CXXRecordDecl::base_class_iterator I = Record->bases_begin(),
+ E = Record->bases_end(); I != E; ++I) {
+ CanQualType BaseT = SemaRef.Context.getCanonicalType((*I).getType());
+ CanQual<RecordType> BaseRT = BaseT->getAs<RecordType>();
+ if (!BaseRT) return false;
+
+ CXXRecordDecl *BaseRecord = cast<CXXRecordDecl>(BaseRT->getDecl());
+ if (!IsProvablyNotDerivedFrom(SemaRef, BaseRecord, Bases))
+ return false;
+ }
+
+ return true;
+}
+
+enum IMAKind {
+ /// The reference is definitely not an instance member access.
+ IMA_Static,
+
+ /// The reference may be an implicit instance member access.
+ IMA_Mixed,
+
+ /// The reference may be to an instance member, but it is invalid if
+ /// so, because the context is not an instance method.
+ IMA_Mixed_StaticContext,
+
+ /// The reference may be to an instance member, but it is invalid if
+ /// so, because the context is from an unrelated class.
+ IMA_Mixed_Unrelated,
+
+ /// The reference is definitely an implicit instance member access.
+ IMA_Instance,
+
+ /// The reference may be to an unresolved using declaration.
+ IMA_Unresolved,
+
+ /// The reference may be to an unresolved using declaration and the
+ /// context is not an instance method.
+ IMA_Unresolved_StaticContext,
+
+ /// All possible referrents are instance members and the current
+ /// context is not an instance method.
+ IMA_Error_StaticContext,
+
+ /// All possible referrents are instance members of an unrelated
+ /// class.
+ IMA_Error_Unrelated
+};
+
+/// The given lookup names class member(s) and is not being used for
+/// an address-of-member expression. Classify the type of access
+/// according to whether it's possible that this reference names an
+/// instance member. This is best-effort; it is okay to
+/// conservatively answer "yes", in which case some errors will simply
+/// not be caught until template-instantiation.
+static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef,
+ Scope *CurScope,
+ const LookupResult &R) {
+ assert(!R.empty() && (*R.begin())->isCXXClassMember());
+
+ DeclContext *DC = SemaRef.getFunctionLevelDeclContext();
+
+ bool isStaticContext =
+ (!isa<CXXMethodDecl>(DC) ||
+ cast<CXXMethodDecl>(DC)->isStatic());
+
+ // C++0x [expr.prim]p4:
+ // Otherwise, if a member-declarator declares a non-static data member
+ // of a class X, the expression this is a prvalue of type "pointer to X"
+ // within the optional brace-or-equal-initializer.
+ if (CurScope->getFlags() & Scope::ThisScope)
+ isStaticContext = false;
+
+ if (R.isUnresolvableResult())
+ return isStaticContext ? IMA_Unresolved_StaticContext : IMA_Unresolved;
+
+ // Collect all the declaring classes of instance members we find.
+ bool hasNonInstance = false;
+ bool hasField = false;
+ llvm::SmallPtrSet<CXXRecordDecl*, 4> Classes;
+ for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) {
+ NamedDecl *D = *I;
+
+ if (D->isCXXInstanceMember()) {
+ if (dyn_cast<FieldDecl>(D))
+ hasField = true;
+
+ CXXRecordDecl *R = cast<CXXRecordDecl>(D->getDeclContext());
+ Classes.insert(R->getCanonicalDecl());
+ }
+ else
+ hasNonInstance = true;
+ }
+
+ // If we didn't find any instance members, it can't be an implicit
+ // member reference.
+ if (Classes.empty())
+ return IMA_Static;
+
+ // If the current context is not an instance method, it can't be
+ // an implicit member reference.
+ if (isStaticContext) {
+ if (hasNonInstance)
+ return IMA_Mixed_StaticContext;
+
+ if (SemaRef.getLangOptions().CPlusPlus0x && hasField) {
+ // C++0x [expr.prim.general]p10:
+ // An id-expression that denotes a non-static data member or non-static
+ // member function of a class can only be used:
+ // (...)
+ // - if that id-expression denotes a non-static data member and it
+ // appears in an unevaluated operand.
+ const Sema::ExpressionEvaluationContextRecord& record
+ = SemaRef.ExprEvalContexts.back();
+ bool isUnevaluatedExpression = (record.Context == Sema::Unevaluated);
+ if (isUnevaluatedExpression)
+ return IMA_Mixed_StaticContext;
+ }
+
+ return IMA_Error_StaticContext;
+ }
+
+ CXXRecordDecl *contextClass;
+ if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(DC))
+ contextClass = MD->getParent()->getCanonicalDecl();
+ else
+ contextClass = cast<CXXRecordDecl>(DC);
+
+ // [class.mfct.non-static]p3:
+ // ...is used in the body of a non-static member function of class X,
+ // if name lookup (3.4.1) resolves the name in the id-expression to a
+ // non-static non-type member of some class C [...]
+ // ...if C is not X or a base class of X, the class member access expression
+ // is ill-formed.
+ if (R.getNamingClass() &&
+ contextClass != R.getNamingClass()->getCanonicalDecl() &&
+ contextClass->isProvablyNotDerivedFrom(R.getNamingClass()))
+ return (hasNonInstance ? IMA_Mixed_Unrelated : IMA_Error_Unrelated);
+
+ // If we can prove that the current context is unrelated to all the
+ // declaring classes, it can't be an implicit member reference (in
+ // which case it's an error if any of those members are selected).
+ if (IsProvablyNotDerivedFrom(SemaRef, contextClass, Classes))
+ return (hasNonInstance ? IMA_Mixed_Unrelated : IMA_Error_Unrelated);
+
+ return (hasNonInstance ? IMA_Mixed : IMA_Instance);
+}
+
+/// Diagnose a reference to a field with no object available.
+static void DiagnoseInstanceReference(Sema &SemaRef,
+ const CXXScopeSpec &SS,
+ NamedDecl *rep,
+ const DeclarationNameInfo &nameInfo) {
+ SourceLocation Loc = nameInfo.getLoc();
+ SourceRange Range(Loc);
+ if (SS.isSet()) Range.setBegin(SS.getRange().getBegin());
+
+ if (isa<FieldDecl>(rep) || isa<IndirectFieldDecl>(rep)) {
+ if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(SemaRef.CurContext)) {
+ if (MD->isStatic()) {
+ // "invalid use of member 'x' in static member function"
+ SemaRef.Diag(Loc, diag::err_invalid_member_use_in_static_method)
+ << Range << nameInfo.getName();
+ return;
+ }
+ }
+
+ SemaRef.Diag(Loc, diag::err_invalid_non_static_member_use)
+ << nameInfo.getName() << Range;
+ return;
+ }
+
+ SemaRef.Diag(Loc, diag::err_member_call_without_object) << Range;
+}
+
+/// Builds an expression which might be an implicit member expression.
+ExprResult
+Sema::BuildPossibleImplicitMemberExpr(const CXXScopeSpec &SS,
+ LookupResult &R,
+ const TemplateArgumentListInfo *TemplateArgs) {
+ switch (ClassifyImplicitMemberAccess(*this, CurScope, R)) {
+ case IMA_Instance:
+ return BuildImplicitMemberExpr(SS, R, TemplateArgs, true);
+
+ case IMA_Mixed:
+ case IMA_Mixed_Unrelated:
+ case IMA_Unresolved:
+ return BuildImplicitMemberExpr(SS, R, TemplateArgs, false);
+
+ case IMA_Static:
+ case IMA_Mixed_StaticContext:
+ case IMA_Unresolved_StaticContext:
+ if (TemplateArgs)
+ return BuildTemplateIdExpr(SS, R, false, *TemplateArgs);
+ return BuildDeclarationNameExpr(SS, R, false);
+
+ case IMA_Error_StaticContext:
+ case IMA_Error_Unrelated:
+ DiagnoseInstanceReference(*this, SS, R.getRepresentativeDecl(),
+ R.getLookupNameInfo());
+ return ExprError();
+ }
+
+ llvm_unreachable("unexpected instance member access kind");
+ return ExprError();
+}
+
+/// Check an ext-vector component access expression.
+///
+/// VK should be set in advance to the value kind of the base
+/// expression.
+static QualType
+CheckExtVectorComponent(Sema &S, QualType baseType, ExprValueKind &VK,
+ SourceLocation OpLoc, const IdentifierInfo *CompName,
+ SourceLocation CompLoc) {
+ // FIXME: Share logic with ExtVectorElementExpr::containsDuplicateElements,
+ // see FIXME there.
+ //
+ // FIXME: This logic can be greatly simplified by splitting it along
+ // halving/not halving and reworking the component checking.
+ const ExtVectorType *vecType = baseType->getAs<ExtVectorType>();
+
+ // The vector accessor can't exceed the number of elements.
+ const char *compStr = CompName->getNameStart();
+
+ // This flag determines whether or not the component is one of the four
+ // special names that indicate a subset of exactly half the elements are
+ // to be selected.
+ bool HalvingSwizzle = false;
+
+ // This flag determines whether or not CompName has an 's' char prefix,
+ // indicating that it is a string of hex values to be used as vector indices.
+ bool HexSwizzle = *compStr == 's' || *compStr == 'S';
+
+ bool HasRepeated = false;
+ bool HasIndex[16] = {};
+
+ int Idx;
+
+ // Check that we've found one of the special components, or that the component
+ // names must come from the same set.
+ if (!strcmp(compStr, "hi") || !strcmp(compStr, "lo") ||
+ !strcmp(compStr, "even") || !strcmp(compStr, "odd")) {
+ HalvingSwizzle = true;
+ } else if (!HexSwizzle &&
+ (Idx = vecType->getPointAccessorIdx(*compStr)) != -1) {
+ do {
+ if (HasIndex[Idx]) HasRepeated = true;
+ HasIndex[Idx] = true;
+ compStr++;
+ } while (*compStr && (Idx = vecType->getPointAccessorIdx(*compStr)) != -1);
+ } else {
+ if (HexSwizzle) compStr++;
+ while ((Idx = vecType->getNumericAccessorIdx(*compStr)) != -1) {
+ if (HasIndex[Idx]) HasRepeated = true;
+ HasIndex[Idx] = true;
+ compStr++;
+ }
+ }
+
+ if (!HalvingSwizzle && *compStr) {
+ // We didn't get to the end of the string. This means the component names
+ // didn't come from the same set *or* we encountered an illegal name.
+ S.Diag(OpLoc, diag::err_ext_vector_component_name_illegal)
+ << llvm::StringRef(compStr, 1) << SourceRange(CompLoc);
+ return QualType();
+ }
+
+ // Ensure no component accessor exceeds the width of the vector type it
+ // operates on.
+ if (!HalvingSwizzle) {
+ compStr = CompName->getNameStart();
+
+ if (HexSwizzle)
+ compStr++;
+
+ while (*compStr) {
+ if (!vecType->isAccessorWithinNumElements(*compStr++)) {
+ S.Diag(OpLoc, diag::err_ext_vector_component_exceeds_length)
+ << baseType << SourceRange(CompLoc);
+ return QualType();
+ }
+ }
+ }
+
+ // The component accessor looks fine - now we need to compute the actual type.
+ // The vector type is implied by the component accessor. For example,
+ // vec4.b is a float, vec4.xy is a vec2, vec4.rgb is a vec3, etc.
+ // vec4.s0 is a float, vec4.s23 is a vec3, etc.
+ // vec4.hi, vec4.lo, vec4.e, and vec4.o all return vec2.
+ unsigned CompSize = HalvingSwizzle ? (vecType->getNumElements() + 1) / 2
+ : CompName->getLength();
+ if (HexSwizzle)
+ CompSize--;
+
+ if (CompSize == 1)
+ return vecType->getElementType();
+
+ if (HasRepeated) VK = VK_RValue;
+
+ QualType VT = S.Context.getExtVectorType(vecType->getElementType(), CompSize);
+ // Now look up the TypeDefDecl from the vector type. Without this,
+ // diagostics look bad. We want extended vector types to appear built-in.
+ for (unsigned i = 0, E = S.ExtVectorDecls.size(); i != E; ++i) {
+ if (S.ExtVectorDecls[i]->getUnderlyingType() == VT)
+ return S.Context.getTypedefType(S.ExtVectorDecls[i]);
+ }
+ return VT; // should never get here (a typedef type should always be found).
+}
+
+static Decl *FindGetterSetterNameDeclFromProtocolList(const ObjCProtocolDecl*PDecl,
+ IdentifierInfo *Member,
+ const Selector &Sel,
+ ASTContext &Context) {
+ if (Member)
+ if (ObjCPropertyDecl *PD = PDecl->FindPropertyDeclaration(Member))
+ return PD;
+ if (ObjCMethodDecl *OMD = PDecl->getInstanceMethod(Sel))
+ return OMD;
+
+ for (ObjCProtocolDecl::protocol_iterator I = PDecl->protocol_begin(),
+ E = PDecl->protocol_end(); I != E; ++I) {
+ if (Decl *D = FindGetterSetterNameDeclFromProtocolList(*I, Member, Sel,
+ Context))
+ return D;
+ }
+ return 0;
+}
+
+static Decl *FindGetterSetterNameDecl(const ObjCObjectPointerType *QIdTy,
+ IdentifierInfo *Member,
+ const Selector &Sel,
+ ASTContext &Context) {
+ // Check protocols on qualified interfaces.
+ Decl *GDecl = 0;
+ for (ObjCObjectPointerType::qual_iterator I = QIdTy->qual_begin(),
+ E = QIdTy->qual_end(); I != E; ++I) {
+ if (Member)
+ if (ObjCPropertyDecl *PD = (*I)->FindPropertyDeclaration(Member)) {
+ GDecl = PD;
+ break;
+ }
+ // Also must look for a getter or setter name which uses property syntax.
+ if (ObjCMethodDecl *OMD = (*I)->getInstanceMethod(Sel)) {
+ GDecl = OMD;
+ break;
+ }
+ }
+ if (!GDecl) {
+ for (ObjCObjectPointerType::qual_iterator I = QIdTy->qual_begin(),
+ E = QIdTy->qual_end(); I != E; ++I) {
+ // Search in the protocol-qualifier list of current protocol.
+ GDecl = FindGetterSetterNameDeclFromProtocolList(*I, Member, Sel,
+ Context);
+ if (GDecl)
+ return GDecl;
+ }
+ }
+ return GDecl;
+}
+
+ExprResult
+Sema::ActOnDependentMemberExpr(Expr *BaseExpr, QualType BaseType,
+ bool IsArrow, SourceLocation OpLoc,
+ const CXXScopeSpec &SS,
+ NamedDecl *FirstQualifierInScope,
+ const DeclarationNameInfo &NameInfo,
+ const TemplateArgumentListInfo *TemplateArgs) {
+ // Even in dependent contexts, try to diagnose base expressions with
+ // obviously wrong types, e.g.:
+ //
+ // T* t;
+ // t.f;
+ //
+ // In Obj-C++, however, the above expression is valid, since it could be
+ // accessing the 'f' property if T is an Obj-C interface. The extra check
+ // allows this, while still reporting an error if T is a struct pointer.
+ if (!IsArrow) {
+ const PointerType *PT = BaseType->getAs<PointerType>();
+ if (PT && (!getLangOptions().ObjC1 ||
+ PT->getPointeeType()->isRecordType())) {
+ assert(BaseExpr && "cannot happen with implicit member accesses");
+ Diag(NameInfo.getLoc(), diag::err_typecheck_member_reference_struct_union)
+ << BaseType << BaseExpr->getSourceRange();
+ return ExprError();
+ }
+ }
+
+ assert(BaseType->isDependentType() ||
+ NameInfo.getName().isDependentName() ||
+ isDependentScopeSpecifier(SS));
+
+ // Get the type being accessed in BaseType. If this is an arrow, the BaseExpr
+ // must have pointer type, and the accessed type is the pointee.
+ return Owned(CXXDependentScopeMemberExpr::Create(Context, BaseExpr, BaseType,
+ IsArrow, OpLoc,
+ SS.getWithLocInContext(Context),
+ FirstQualifierInScope,
+ NameInfo, TemplateArgs));
+}
+
+/// We know that the given qualified member reference points only to
+/// declarations which do not belong to the static type of the base
+/// expression. Diagnose the problem.
+static void DiagnoseQualifiedMemberReference(Sema &SemaRef,
+ Expr *BaseExpr,
+ QualType BaseType,
+ const CXXScopeSpec &SS,
+ NamedDecl *rep,
+ const DeclarationNameInfo &nameInfo) {
+ // If this is an implicit member access, use a different set of
+ // diagnostics.
+ if (!BaseExpr)
+ return DiagnoseInstanceReference(SemaRef, SS, rep, nameInfo);
+
+ SemaRef.Diag(nameInfo.getLoc(), diag::err_qualified_member_of_unrelated)
+ << SS.getRange() << rep << BaseType;
+}
+
+// Check whether the declarations we found through a nested-name
+// specifier in a member expression are actually members of the base
+// type. The restriction here is:
+//
+// C++ [expr.ref]p2:
+// ... In these cases, the id-expression shall name a
+// member of the class or of one of its base classes.
+//
+// So it's perfectly legitimate for the nested-name specifier to name
+// an unrelated class, and for us to find an overload set including
+// decls from classes which are not superclasses, as long as the decl
+// we actually pick through overload resolution is from a superclass.
+bool Sema::CheckQualifiedMemberReference(Expr *BaseExpr,
+ QualType BaseType,
+ const CXXScopeSpec &SS,
+ const LookupResult &R) {
+ const RecordType *BaseRT = BaseType->getAs<RecordType>();
+ if (!BaseRT) {
+ // We can't check this yet because the base type is still
+ // dependent.
+ assert(BaseType->isDependentType());
+ return false;
+ }
+ CXXRecordDecl *BaseRecord = cast<CXXRecordDecl>(BaseRT->getDecl());
+
+ for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) {
+ // If this is an implicit member reference and we find a
+ // non-instance member, it's not an error.
+ if (!BaseExpr && !(*I)->isCXXInstanceMember())
+ return false;
+
+ // Note that we use the DC of the decl, not the underlying decl.
+ DeclContext *DC = (*I)->getDeclContext();
+ while (DC->isTransparentContext())
+ DC = DC->getParent();
+
+ if (!DC->isRecord())
+ continue;
+
+ llvm::SmallPtrSet<CXXRecordDecl*,4> MemberRecord;
+ MemberRecord.insert(cast<CXXRecordDecl>(DC)->getCanonicalDecl());
+
+ if (!IsProvablyNotDerivedFrom(*this, BaseRecord, MemberRecord))
+ return false;
+ }
+
+ DiagnoseQualifiedMemberReference(*this, BaseExpr, BaseType, SS,
+ R.getRepresentativeDecl(),
+ R.getLookupNameInfo());
+ return true;
+}
+
+static bool
+LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
+ SourceRange BaseRange, const RecordType *RTy,
+ SourceLocation OpLoc, CXXScopeSpec &SS,
+ bool HasTemplateArgs) {
+ RecordDecl *RDecl = RTy->getDecl();
+ if (SemaRef.RequireCompleteType(OpLoc, QualType(RTy, 0),
+ SemaRef.PDiag(diag::err_typecheck_incomplete_tag)
+ << BaseRange))
+ return true;
+
+ if (HasTemplateArgs) {
+ // LookupTemplateName doesn't expect these both to exist simultaneously.
+ QualType ObjectType = SS.isSet() ? QualType() : QualType(RTy, 0);
+
+ bool MOUS;
+ SemaRef.LookupTemplateName(R, 0, SS, ObjectType, false, MOUS);
+ return false;
+ }
+
+ DeclContext *DC = RDecl;
+ if (SS.isSet()) {
+ // If the member name was a qualified-id, look into the
+ // nested-name-specifier.
+ DC = SemaRef.computeDeclContext(SS, false);
+
+ if (SemaRef.RequireCompleteDeclContext(SS, DC)) {
+ SemaRef.Diag(SS.getRange().getEnd(), diag::err_typecheck_incomplete_tag)
+ << SS.getRange() << DC;
+ return true;
+ }
+
+ assert(DC && "Cannot handle non-computable dependent contexts in lookup");
+
+ if (!isa<TypeDecl>(DC)) {
+ SemaRef.Diag(R.getNameLoc(), diag::err_qualified_member_nonclass)
+ << DC << SS.getRange();
+ return true;
+ }
+ }
+
+ // The record definition is complete, now look up the member.
+ SemaRef.LookupQualifiedName(R, DC);
+
+ if (!R.empty())
+ return false;
+
+ // We didn't find anything with the given name, so try to correct
+ // for typos.
+ DeclarationName Name = R.getLookupName();
+ if (SemaRef.CorrectTypo(R, 0, &SS, DC, false, Sema::CTC_MemberLookup) &&
+ !R.empty() &&
+ (isa<ValueDecl>(*R.begin()) || isa<FunctionTemplateDecl>(*R.begin()))) {
+ SemaRef.Diag(R.getNameLoc(), diag::err_no_member_suggest)
+ << Name << DC << R.getLookupName() << SS.getRange()
+ << FixItHint::CreateReplacement(R.getNameLoc(),
+ R.getLookupName().getAsString());
+ if (NamedDecl *ND = R.getAsSingle<NamedDecl>())
+ SemaRef.Diag(ND->getLocation(), diag::note_previous_decl)
+ << ND->getDeclName();
+ return false;
+ } else {
+ R.clear();
+ R.setLookupName(Name);
+ }
+
+ return false;
+}
+
+ExprResult
+Sema::BuildMemberReferenceExpr(Expr *Base, QualType BaseType,
+ SourceLocation OpLoc, bool IsArrow,
+ CXXScopeSpec &SS,
+ NamedDecl *FirstQualifierInScope,
+ const DeclarationNameInfo &NameInfo,
+ const TemplateArgumentListInfo *TemplateArgs) {
+ if (BaseType->isDependentType() ||
+ (SS.isSet() && isDependentScopeSpecifier(SS)))
+ return ActOnDependentMemberExpr(Base, BaseType,
+ IsArrow, OpLoc,
+ SS, FirstQualifierInScope,
+ NameInfo, TemplateArgs);
+
+ LookupResult R(*this, NameInfo, LookupMemberName);
+
+ // Implicit member accesses.
+ if (!Base) {
+ QualType RecordTy = BaseType;
+ if (IsArrow) RecordTy = RecordTy->getAs<PointerType>()->getPointeeType();
+ if (LookupMemberExprInRecord(*this, R, SourceRange(),
+ RecordTy->getAs<RecordType>(),
+ OpLoc, SS, TemplateArgs != 0))
+ return ExprError();
+
+ // Explicit member accesses.
+ } else {
+ ExprResult BaseResult = Owned(Base);
+ ExprResult Result =
+ LookupMemberExpr(R, BaseResult, IsArrow, OpLoc,
+ SS, /*ObjCImpDecl*/ 0, TemplateArgs != 0);
+
+ if (BaseResult.isInvalid())
+ return ExprError();
+ Base = BaseResult.take();
+
+ if (Result.isInvalid()) {
+ Owned(Base);
+ return ExprError();
+ }
+
+ if (Result.get())
+ return move(Result);
+
+ // LookupMemberExpr can modify Base, and thus change BaseType
+ BaseType = Base->getType();
+ }
+
+ return BuildMemberReferenceExpr(Base, BaseType,
+ OpLoc, IsArrow, SS, FirstQualifierInScope,
+ R, TemplateArgs);
+}
+
+static ExprResult
+BuildFieldReferenceExpr(Sema &S, Expr *BaseExpr, bool IsArrow,
+ const CXXScopeSpec &SS, FieldDecl *Field,
+ DeclAccessPair FoundDecl,
+ const DeclarationNameInfo &MemberNameInfo);
+
+ExprResult
+Sema::BuildAnonymousStructUnionMemberReference(const CXXScopeSpec &SS,
+ SourceLocation loc,
+ IndirectFieldDecl *indirectField,
+ Expr *baseObjectExpr,
+ SourceLocation opLoc) {
+ // First, build the expression that refers to the base object.
+
+ bool baseObjectIsPointer = false;
+ Qualifiers baseQuals;
+
+ // Case 1: the base of the indirect field is not a field.
+ VarDecl *baseVariable = indirectField->getVarDecl();
+ CXXScopeSpec EmptySS;
+ if (baseVariable) {
+ assert(baseVariable->getType()->isRecordType());
+
+ // In principle we could have a member access expression that
+ // accesses an anonymous struct/union that's a static member of
+ // the base object's class. However, under the current standard,
+ // static data members cannot be anonymous structs or unions.
+ // Supporting this is as easy as building a MemberExpr here.
+ assert(!baseObjectExpr && "anonymous struct/union is static data member?");
+
+ DeclarationNameInfo baseNameInfo(DeclarationName(), loc);
+
+ ExprResult result
+ = BuildDeclarationNameExpr(EmptySS, baseNameInfo, baseVariable);
+ if (result.isInvalid()) return ExprError();
+
+ baseObjectExpr = result.take();
+ baseObjectIsPointer = false;
+ baseQuals = baseObjectExpr->getType().getQualifiers();
+
+ // Case 2: the base of the indirect field is a field and the user
+ // wrote a member expression.
+ } else if (baseObjectExpr) {
+ // The caller provided the base object expression. Determine
+ // whether its a pointer and whether it adds any qualifiers to the
+ // anonymous struct/union fields we're looking into.
+ QualType objectType = baseObjectExpr->getType();
+
+ if (const PointerType *ptr = objectType->getAs<PointerType>()) {
+ baseObjectIsPointer = true;
+ objectType = ptr->getPointeeType();
+ } else {
+ baseObjectIsPointer = false;
+ }
+ baseQuals = objectType.getQualifiers();
+
+ // Case 3: the base of the indirect field is a field and we should
+ // build an implicit member access.
+ } else {
+ // We've found a member of an anonymous struct/union that is
+ // inside a non-anonymous struct/union, so in a well-formed
+ // program our base object expression is "this".
+ QualType ThisTy = getAndCaptureCurrentThisType();
+ if (ThisTy.isNull()) {
+ Diag(loc, diag::err_invalid_member_use_in_static_method)
+ << indirectField->getDeclName();
+ return ExprError();
+ }
+
+ // Our base object expression is "this".
+ baseObjectExpr
+ = new (Context) CXXThisExpr(loc, ThisTy, /*isImplicit=*/ true);
+ baseObjectIsPointer = true;
+ baseQuals = ThisTy->castAs<PointerType>()->getPointeeType().getQualifiers();
+ }
+
+ // Build the implicit member references to the field of the
+ // anonymous struct/union.
+ Expr *result = baseObjectExpr;
+ IndirectFieldDecl::chain_iterator
+ FI = indirectField->chain_begin(), FEnd = indirectField->chain_end();
+
+ // Build the first member access in the chain with full information.
+ if (!baseVariable) {
+ FieldDecl *field = cast<FieldDecl>(*FI);
+
+ // FIXME: use the real found-decl info!
+ DeclAccessPair foundDecl = DeclAccessPair::make(field, field->getAccess());
+
+ // Make a nameInfo that properly uses the anonymous name.
+ DeclarationNameInfo memberNameInfo(field->getDeclName(), loc);
+
+ result = BuildFieldReferenceExpr(*this, result, baseObjectIsPointer,
+ EmptySS, field, foundDecl,
+ memberNameInfo).take();
+ baseObjectIsPointer = false;
+
+ // FIXME: check qualified member access
+ }
+
+ // In all cases, we should now skip the first declaration in the chain.
+ ++FI;
+
+ while (FI != FEnd) {
+ FieldDecl *field = cast<FieldDecl>(*FI++);
+
+ // FIXME: these are somewhat meaningless
+ DeclarationNameInfo memberNameInfo(field->getDeclName(), loc);
+ DeclAccessPair foundDecl = DeclAccessPair::make(field, field->getAccess());
+
+ result = BuildFieldReferenceExpr(*this, result, /*isarrow*/ false,
+ (FI == FEnd? SS : EmptySS), field,
+ foundDecl, memberNameInfo).take();
+ }
+
+ return Owned(result);
+}
+
+/// \brief Build a MemberExpr AST node.
+static MemberExpr *BuildMemberExpr(ASTContext &C, Expr *Base, bool isArrow,
+ const CXXScopeSpec &SS, ValueDecl *Member,
+ DeclAccessPair FoundDecl,
+ const DeclarationNameInfo &MemberNameInfo,
+ QualType Ty,
+ ExprValueKind VK, ExprObjectKind OK,
+ const TemplateArgumentListInfo *TemplateArgs = 0) {
+ return MemberExpr::Create(C, Base, isArrow, SS.getWithLocInContext(C),
+ Member, FoundDecl, MemberNameInfo,
+ TemplateArgs, Ty, VK, OK);
+}
+
+ExprResult
+Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
+ SourceLocation OpLoc, bool IsArrow,
+ const CXXScopeSpec &SS,
+ NamedDecl *FirstQualifierInScope,
+ LookupResult &R,
+ const TemplateArgumentListInfo *TemplateArgs,
+ bool SuppressQualifierCheck) {
+ QualType BaseType = BaseExprType;
+ if (IsArrow) {
+ assert(BaseType->isPointerType());
+ BaseType = BaseType->getAs<PointerType>()->getPointeeType();
+ }
+ R.setBaseObjectType(BaseType);
+
+ const DeclarationNameInfo &MemberNameInfo = R.getLookupNameInfo();
+ DeclarationName MemberName = MemberNameInfo.getName();
+ SourceLocation MemberLoc = MemberNameInfo.getLoc();
+
+ if (R.isAmbiguous())
+ return ExprError();
+
+ if (R.empty()) {
+ // Rederive where we looked up.
+ DeclContext *DC = (SS.isSet()
+ ? computeDeclContext(SS, false)
+ : BaseType->getAs<RecordType>()->getDecl());
+
+ Diag(R.getNameLoc(), diag::err_no_member)
+ << MemberName << DC
+ << (BaseExpr ? BaseExpr->getSourceRange() : SourceRange());
+ return ExprError();
+ }
+
+ // Diagnose lookups that find only declarations from a non-base
+ // type. This is possible for either qualified lookups (which may
+ // have been qualified with an unrelated type) or implicit member
+ // expressions (which were found with unqualified lookup and thus
+ // may have come from an enclosing scope). Note that it's okay for
+ // lookup to find declarations from a non-base type as long as those
+ // aren't the ones picked by overload resolution.
+ if ((SS.isSet() || !BaseExpr ||
+ (isa<CXXThisExpr>(BaseExpr) &&
+ cast<CXXThisExpr>(BaseExpr)->isImplicit())) &&
+ !SuppressQualifierCheck &&
+ CheckQualifiedMemberReference(BaseExpr, BaseType, SS, R))
+ return ExprError();
+
+ // Construct an unresolved result if we in fact got an unresolved
+ // result.
+ if (R.isOverloadedResult() || R.isUnresolvableResult()) {
+ // Suppress any lookup-related diagnostics; we'll do these when we
+ // pick a member.
+ R.suppressDiagnostics();
+
+ UnresolvedMemberExpr *MemExpr
+ = UnresolvedMemberExpr::Create(Context, R.isUnresolvableResult(),
+ BaseExpr, BaseExprType,
+ IsArrow, OpLoc,
+ SS.getWithLocInContext(Context),
+ MemberNameInfo,
+ TemplateArgs, R.begin(), R.end());
+
+ return Owned(MemExpr);
+ }
+
+ assert(R.isSingleResult());
+ DeclAccessPair FoundDecl = R.begin().getPair();
+ NamedDecl *MemberDecl = R.getFoundDecl();
+
+ // FIXME: diagnose the presence of template arguments now.
+
+ // If the decl being referenced had an error, return an error for this
+ // sub-expr without emitting another error, in order to avoid cascading
+ // error cases.
+ if (MemberDecl->isInvalidDecl())
+ return ExprError();
+
+ // Handle the implicit-member-access case.
+ if (!BaseExpr) {
+ // If this is not an instance member, convert to a non-member access.
+ if (!MemberDecl->isCXXInstanceMember())
+ return BuildDeclarationNameExpr(SS, R.getLookupNameInfo(), MemberDecl);
+
+ SourceLocation Loc = R.getNameLoc();
+ if (SS.getRange().isValid())
+ Loc = SS.getRange().getBegin();
+ BaseExpr = new (Context) CXXThisExpr(Loc, BaseExprType,/*isImplicit=*/true);
+ }
+
+ bool ShouldCheckUse = true;
+ if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(MemberDecl)) {
+ // Don't diagnose the use of a virtual member function unless it's
+ // explicitly qualified.
+ if (MD->isVirtual() && !SS.isSet())
+ ShouldCheckUse = false;
+ }
+
+ // Check the use of this member.
+ if (ShouldCheckUse && DiagnoseUseOfDecl(MemberDecl, MemberLoc)) {
+ Owned(BaseExpr);
+ return ExprError();
+ }
+
+ // Perform a property load on the base regardless of whether we
+ // actually need it for the declaration.
+ if (BaseExpr->getObjectKind() == OK_ObjCProperty) {
+ ExprResult Result = ConvertPropertyForRValue(BaseExpr);
+ if (Result.isInvalid())
+ return ExprError();
+ BaseExpr = Result.take();
+ }
+
+ if (FieldDecl *FD = dyn_cast<FieldDecl>(MemberDecl))
+ return BuildFieldReferenceExpr(*this, BaseExpr, IsArrow,
+ SS, FD, FoundDecl, MemberNameInfo);
+
+ if (IndirectFieldDecl *FD = dyn_cast<IndirectFieldDecl>(MemberDecl))
+ // We may have found a field within an anonymous union or struct
+ // (C++ [class.union]).
+ return BuildAnonymousStructUnionMemberReference(SS, MemberLoc, FD,
+ BaseExpr, OpLoc);
+
+ if (VarDecl *Var = dyn_cast<VarDecl>(MemberDecl)) {
+ MarkDeclarationReferenced(MemberLoc, Var);
+ return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS,
+ Var, FoundDecl, MemberNameInfo,
+ Var->getType().getNonReferenceType(),
+ VK_LValue, OK_Ordinary));
+ }
+
+ if (CXXMethodDecl *MemberFn = dyn_cast<CXXMethodDecl>(MemberDecl)) {
+ ExprValueKind valueKind;
+ QualType type;
+ if (MemberFn->isInstance()) {
+ valueKind = VK_RValue;
+ type = Context.BoundMemberTy;
+ } else {
+ valueKind = VK_LValue;
+ type = MemberFn->getType();
+ }
+
+ MarkDeclarationReferenced(MemberLoc, MemberDecl);
+ return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS,
+ MemberFn, FoundDecl, MemberNameInfo,
+ type, valueKind, OK_Ordinary));
+ }
+ assert(!isa<FunctionDecl>(MemberDecl) && "member function not C++ method?");
+
+ if (EnumConstantDecl *Enum = dyn_cast<EnumConstantDecl>(MemberDecl)) {
+ MarkDeclarationReferenced(MemberLoc, MemberDecl);
+ return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS,
+ Enum, FoundDecl, MemberNameInfo,
+ Enum->getType(), VK_RValue, OK_Ordinary));
+ }
+
+ Owned(BaseExpr);
+
+ // We found something that we didn't expect. Complain.
+ if (isa<TypeDecl>(MemberDecl))
+ Diag(MemberLoc, diag::err_typecheck_member_reference_type)
+ << MemberName << BaseType << int(IsArrow);
+ else
+ Diag(MemberLoc, diag::err_typecheck_member_reference_unknown)
+ << MemberName << BaseType << int(IsArrow);
+
+ Diag(MemberDecl->getLocation(), diag::note_member_declared_here)
+ << MemberName;
+ R.suppressDiagnostics();
+ return ExprError();
+}
+
+/// Given that normal member access failed on the given expression,
+/// and given that the expression's type involves builtin-id or
+/// builtin-Class, decide whether substituting in the redefinition
+/// types would be profitable. The redefinition type is whatever
+/// this translation unit tried to typedef to id/Class; we store
+/// it to the side and then re-use it in places like this.
+static bool ShouldTryAgainWithRedefinitionType(Sema &S, ExprResult &base) {
+ const ObjCObjectPointerType *opty
+ = base.get()->getType()->getAs<ObjCObjectPointerType>();
+ if (!opty) return false;
+
+ const ObjCObjectType *ty = opty->getObjectType();
+
+ QualType redef;
+ if (ty->isObjCId()) {
+ redef = S.Context.ObjCIdRedefinitionType;
+ } else if (ty->isObjCClass()) {
+ redef = S.Context.ObjCClassRedefinitionType;
+ } else {
+ return false;
+ }
+
+ // Do the substitution as long as the redefinition type isn't just a
+ // possibly-qualified pointer to builtin-id or builtin-Class again.
+ opty = redef->getAs<ObjCObjectPointerType>();
+ if (opty && !opty->getObjectType()->getInterface() != 0)
+ return false;
+
+ base = S.ImpCastExprToType(base.take(), redef, CK_BitCast);
+ return true;
+}
+
+/// Look up the given member of the given non-type-dependent
+/// expression. This can return in one of two ways:
+/// * If it returns a sentinel null-but-valid result, the caller will
+/// assume that lookup was performed and the results written into
+/// the provided structure. It will take over from there.
+/// * Otherwise, the returned expression will be produced in place of
+/// an ordinary member expression.
+///
+/// The ObjCImpDecl bit is a gross hack that will need to be properly
+/// fixed for ObjC++.
+ExprResult
+Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr,
+ bool &IsArrow, SourceLocation OpLoc,
+ CXXScopeSpec &SS,
+ Decl *ObjCImpDecl, bool HasTemplateArgs) {
+ assert(BaseExpr.get() && "no base expression");
+
+ // Perform default conversions.
+ BaseExpr = DefaultFunctionArrayConversion(BaseExpr.take());
+
+ if (IsArrow) {
+ BaseExpr = DefaultLvalueConversion(BaseExpr.take());
+ if (BaseExpr.isInvalid())
+ return ExprError();
+ }
+
+ QualType BaseType = BaseExpr.get()->getType();
+ assert(!BaseType->isDependentType());
+
+ DeclarationName MemberName = R.getLookupName();
+ SourceLocation MemberLoc = R.getNameLoc();
+
+ // For later type-checking purposes, turn arrow accesses into dot
+ // accesses. The only access type we support that doesn't follow
+ // the C equivalence "a->b === (*a).b" is ObjC property accesses,
+ // and those never use arrows, so this is unaffected.
+ if (IsArrow) {
+ if (const PointerType *Ptr = BaseType->getAs<PointerType>())
+ BaseType = Ptr->getPointeeType();
+ else if (const ObjCObjectPointerType *Ptr
+ = BaseType->getAs<ObjCObjectPointerType>())
+ BaseType = Ptr->getPointeeType();
+ else if (BaseType->isRecordType()) {
+ // Recover from arrow accesses to records, e.g.:
+ // struct MyRecord foo;
+ // foo->bar
+ // This is actually well-formed in C++ if MyRecord has an
+ // overloaded operator->, but that should have been dealt with
+ // by now.
+ Diag(OpLoc, diag::err_typecheck_member_reference_suggestion)
+ << BaseType << int(IsArrow) << BaseExpr.get()->getSourceRange()
+ << FixItHint::CreateReplacement(OpLoc, ".");
+ IsArrow = false;
+ } else if (BaseType == Context.BoundMemberTy) {
+ goto fail;
+ } else {
+ Diag(MemberLoc, diag::err_typecheck_member_reference_arrow)
+ << BaseType << BaseExpr.get()->getSourceRange();
+ return ExprError();
+ }
+ }
+
+ // Handle field access to simple records.
+ if (const RecordType *RTy = BaseType->getAs<RecordType>()) {
+ if (LookupMemberExprInRecord(*this, R, BaseExpr.get()->getSourceRange(),
+ RTy, OpLoc, SS, HasTemplateArgs))
+ return ExprError();
+
+ // Returning valid-but-null is how we indicate to the caller that
+ // the lookup result was filled in.
+ return Owned((Expr*) 0);
+ }
+
+ // Handle ivar access to Objective-C objects.
+ if (const ObjCObjectType *OTy = BaseType->getAs<ObjCObjectType>()) {
+ IdentifierInfo *Member = MemberName.getAsIdentifierInfo();
+
+ // There are three cases for the base type:
+ // - builtin id (qualified or unqualified)
+ // - builtin Class (qualified or unqualified)
+ // - an interface
+ ObjCInterfaceDecl *IDecl = OTy->getInterface();
+ if (!IDecl) {
+ if (getLangOptions().ObjCAutoRefCount &&
+ (OTy->isObjCId() || OTy->isObjCClass()))
+ goto fail;
+ // There's an implicit 'isa' ivar on all objects.
+ // But we only actually find it this way on objects of type 'id',
+ // apparently.
+ if (OTy->isObjCId() && Member->isStr("isa"))
+ return Owned(new (Context) ObjCIsaExpr(BaseExpr.take(), IsArrow, MemberLoc,
+ Context.getObjCClassType()));
+
+ if (ShouldTryAgainWithRedefinitionType(*this, BaseExpr))
+ return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS,
+ ObjCImpDecl, HasTemplateArgs);
+ goto fail;
+ }
+
+ ObjCInterfaceDecl *ClassDeclared;
+ ObjCIvarDecl *IV = IDecl->lookupInstanceVariable(Member, ClassDeclared);
+
+ if (!IV) {
+ // Attempt to correct for typos in ivar names.
+ LookupResult Res(*this, R.getLookupName(), R.getNameLoc(),
+ LookupMemberName);
+ if (CorrectTypo(Res, 0, 0, IDecl, false,
+ IsArrow ? CTC_ObjCIvarLookup
+ : CTC_ObjCPropertyLookup) &&
+ (IV = Res.getAsSingle<ObjCIvarDecl>())) {
+ Diag(R.getNameLoc(),
+ diag::err_typecheck_member_reference_ivar_suggest)
+ << IDecl->getDeclName() << MemberName << IV->getDeclName()
+ << FixItHint::CreateReplacement(R.getNameLoc(),
+ IV->getNameAsString());
+ Diag(IV->getLocation(), diag::note_previous_decl)
+ << IV->getDeclName();
+ } else {
+ Res.clear();
+ Res.setLookupName(Member);
+
+ Diag(MemberLoc, diag::err_typecheck_member_reference_ivar)
+ << IDecl->getDeclName() << MemberName
+ << BaseExpr.get()->getSourceRange();
+ return ExprError();
+ }
+ }
+
+ // If the decl being referenced had an error, return an error for this
+ // sub-expr without emitting another error, in order to avoid cascading
+ // error cases.
+ if (IV->isInvalidDecl())
+ return ExprError();
+
+ // Check whether we can reference this field.
+ if (DiagnoseUseOfDecl(IV, MemberLoc))
+ return ExprError();
+ if (IV->getAccessControl() != ObjCIvarDecl::Public &&
+ IV->getAccessControl() != ObjCIvarDecl::Package) {
+ ObjCInterfaceDecl *ClassOfMethodDecl = 0;
+ if (ObjCMethodDecl *MD = getCurMethodDecl())
+ ClassOfMethodDecl = MD->getClassInterface();
+ else if (ObjCImpDecl && getCurFunctionDecl()) {
+ // Case of a c-function declared inside an objc implementation.
+ // FIXME: For a c-style function nested inside an objc implementation
+ // class, there is no implementation context available, so we pass
+ // down the context as argument to this routine. Ideally, this context
+ // need be passed down in the AST node and somehow calculated from the
+ // AST for a function decl.
+ if (ObjCImplementationDecl *IMPD =
+ dyn_cast<ObjCImplementationDecl>(ObjCImpDecl))
+ ClassOfMethodDecl = IMPD->getClassInterface();
+ else if (ObjCCategoryImplDecl* CatImplClass =
+ dyn_cast<ObjCCategoryImplDecl>(ObjCImpDecl))
+ ClassOfMethodDecl = CatImplClass->getClassInterface();
+ }
+
+ if (IV->getAccessControl() == ObjCIvarDecl::Private) {
+ if (ClassDeclared != IDecl ||
+ ClassOfMethodDecl != ClassDeclared)
+ Diag(MemberLoc, diag::error_private_ivar_access)
+ << IV->getDeclName();
+ } else if (!IDecl->isSuperClassOf(ClassOfMethodDecl))
+ // @protected
+ Diag(MemberLoc, diag::error_protected_ivar_access)
+ << IV->getDeclName();
+ }
+ if (getLangOptions().ObjCAutoRefCount) {
+ Expr *BaseExp = BaseExpr.get()->IgnoreParenImpCasts();
+ if (UnaryOperator *UO = dyn_cast<UnaryOperator>(BaseExp))
+ if (UO->getOpcode() == UO_Deref)
+ BaseExp = UO->getSubExpr()->IgnoreParenCasts();
+
+ if (DeclRefExpr *DE = dyn_cast<DeclRefExpr>(BaseExp))
+ if (DE->getType().getObjCLifetime() == Qualifiers::OCL_Weak)
+ Diag(DE->getLocation(), diag::error_arc_weak_ivar_access);
+ }
+
+ return Owned(new (Context) ObjCIvarRefExpr(IV, IV->getType(),
+ MemberLoc, BaseExpr.take(),
+ IsArrow));
+ }
+
+ // Objective-C property access.
+ const ObjCObjectPointerType *OPT;
+ if (!IsArrow && (OPT = BaseType->getAs<ObjCObjectPointerType>())) {
+ // This actually uses the base as an r-value.
+ BaseExpr = DefaultLvalueConversion(BaseExpr.take());
+ if (BaseExpr.isInvalid())
+ return ExprError();
+
+ assert(Context.hasSameUnqualifiedType(BaseType, BaseExpr.get()->getType()));
+
+ IdentifierInfo *Member = MemberName.getAsIdentifierInfo();
+
+ const ObjCObjectType *OT = OPT->getObjectType();
+
+ // id, with and without qualifiers.
+ if (OT->isObjCId()) {
+ // Check protocols on qualified interfaces.
+ Selector Sel = PP.getSelectorTable().getNullarySelector(Member);
+ if (Decl *PMDecl = FindGetterSetterNameDecl(OPT, Member, Sel, Context)) {
+ if (ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(PMDecl)) {
+ // Check the use of this declaration
+ if (DiagnoseUseOfDecl(PD, MemberLoc))
+ return ExprError();
+
+ QualType T = PD->getType();
+ if (ObjCMethodDecl *Getter = PD->getGetterMethodDecl())
+ T = getMessageSendResultType(BaseType, Getter, false, false);
+
+ return Owned(new (Context) ObjCPropertyRefExpr(PD, T,
+ VK_LValue,
+ OK_ObjCProperty,
+ MemberLoc,
+ BaseExpr.take()));
+ }
+
+ if (ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(PMDecl)) {
+ // Check the use of this method.
+ if (DiagnoseUseOfDecl(OMD, MemberLoc))
+ return ExprError();
+ Selector SetterSel =
+ SelectorTable::constructSetterName(PP.getIdentifierTable(),
+ PP.getSelectorTable(), Member);
+ ObjCMethodDecl *SMD = 0;
+ if (Decl *SDecl = FindGetterSetterNameDecl(OPT, /*Property id*/0,
+ SetterSel, Context))
+ SMD = dyn_cast<ObjCMethodDecl>(SDecl);
+ QualType PType = getMessageSendResultType(BaseType, OMD, false,
+ false);
+
+ ExprValueKind VK = VK_LValue;
+ if (!getLangOptions().CPlusPlus && PType.isCForbiddenLValueType())
+ VK = VK_RValue;
+ ExprObjectKind OK = (VK == VK_RValue ? OK_Ordinary : OK_ObjCProperty);
+
+ return Owned(new (Context) ObjCPropertyRefExpr(OMD, SMD, PType,
+ VK, OK,
+ MemberLoc, BaseExpr.take()));
+ }
+ }
+ // Use of id.member can only be for a property reference. Do not
+ // use the 'id' redefinition in this case.
+ if (IsArrow && ShouldTryAgainWithRedefinitionType(*this, BaseExpr))
+ return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS,
+ ObjCImpDecl, HasTemplateArgs);
+
+ return ExprError(Diag(MemberLoc, diag::err_property_not_found)
+ << MemberName << BaseType);
+ }
+
+ // 'Class', unqualified only.
+ if (OT->isObjCClass()) {
+ // Only works in a method declaration (??!).
+ ObjCMethodDecl *MD = getCurMethodDecl();
+ if (!MD) {
+ if (ShouldTryAgainWithRedefinitionType(*this, BaseExpr))
+ return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS,
+ ObjCImpDecl, HasTemplateArgs);
+
+ goto fail;
+ }
+
+ // Also must look for a getter name which uses property syntax.
+ Selector Sel = PP.getSelectorTable().getNullarySelector(Member);
+ ObjCInterfaceDecl *IFace = MD->getClassInterface();
+ ObjCMethodDecl *Getter;
+ if ((Getter = IFace->lookupClassMethod(Sel))) {
+ // Check the use of this method.
+ if (DiagnoseUseOfDecl(Getter, MemberLoc))
+ return ExprError();
+ } else
+ Getter = IFace->lookupPrivateMethod(Sel, false);
+ // If we found a getter then this may be a valid dot-reference, we
+ // will look for the matching setter, in case it is needed.
+ Selector SetterSel =
+ SelectorTable::constructSetterName(PP.getIdentifierTable(),
+ PP.getSelectorTable(), Member);
+ ObjCMethodDecl *Setter = IFace->lookupClassMethod(SetterSel);
+ if (!Setter) {
+ // If this reference is in an @implementation, also check for 'private'
+ // methods.
+ Setter = IFace->lookupPrivateMethod(SetterSel, false);
+ }
+ // Look through local category implementations associated with the class.
+ if (!Setter)
+ Setter = IFace->getCategoryClassMethod(SetterSel);
+
+ if (Setter && DiagnoseUseOfDecl(Setter, MemberLoc))
+ return ExprError();
+
+ if (Getter || Setter) {
+ QualType PType;
+
+ ExprValueKind VK = VK_LValue;
+ if (Getter) {
+ PType = getMessageSendResultType(QualType(OT, 0), Getter, true,
+ false);
+ if (!getLangOptions().CPlusPlus && PType.isCForbiddenLValueType())
+ VK = VK_RValue;
+ } else {
+ // Get the expression type from Setter's incoming parameter.
+ PType = (*(Setter->param_end() -1))->getType();
+ }
+ ExprObjectKind OK = (VK == VK_RValue ? OK_Ordinary : OK_ObjCProperty);
+
+ // FIXME: we must check that the setter has property type.
+ return Owned(new (Context) ObjCPropertyRefExpr(Getter, Setter,
+ PType, VK, OK,
+ MemberLoc, BaseExpr.take()));
+ }
+
+ if (ShouldTryAgainWithRedefinitionType(*this, BaseExpr))
+ return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS,
+ ObjCImpDecl, HasTemplateArgs);
+
+ return ExprError(Diag(MemberLoc, diag::err_property_not_found)
+ << MemberName << BaseType);
+ }
+
+ // Normal property access.
+ return HandleExprPropertyRefExpr(OPT, BaseExpr.get(), MemberName, MemberLoc,
+ SourceLocation(), QualType(), false);
+ }
+
+ // Handle 'field access' to vectors, such as 'V.xx'.
+ if (BaseType->isExtVectorType()) {
+ // FIXME: this expr should store IsArrow.
+ IdentifierInfo *Member = MemberName.getAsIdentifierInfo();
+ ExprValueKind VK = (IsArrow ? VK_LValue : BaseExpr.get()->getValueKind());
+ QualType ret = CheckExtVectorComponent(*this, BaseType, VK, OpLoc,
+ Member, MemberLoc);
+ if (ret.isNull())
+ return ExprError();
+
+ return Owned(new (Context) ExtVectorElementExpr(ret, VK, BaseExpr.take(),
+ *Member, MemberLoc));
+ }
+
+ // Adjust builtin-sel to the appropriate redefinition type if that's
+ // not just a pointer to builtin-sel again.
+ if (IsArrow &&
+ BaseType->isSpecificBuiltinType(BuiltinType::ObjCSel) &&
+ !Context.ObjCSelRedefinitionType->isObjCSelType()) {
+ BaseExpr = ImpCastExprToType(BaseExpr.take(), Context.ObjCSelRedefinitionType,
+ CK_BitCast);
+ return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS,
+ ObjCImpDecl, HasTemplateArgs);
+ }
+
+ // Failure cases.
+ fail:
+
+ // Recover from dot accesses to pointers, e.g.:
+ // type *foo;
+ // foo.bar
+ // This is actually well-formed in two cases:
+ // - 'type' is an Objective C type
+ // - 'bar' is a pseudo-destructor name which happens to refer to
+ // the appropriate pointer type
+ if (const PointerType *Ptr = BaseType->getAs<PointerType>()) {
+ if (!IsArrow && Ptr->getPointeeType()->isRecordType() &&
+ MemberName.getNameKind() != DeclarationName::CXXDestructorName) {
+ Diag(OpLoc, diag::err_typecheck_member_reference_suggestion)
+ << BaseType << int(IsArrow) << BaseExpr.get()->getSourceRange()
+ << FixItHint::CreateReplacement(OpLoc, "->");
+
+ // Recurse as an -> access.
+ IsArrow = true;
+ return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS,
+ ObjCImpDecl, HasTemplateArgs);
+ }
+ }
+
+ // If the user is trying to apply -> or . to a function name, it's probably
+ // because they forgot parentheses to call that function.
+ QualType ZeroArgCallTy;
+ UnresolvedSet<4> Overloads;
+ if (isExprCallable(*BaseExpr.get(), ZeroArgCallTy, Overloads)) {
+ if (ZeroArgCallTy.isNull()) {
+ Diag(BaseExpr.get()->getExprLoc(), diag::err_member_reference_needs_call)
+ << (Overloads.size() > 1) << 0 << BaseExpr.get()->getSourceRange();
+ UnresolvedSet<2> PlausibleOverloads;
+ for (OverloadExpr::decls_iterator It = Overloads.begin(),
+ DeclsEnd = Overloads.end(); It != DeclsEnd; ++It) {
+ const FunctionDecl *OverloadDecl = cast<FunctionDecl>(*It);
+ QualType OverloadResultTy = OverloadDecl->getResultType();
+ if ((!IsArrow && OverloadResultTy->isRecordType()) ||
+ (IsArrow && OverloadResultTy->isPointerType() &&
+ OverloadResultTy->getPointeeType()->isRecordType()))
+ PlausibleOverloads.addDecl(It.getDecl());
+ }
+ NoteOverloads(PlausibleOverloads, BaseExpr.get()->getExprLoc());
+ return ExprError();
+ }
+ if ((!IsArrow && ZeroArgCallTy->isRecordType()) ||
+ (IsArrow && ZeroArgCallTy->isPointerType() &&
+ ZeroArgCallTy->getPointeeType()->isRecordType())) {
+ // At this point, we know BaseExpr looks like it's potentially callable
+ // with 0 arguments, and that it returns something of a reasonable type,
+ // so we can emit a fixit and carry on pretending that BaseExpr was
+ // actually a CallExpr.
+ SourceLocation ParenInsertionLoc =
+ PP.getLocForEndOfToken(BaseExpr.get()->getLocEnd());
+ Diag(BaseExpr.get()->getExprLoc(), diag::err_member_reference_needs_call)
+ << (Overloads.size() > 1) << 1 << BaseExpr.get()->getSourceRange()
+ << FixItHint::CreateInsertion(ParenInsertionLoc, "()");
+ // FIXME: Try this before emitting the fixit, and suppress diagnostics
+ // while doing so.
+ ExprResult NewBase =
+ ActOnCallExpr(0, BaseExpr.take(), ParenInsertionLoc,
+ MultiExprArg(*this, 0, 0),
+ ParenInsertionLoc.getFileLocWithOffset(1));
+ if (NewBase.isInvalid())
+ return ExprError();
+ BaseExpr = NewBase;
+ BaseExpr = DefaultFunctionArrayConversion(BaseExpr.take());
+ return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS,
+ ObjCImpDecl, HasTemplateArgs);
+ }
+ }
+
+ Diag(MemberLoc, diag::err_typecheck_member_reference_struct_union)
+ << BaseType << BaseExpr.get()->getSourceRange();
+
+ return ExprError();
+}
+
+/// The main callback when the parser finds something like
+/// expression . [nested-name-specifier] identifier
+/// expression -> [nested-name-specifier] identifier
+/// where 'identifier' encompasses a fairly broad spectrum of
+/// possibilities, including destructor and operator references.
+///
+/// \param OpKind either tok::arrow or tok::period
+/// \param HasTrailingLParen whether the next token is '(', which
+/// is used to diagnose mis-uses of special members that can
+/// only be called
+/// \param ObjCImpDecl the current ObjC @implementation decl;
+/// this is an ugly hack around the fact that ObjC @implementations
+/// aren't properly put in the context chain
+ExprResult Sema::ActOnMemberAccessExpr(Scope *S, Expr *Base,
+ SourceLocation OpLoc,
+ tok::TokenKind OpKind,
+ CXXScopeSpec &SS,
+ UnqualifiedId &Id,
+ Decl *ObjCImpDecl,
+ bool HasTrailingLParen) {
+ if (SS.isSet() && SS.isInvalid())
+ return ExprError();
+
+ // Warn about the explicit constructor calls Microsoft extension.
+ if (getLangOptions().Microsoft &&
+ Id.getKind() == UnqualifiedId::IK_ConstructorName)
+ Diag(Id.getSourceRange().getBegin(),
+ diag::ext_ms_explicit_constructor_call);
+
+ TemplateArgumentListInfo TemplateArgsBuffer;
+
+ // Decompose the name into its component parts.
+ DeclarationNameInfo NameInfo;
+ const TemplateArgumentListInfo *TemplateArgs;
+ DecomposeUnqualifiedId(Id, TemplateArgsBuffer,
+ NameInfo, TemplateArgs);
+
+ DeclarationName Name = NameInfo.getName();
+ bool IsArrow = (OpKind == tok::arrow);
+
+ NamedDecl *FirstQualifierInScope
+ = (!SS.isSet() ? 0 : FindFirstQualifierInScope(S,
+ static_cast<NestedNameSpecifier*>(SS.getScopeRep())));
+
+ // This is a postfix expression, so get rid of ParenListExprs.
+ ExprResult Result = MaybeConvertParenListExprToParenExpr(S, Base);
+ if (Result.isInvalid()) return ExprError();
+ Base = Result.take();
+
+ if (Base->getType()->isDependentType() || Name.isDependentName() ||
+ isDependentScopeSpecifier(SS)) {
+ Result = ActOnDependentMemberExpr(Base, Base->getType(),
+ IsArrow, OpLoc,
+ SS, FirstQualifierInScope,
+ NameInfo, TemplateArgs);
+ } else {
+ LookupResult R(*this, NameInfo, LookupMemberName);
+ ExprResult BaseResult = Owned(Base);
+ Result = LookupMemberExpr(R, BaseResult, IsArrow, OpLoc,
+ SS, ObjCImpDecl, TemplateArgs != 0);
+ if (BaseResult.isInvalid())
+ return ExprError();
+ Base = BaseResult.take();
+
+ if (Result.isInvalid()) {
+ Owned(Base);
+ return ExprError();
+ }
+
+ if (Result.get()) {
+ // The only way a reference to a destructor can be used is to
+ // immediately call it, which falls into this case. If the
+ // next token is not a '(', produce a diagnostic and build the
+ // call now.
+ if (!HasTrailingLParen &&
+ Id.getKind() == UnqualifiedId::IK_DestructorName)
+ return DiagnoseDtorReference(NameInfo.getLoc(), Result.get());
+
+ return move(Result);
+ }
+
+ Result = BuildMemberReferenceExpr(Base, Base->getType(),
+ OpLoc, IsArrow, SS, FirstQualifierInScope,
+ R, TemplateArgs);
+ }
+
+ return move(Result);
+}
+
+static ExprResult
+BuildFieldReferenceExpr(Sema &S, Expr *BaseExpr, bool IsArrow,
+ const CXXScopeSpec &SS, FieldDecl *Field,
+ DeclAccessPair FoundDecl,
+ const DeclarationNameInfo &MemberNameInfo) {
+ // x.a is an l-value if 'a' has a reference type. Otherwise:
+ // x.a is an l-value/x-value/pr-value if the base is (and note
+ // that *x is always an l-value), except that if the base isn't
+ // an ordinary object then we must have an rvalue.
+ ExprValueKind VK = VK_LValue;
+ ExprObjectKind OK = OK_Ordinary;
+ if (!IsArrow) {
+ if (BaseExpr->getObjectKind() == OK_Ordinary)
+ VK = BaseExpr->getValueKind();
+ else
+ VK = VK_RValue;
+ }
+ if (VK != VK_RValue && Field->isBitField())
+ OK = OK_BitField;
+
+ // Figure out the type of the member; see C99 6.5.2.3p3, C++ [expr.ref]
+ QualType MemberType = Field->getType();
+ if (const ReferenceType *Ref = MemberType->getAs<ReferenceType>()) {
+ MemberType = Ref->getPointeeType();
+ VK = VK_LValue;
+ } else {
+ QualType BaseType = BaseExpr->getType();
+ if (IsArrow) BaseType = BaseType->getAs<PointerType>()->getPointeeType();
+
+ Qualifiers BaseQuals = BaseType.getQualifiers();
+
+ // GC attributes are never picked up by members.
+ BaseQuals.removeObjCGCAttr();
+
+ // CVR attributes from the base are picked up by members,
+ // except that 'mutable' members don't pick up 'const'.
+ if (Field->isMutable()) BaseQuals.removeConst();
+
+ Qualifiers MemberQuals
+ = S.Context.getCanonicalType(MemberType).getQualifiers();
+
+ // TR 18037 does not allow fields to be declared with address spaces.
+ assert(!MemberQuals.hasAddressSpace());
+
+ Qualifiers Combined = BaseQuals + MemberQuals;
+ if (Combined != MemberQuals)
+ MemberType = S.Context.getQualifiedType(MemberType, Combined);
+ }
+
+ S.MarkDeclarationReferenced(MemberNameInfo.getLoc(), Field);
+ ExprResult Base =
+ S.PerformObjectMemberConversion(BaseExpr, SS.getScopeRep(),
+ FoundDecl, Field);
+ if (Base.isInvalid())
+ return ExprError();
+ return S.Owned(BuildMemberExpr(S.Context, Base.take(), IsArrow, SS,
+ Field, FoundDecl, MemberNameInfo,
+ MemberType, VK, OK));
+}
+
+/// Builds an implicit member access expression. The current context
+/// is known to be an instance method, and the given unqualified lookup
+/// set is known to contain only instance members, at least one of which
+/// is from an appropriate type.
+ExprResult
+Sema::BuildImplicitMemberExpr(const CXXScopeSpec &SS,
+ LookupResult &R,
+ const TemplateArgumentListInfo *TemplateArgs,
+ bool IsKnownInstance) {
+ assert(!R.empty() && !R.isAmbiguous());
+
+ SourceLocation loc = R.getNameLoc();
+
+ // We may have found a field within an anonymous union or struct
+ // (C++ [class.union]).
+ // FIXME: template-ids inside anonymous structs?
+ if (IndirectFieldDecl *FD = R.getAsSingle<IndirectFieldDecl>())
+ return BuildAnonymousStructUnionMemberReference(SS, R.getNameLoc(), FD);
+
+ // If this is known to be an instance access, go ahead and build an
+ // implicit 'this' expression now.
+ // 'this' expression now.
+ QualType ThisTy = getAndCaptureCurrentThisType();
+ assert(!ThisTy.isNull() && "didn't correctly pre-flight capture of 'this'");
+
+ Expr *baseExpr = 0; // null signifies implicit access
+ if (IsKnownInstance) {
+ SourceLocation Loc = R.getNameLoc();
+ if (SS.getRange().isValid())
+ Loc = SS.getRange().getBegin();
+ baseExpr = new (Context) CXXThisExpr(loc, ThisTy, /*isImplicit=*/true);
+ }
+
+ return BuildMemberReferenceExpr(baseExpr, ThisTy,
+ /*OpLoc*/ SourceLocation(),
+ /*IsArrow*/ true,
+ SS,
+ /*FirstQualifierInScope*/ 0,
+ R, TemplateArgs);
+}
Propchange: cfe/trunk/lib/Sema/SemaExprMember.cpp
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cfe/trunk/lib/Sema/SemaExprMember.cpp
------------------------------------------------------------------------------
svn:keywords = Id
Propchange: cfe/trunk/lib/Sema/SemaExprMember.cpp
------------------------------------------------------------------------------
svn:mime-type = text/plain
More information about the cfe-commits
mailing list