aboutsummaryrefslogtreecommitdiff
path: root/lib/Sema/SemaExpr.cpp
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2011-06-23 00:49:38 +0000
committerDouglas Gregor <dgregor@apple.com>2011-06-23 00:49:38 +0000
commit2b1ad8b42bbbe00a1845e566f52f1941b8dbc725 (patch)
tree3495e7b422dd60778531365ace56369101b6d0de /lib/Sema/SemaExpr.cpp
parent647ba1bc2e5b9aeb3ed294353b0277f835effa7d (diff)
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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@133674 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/SemaExpr.cpp')
-rw-r--r--lib/Sema/SemaExpr.cpp1598
1 files changed, 11 insertions, 1587 deletions
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 8914bf3835..a8e7348d41 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -1282,125 +1282,6 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK,
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 @@ Sema::BuildAnonymousStructUnionMemberReference(const CXXScopeSpec &SS,
/// 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 @@ ExprResult Sema::ActOnIdExpression(Scope *S,
// 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 @@ ExprResult Sema::ActOnIdExpression(Scope *S,
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 @@ Sema::PerformObjectMemberConversion(Expr *From,
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 @@ Sema::ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc,
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 @@ Sema::CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc,
}
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();<