#include "clang/Sema/Overload.h"
#include "clang/AST/ASTLambda.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"
#include "clang/Sema/Lookup.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/SemaInternal.h"
using namespace clang;
using namespace sema;
typedef llvm::SmallPtrSet<const CXXRecordDecl*, 4> BaseSet;
static bool isProvablyNotDerivedFrom(Sema &SemaRef, CXXRecordDecl *Record,
const BaseSet &Bases) {
auto BaseIsNotInSet = [&Bases](const CXXRecordDecl *Base) {
return !Bases.count(Base->getCanonicalDecl());
};
return BaseIsNotInSet(Record) && Record->forallBases(BaseIsNotInSet);
}
enum IMAKind {
IMA_Static,
IMA_Mixed,
IMA_Mixed_StaticContext,
IMA_Mixed_Unrelated,
IMA_Instance,
IMA_Unresolved,
IMA_Abstract,
IMA_Unresolved_StaticContext,
IMA_Field_Uneval_Context,
IMA_Error_StaticContext,
IMA_Error_Unrelated
};
static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef,
const LookupResult &R) {
assert(!R.empty() && (*R.begin())->isCXXClassMember());
DeclContext *DC = SemaRef.getFunctionLevelDeclContext();
bool isStaticContext = SemaRef.CXXThisTypeOverride.isNull() &&
(!isa<CXXMethodDecl>(DC) || cast<CXXMethodDecl>(DC)->isStatic());
if (R.isUnresolvableResult())
return isStaticContext ? IMA_Unresolved_StaticContext : IMA_Unresolved;
bool hasNonInstance = false;
bool isField = false;
BaseSet Classes;
for (NamedDecl *D : R) {
D = D->getUnderlyingDecl();
if (D->isCXXInstanceMember()) {
isField |= isa<FieldDecl>(D) || isa<MSPropertyDecl>(D) ||
isa<IndirectFieldDecl>(D);
CXXRecordDecl *R = cast<CXXRecordDecl>(D->getDeclContext());
Classes.insert(R->getCanonicalDecl());
} else
hasNonInstance = true;
}
if (Classes.empty())
return IMA_Static;
IMAKind AbstractInstanceResult = IMA_Static; assert(!AbstractInstanceResult);
switch (SemaRef.ExprEvalContexts.back().Context) {
case Sema::ExpressionEvaluationContext::Unevaluated:
case Sema::ExpressionEvaluationContext::UnevaluatedList:
if (isField && SemaRef.getLangOpts().CPlusPlus11)
AbstractInstanceResult = IMA_Field_Uneval_Context;
break;
case Sema::ExpressionEvaluationContext::UnevaluatedAbstract:
AbstractInstanceResult = IMA_Abstract;
break;
case Sema::ExpressionEvaluationContext::DiscardedStatement:
case Sema::ExpressionEvaluationContext::ConstantEvaluated:
case Sema::ExpressionEvaluationContext::ImmediateFunctionContext:
case Sema::ExpressionEvaluationContext::PotentiallyEvaluated:
case Sema::ExpressionEvaluationContext::PotentiallyEvaluatedIfUsed:
break;
}
if (isStaticContext) {
if (hasNonInstance)
return IMA_Mixed_StaticContext;
return AbstractInstanceResult ? AbstractInstanceResult
: IMA_Error_StaticContext;
}
CXXRecordDecl *contextClass;
if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(DC))
contextClass = MD->getParent()->getCanonicalDecl();
else
contextClass = cast<CXXRecordDecl>(DC);
if (R.getNamingClass() &&
contextClass->getCanonicalDecl() !=
R.getNamingClass()->getCanonicalDecl()) {
Classes.clear();
Classes.insert(R.getNamingClass()->getCanonicalDecl());
}
if (isProvablyNotDerivedFrom(SemaRef, contextClass, Classes))
return hasNonInstance ? IMA_Mixed_Unrelated :
AbstractInstanceResult ? AbstractInstanceResult :
IMA_Error_Unrelated;
return (hasNonInstance ? IMA_Mixed : IMA_Instance);
}
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());
Rep = Rep->getUnderlyingDecl();
DeclContext *FunctionLevelDC = SemaRef.getFunctionLevelDeclContext();
CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FunctionLevelDC);
CXXRecordDecl *ContextClass = Method ? Method->getParent() : nullptr;
CXXRecordDecl *RepClass = dyn_cast<CXXRecordDecl>(Rep->getDeclContext());
bool InStaticMethod = Method && Method->isStatic();
bool IsField = isa<FieldDecl>(Rep) || isa<IndirectFieldDecl>(Rep);
if (IsField && InStaticMethod)
SemaRef.Diag(Loc, diag::err_invalid_member_use_in_static_method)
<< Range << nameInfo.getName();
else if (ContextClass && RepClass && SS.isEmpty() && !InStaticMethod &&
!RepClass->Equals(ContextClass) && RepClass->Encloses(ContextClass))
SemaRef.Diag(Loc, diag::err_nested_non_static_member_use)
<< IsField << RepClass << nameInfo.getName() << ContextClass << Range;
else if (IsField)
SemaRef.Diag(Loc, diag::err_invalid_non_static_member_use)
<< nameInfo.getName() << Range;
else
SemaRef.Diag(Loc, diag::err_member_call_without_object)
<< Range;
}
ExprResult Sema::BuildPossibleImplicitMemberExpr(
const CXXScopeSpec &SS, SourceLocation TemplateKWLoc, LookupResult &R,
const TemplateArgumentListInfo *TemplateArgs, const Scope *S,
UnresolvedLookupExpr *AsULE) {
switch (ClassifyImplicitMemberAccess(*this, R)) {
case IMA_Instance:
return BuildImplicitMemberExpr(SS, TemplateKWLoc, R, TemplateArgs, true, S);
case IMA_Mixed:
case IMA_Mixed_Unrelated:
case IMA_Unresolved:
return BuildImplicitMemberExpr(SS, TemplateKWLoc, R, TemplateArgs, false,
S);
case IMA_Field_Uneval_Context:
Diag(R.getNameLoc(), diag::warn_cxx98_compat_non_static_member_use)
<< R.getLookupNameInfo().getName();
LLVM_FALLTHROUGH;
case IMA_Static:
case IMA_Abstract:
case IMA_Mixed_StaticContext:
case IMA_Unresolved_StaticContext:
if (TemplateArgs || TemplateKWLoc.isValid())
return BuildTemplateIdExpr(SS, TemplateKWLoc, R, false, TemplateArgs);
return AsULE ? AsULE : 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");
}
static bool
IsRGBA(char c) {
switch (c) {
case 'r':
case 'g':
case 'b':
case 'a':
return true;
default:
return false;
}
}
static bool IsValidOpenCLComponentSwizzleLength(unsigned len)
{
return (len >= 1 && len <= 4) || len == 8 || len == 16;
}
static QualType
CheckExtVectorComponent(Sema &S, QualType baseType, ExprValueKind &VK,
SourceLocation OpLoc, const IdentifierInfo *CompName,
SourceLocation CompLoc) {
const ExtVectorType *vecType = baseType->getAs<ExtVectorType>();
const char *compStr = CompName->getNameStart();
bool HalvingSwizzle = false;
bool HexSwizzle = (*compStr == 's' || *compStr == 'S') && compStr[1];
bool HasRepeated = false;
bool HasIndex[16] = {};
int Idx;
if (!strcmp(compStr, "hi") || !strcmp(compStr, "lo") ||
!strcmp(compStr, "even") || !strcmp(compStr, "odd")) {
HalvingSwizzle = true;
} else if (!HexSwizzle &&
(Idx = vecType->getPointAccessorIdx(*compStr)) != -1) {
bool HasRGBA = IsRGBA(*compStr);
do {
if (HasRGBA != IsRGBA(*compStr))
break;
if (HasIndex[Idx]) HasRepeated = true;
HasIndex[Idx] = true;
compStr++;
} while (*compStr && (Idx = vecType->getPointAccessorIdx(*compStr)) != -1);
if (HasRGBA || (*compStr && IsRGBA(*compStr))) {
if (S.getLangOpts().OpenCL &&
S.getLangOpts().getOpenCLCompatibleVersion() < 300) {
const char *DiagBegin = HasRGBA ? CompName->getNameStart() : compStr;
S.Diag(OpLoc, diag::ext_opencl_ext_vector_type_rgba_selector)
<< StringRef(DiagBegin, 1) << SourceRange(CompLoc);
}
}
} else {
if (HexSwizzle) compStr++;
while ((Idx = vecType->getNumericAccessorIdx(*compStr)) != -1) {
if (HasIndex[Idx]) HasRepeated = true;
HasIndex[Idx] = true;
compStr++;
}
}
if (!HalvingSwizzle && *compStr) {
S.Diag(OpLoc, diag::err_ext_vector_component_name_illegal)
<< StringRef(compStr, 1) << SourceRange(CompLoc);
return QualType();
}
if (!HalvingSwizzle) {
compStr = CompName->getNameStart();
if (HexSwizzle)
compStr++;
while (*compStr) {
if (!vecType->isAccessorWithinNumElements(*compStr++, HexSwizzle)) {
S.Diag(OpLoc, diag::err_ext_vector_component_exceeds_length)
<< baseType << SourceRange(CompLoc);
return QualType();
}
}
}
if (S.getLangOpts().OpenCL && !HalvingSwizzle) {
unsigned SwizzleLength = CompName->getLength();
if (HexSwizzle)
SwizzleLength--;
if (IsValidOpenCLComponentSwizzleLength(SwizzleLength) == false) {
S.Diag(OpLoc, diag::err_opencl_ext_vector_component_invalid_length)
<< SwizzleLength << SourceRange(CompLoc);
return QualType();
}
}
unsigned CompSize = HalvingSwizzle ? (vecType->getNumElements() + 1) / 2
: CompName->getLength();
if (HexSwizzle)
CompSize--;
if (CompSize == 1)
return vecType->getElementType();
if (HasRepeated)
VK = VK_PRValue;
QualType VT = S.Context.getExtVectorType(vecType->getElementType(), CompSize);
for (Sema::ExtVectorDeclsType::iterator
I = S.ExtVectorDecls.begin(S.getExternalSource()),
E = S.ExtVectorDecls.end();
I != E; ++I) {
if ((*I)->getUnderlyingType() == VT)
return S.Context.getTypedefType(*I);
}
return VT; }
static Decl *FindGetterSetterNameDeclFromProtocolList(const ObjCProtocolDecl*PDecl,
IdentifierInfo *Member,
const Selector &Sel,
ASTContext &Context) {
if (Member)
if (ObjCPropertyDecl *PD = PDecl->FindPropertyDeclaration(
Member, ObjCPropertyQueryKind::OBJC_PR_query_instance))
return PD;
if (ObjCMethodDecl *OMD = PDecl->getInstanceMethod(Sel))
return OMD;
for (const auto *I : PDecl->protocols()) {
if (Decl *D = FindGetterSetterNameDeclFromProtocolList(I, Member, Sel,
Context))
return D;
}
return nullptr;
}
static Decl *FindGetterSetterNameDecl(const ObjCObjectPointerType *QIdTy,
IdentifierInfo *Member,
const Selector &Sel,
ASTContext &Context) {
Decl *GDecl = nullptr;
for (const auto *I : QIdTy->quals()) {
if (Member)
if (ObjCPropertyDecl *PD = I->FindPropertyDeclaration(
Member, ObjCPropertyQueryKind::OBJC_PR_query_instance)) {
GDecl = PD;
break;
}
if (ObjCMethodDecl *OMD = I->getInstanceMethod(Sel)) {
GDecl = OMD;
break;
}
}
if (!GDecl) {
for (const auto *I : QIdTy->quals()) {
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,
SourceLocation TemplateKWLoc,
NamedDecl *FirstQualifierInScope,
const DeclarationNameInfo &NameInfo,
const TemplateArgumentListInfo *TemplateArgs) {
if (!IsArrow) {
const PointerType *PT = BaseType->getAs<PointerType>();
if (PT && (!getLangOpts().ObjC ||
PT->getPointeeType()->isRecordType())) {
assert(BaseExpr && "cannot happen with implicit member accesses");
Diag(OpLoc, diag::err_typecheck_member_reference_struct_union)
<< BaseType << BaseExpr->getSourceRange() << NameInfo.getSourceRange();
return ExprError();
}
}
assert(BaseType->isDependentType() || NameInfo.getName().isDependentName() ||
isDependentScopeSpecifier(SS) ||
(TemplateArgs && llvm::any_of(TemplateArgs->arguments(),
[](const TemplateArgumentLoc &Arg) {
return Arg.getArgument().isDependent();
})));
return CXXDependentScopeMemberExpr::Create(
Context, BaseExpr, BaseType, IsArrow, OpLoc,
SS.getWithLocInContext(Context), TemplateKWLoc, FirstQualifierInScope,
NameInfo, TemplateArgs);
}
static void DiagnoseQualifiedMemberReference(Sema &SemaRef,
Expr *BaseExpr,
QualType BaseType,
const CXXScopeSpec &SS,
NamedDecl *rep,
const DeclarationNameInfo &nameInfo) {
if (!BaseExpr)
return diagnoseInstanceReference(SemaRef, SS, rep, nameInfo);
SemaRef.Diag(nameInfo.getLoc(), diag::err_qualified_member_of_unrelated)
<< SS.getRange() << rep << BaseType;
}
bool Sema::CheckQualifiedMemberReference(Expr *BaseExpr,
QualType BaseType,
const CXXScopeSpec &SS,
const LookupResult &R) {
CXXRecordDecl *BaseRecord =
cast_or_null<CXXRecordDecl>(computeDeclContext(BaseType));
if (!BaseRecord) {
assert(BaseType->isDependentType());
return false;
}
for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) {
if (!BaseExpr && !(*I)->isCXXInstanceMember())
return false;
DeclContext *DC = (*I)->getDeclContext()->getNonTransparentContext();
if (!DC->isRecord())
continue;
CXXRecordDecl *MemberRecord = cast<CXXRecordDecl>(DC)->getCanonicalDecl();
if (BaseRecord->getCanonicalDecl() == MemberRecord ||
!BaseRecord->isProvablyNotDerivedFrom(MemberRecord))
return false;
}
DiagnoseQualifiedMemberReference(*this, BaseExpr, BaseType, SS,
R.getRepresentativeDecl(),
R.getLookupNameInfo());
return true;
}
namespace {
class RecordMemberExprValidatorCCC final : public CorrectionCandidateCallback {
public:
explicit RecordMemberExprValidatorCCC(const RecordType *RTy)
: Record(RTy->getDecl()) {
WantTypeSpecifiers = false;
WantExpressionKeywords = false;
WantCXXNamedCasts = false;
WantFunctionLikeCasts = false;
WantRemainingKeywords = false;
}
bool ValidateCandidate(const TypoCorrection &candidate) override {
NamedDecl *ND = candidate.getCorrectionDecl();
if (!ND || !(isa<ValueDecl>(ND) || isa<FunctionTemplateDecl>(ND)))
return false;
if (Record->containsDecl(ND))
return true;
if (const auto *RD = dyn_cast<CXXRecordDecl>(Record)) {
for (const auto &BS : RD->bases()) {
if (const auto *BSTy = BS.getType()->getAs<RecordType>()) {
if (BSTy->getDecl()->containsDecl(ND))
return true;
}
}
}
return false;
}
std::unique_ptr<CorrectionCandidateCallback> clone() override {
return std::make_unique<RecordMemberExprValidatorCCC>(*this);
}
private:
const RecordDecl *const Record;
};
}
static bool LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
Expr *BaseExpr,
const RecordType *RTy,
SourceLocation OpLoc, bool IsArrow,
CXXScopeSpec &SS, bool HasTemplateArgs,
SourceLocation TemplateKWLoc,
TypoExpr *&TE) {
SourceRange BaseRange = BaseExpr ? BaseExpr->getSourceRange() : SourceRange();
RecordDecl *RDecl = RTy->getDecl();
if (!SemaRef.isThisOutsideMemberFunctionBody(QualType(RTy, 0)) &&
SemaRef.RequireCompleteType(OpLoc, QualType(RTy, 0),
diag::err_typecheck_incomplete_tag,
BaseRange))
return true;
if (HasTemplateArgs || TemplateKWLoc.isValid()) {
QualType ObjectType = SS.isSet() ? QualType() : QualType(RTy, 0);
bool MOUS;
return SemaRef.LookupTemplateName(R, nullptr, SS, ObjectType, false, MOUS,
TemplateKWLoc);
}
DeclContext *DC = RDecl;
if (SS.isSet()) {
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;
}
}
SemaRef.LookupQualifiedName(R, DC, SS);
if (!R.empty())
return false;
DeclarationName Typo = R.getLookupName();
SourceLocation TypoLoc = R.getNameLoc();
struct QueryState {
Sema &SemaRef;
DeclarationNameInfo NameInfo;
Sema::LookupNameKind LookupKind;
Sema::RedeclarationKind Redecl;
};
QueryState Q = {R.getSema(), R.getLookupNameInfo(), R.getLookupKind(),
R.redeclarationKind()};
RecordMemberExprValidatorCCC CCC(RTy);
TE = SemaRef.CorrectTypoDelayed(
R.getLookupNameInfo(), R.getLookupKind(), nullptr, &SS, CCC,
[=, &SemaRef](const TypoCorrection &TC) {
if (TC) {
assert(!TC.isKeyword() &&
"Got a keyword as a correction for a member!");
bool DroppedSpecifier =
TC.WillReplaceSpecifier() &&
Typo.getAsString() == TC.getAsString(SemaRef.getLangOpts());
SemaRef.diagnoseTypo(TC, SemaRef.PDiag(diag::err_no_member_suggest)
<< Typo << DC << DroppedSpecifier
<< SS.getRange());
} else {
SemaRef.Diag(TypoLoc, diag::err_no_member) << Typo << DC << BaseRange;
}
},
[=](Sema &SemaRef, TypoExpr *TE, TypoCorrection TC) mutable {
LookupResult R(Q.SemaRef, Q.NameInfo, Q.LookupKind, Q.Redecl);
R.clear(); R.suppressDiagnostics();
R.setLookupName(TC.getCorrection());
for (NamedDecl *ND : TC)
R.addDecl(ND);
R.resolveKind();
return SemaRef.BuildMemberReferenceExpr(
BaseExpr, BaseExpr->getType(), OpLoc, IsArrow, SS, SourceLocation(),
nullptr, R, nullptr, nullptr);
},
Sema::CTK_ErrorRecovery, DC);
return false;
}
static ExprResult LookupMemberExpr(Sema &S, LookupResult &R,
ExprResult &BaseExpr, bool &IsArrow,
SourceLocation OpLoc, CXXScopeSpec &SS,
Decl *ObjCImpDecl, bool HasTemplateArgs,
SourceLocation TemplateKWLoc);
ExprResult
Sema::BuildMemberReferenceExpr(Expr *Base, QualType BaseType,
SourceLocation OpLoc, bool IsArrow,
CXXScopeSpec &SS,
SourceLocation TemplateKWLoc,
NamedDecl *FirstQualifierInScope,
const DeclarationNameInfo &NameInfo,
const TemplateArgumentListInfo *TemplateArgs,
const Scope *S,
ActOnMemberAccessExtraArgs *ExtraArgs) {
if (BaseType->isDependentType() ||
(SS.isSet() && isDependentScopeSpecifier(SS)))
return ActOnDependentMemberExpr(Base, BaseType,
IsArrow, OpLoc,
SS, TemplateKWLoc, FirstQualifierInScope,
NameInfo, TemplateArgs);
LookupResult R(*this, NameInfo, LookupMemberName);
if (!Base) {
TypoExpr *TE = nullptr;
QualType RecordTy = BaseType;
if (IsArrow) RecordTy = RecordTy->castAs<PointerType>()->getPointeeType();
if (LookupMemberExprInRecord(
*this, R, nullptr, RecordTy->getAs<RecordType>(), OpLoc, IsArrow,
SS, TemplateArgs != nullptr, TemplateKWLoc, TE))
return ExprError();
if (TE)
return TE;
} else {
ExprResult BaseResult = Base;
ExprResult Result =
LookupMemberExpr(*this, R, BaseResult, IsArrow, OpLoc, SS,
ExtraArgs ? ExtraArgs->ObjCImpDecl : nullptr,
TemplateArgs != nullptr, TemplateKWLoc);
if (BaseResult.isInvalid())
return ExprError();
Base = BaseResult.get();
if (Result.isInvalid())
return ExprError();
if (Result.get())
return Result;
BaseType = Base->getType();
}
return BuildMemberReferenceExpr(Base, BaseType,
OpLoc, IsArrow, SS, TemplateKWLoc,
FirstQualifierInScope, R, TemplateArgs, S,
false, ExtraArgs);
}
ExprResult
Sema::BuildAnonymousStructUnionMemberReference(const CXXScopeSpec &SS,
SourceLocation loc,
IndirectFieldDecl *indirectField,
DeclAccessPair foundDecl,
Expr *baseObjectExpr,
SourceLocation opLoc) {
VarDecl *baseVariable = indirectField->getVarDecl();
CXXScopeSpec EmptySS;
if (baseVariable) {
assert(baseVariable->getType()->isRecordType());
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.get();
}
assert((baseVariable || baseObjectExpr) &&
"referencing anonymous struct/union without a base variable or "
"expression");
Expr *result = baseObjectExpr;
IndirectFieldDecl::chain_iterator
FI = indirectField->chain_begin(), FEnd = indirectField->chain_end();
if (!baseVariable) {
FieldDecl *field = cast<FieldDecl>(*FI);
bool baseObjectIsPointer = baseObjectExpr->getType()->isPointerType();
DeclarationNameInfo memberNameInfo(field->getDeclName(), loc);
result =
BuildFieldReferenceExpr(result, baseObjectIsPointer, SourceLocation(),
SS, field, foundDecl, memberNameInfo)
.get();
if (!result)
return ExprError();
}
++FI;
while (FI != FEnd) {
FieldDecl *field = cast<FieldDecl>(*FI++);
DeclarationNameInfo memberNameInfo(field->getDeclName(), loc);
DeclAccessPair fakeFoundDecl =
DeclAccessPair::make(field, field->getAccess());
result =
BuildFieldReferenceExpr(result, false, SourceLocation(),
(FI == FEnd ? SS : EmptySS), field,
fakeFoundDecl, memberNameInfo)
.get();
}
return result;
}
static ExprResult
BuildMSPropertyRefExpr(Sema &S, Expr *BaseExpr, bool IsArrow,
const CXXScopeSpec &SS,
MSPropertyDecl *PD,
const DeclarationNameInfo &NameInfo) {
return new (S.Context) MSPropertyRefExpr(BaseExpr, PD, IsArrow,
S.Context.PseudoObjectTy, VK_LValue,
SS.getWithLocInContext(S.Context),
NameInfo.getLoc());
}
MemberExpr *Sema::BuildMemberExpr(
Expr *Base, bool IsArrow, SourceLocation OpLoc, const CXXScopeSpec *SS,
SourceLocation TemplateKWLoc, ValueDecl *Member, DeclAccessPair FoundDecl,
bool HadMultipleCandidates, const DeclarationNameInfo &MemberNameInfo,
QualType Ty, ExprValueKind VK, ExprObjectKind OK,
const TemplateArgumentListInfo *TemplateArgs) {
NestedNameSpecifierLoc NNS =
SS ? SS->getWithLocInContext(Context) : NestedNameSpecifierLoc();
return BuildMemberExpr(Base, IsArrow, OpLoc, NNS, TemplateKWLoc, Member,
FoundDecl, HadMultipleCandidates, MemberNameInfo, Ty,
VK, OK, TemplateArgs);
}
MemberExpr *Sema::BuildMemberExpr(
Expr *Base, bool IsArrow, SourceLocation OpLoc, NestedNameSpecifierLoc NNS,
SourceLocation TemplateKWLoc, ValueDecl *Member, DeclAccessPair FoundDecl,
bool HadMultipleCandidates, const DeclarationNameInfo &MemberNameInfo,
QualType Ty, ExprValueKind VK, ExprObjectKind OK,
const TemplateArgumentListInfo *TemplateArgs) {
assert((!IsArrow || Base->isPRValue()) &&
"-> base must be a pointer prvalue");
MemberExpr *E =
MemberExpr::Create(Context, Base, IsArrow, OpLoc, NNS, TemplateKWLoc,
Member, FoundDecl, MemberNameInfo, TemplateArgs, Ty,
VK, OK, getNonOdrUseReasonInCurrentContext(Member));
E->setHadMultipleCandidates(HadMultipleCandidates);
MarkMemberReferenced(E);
if (auto *FPT = Ty->getAs<FunctionProtoType>()) {
if (isUnresolvedExceptionSpec(FPT->getExceptionSpecType())) {
if (auto *NewFPT = ResolveExceptionSpec(MemberNameInfo.getLoc(), FPT))
E->setType(Context.getQualifiedType(NewFPT, Ty.getQualifiers()));
}
}
return E;
}
static bool IsInFnTryBlockHandler(const Scope *S) {
for (; S != S->getFnParent(); S = S->getParent()) {
if (S->isFnTryCatchScope())
return (S->getFlags() & Scope::TryScope) != Scope::TryScope;
}
return false;
}
ExprResult
Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
SourceLocation OpLoc, bool IsArrow,
const CXXScopeSpec &SS,
SourceLocation TemplateKWLoc,
NamedDecl *FirstQualifierInScope,
LookupResult &R,
const TemplateArgumentListInfo *TemplateArgs,
const Scope *S,
bool SuppressQualifierCheck,
ActOnMemberAccessExtraArgs *ExtraArgs) {
QualType BaseType = BaseExprType;
if (IsArrow) {
assert(BaseType->isPointerType());
BaseType = BaseType->castAs<PointerType>()->getPointeeType();
}
R.setBaseObjectType(BaseType);
if (!IsArrow && BaseExpr && BaseExpr->isPRValue()) {
ExprResult Converted = TemporaryMaterializationConversion(BaseExpr);
if (Converted.isInvalid())
return ExprError();
BaseExpr = Converted.get();
}
const DeclarationNameInfo &MemberNameInfo = R.getLookupNameInfo();
DeclarationName MemberName = MemberNameInfo.getName();
SourceLocation MemberLoc = MemberNameInfo.getLoc();
if (R.isAmbiguous())
return ExprError();
const auto *FD = getCurFunctionDecl();
if (S && BaseExpr && FD &&
(isa<CXXDestructorDecl>(FD) || isa<CXXConstructorDecl>(FD)) &&
isa<CXXThisExpr>(BaseExpr->IgnoreImpCasts()) &&
IsInFnTryBlockHandler(S))
Diag(MemberLoc, diag::warn_cdtor_function_try_handler_mem_expr)
<< isa<CXXDestructorDecl>(FD);
if (R.empty()) {
DeclContext *DC = (SS.isSet()
? computeDeclContext(SS, false)
: BaseType->castAs<RecordType>()->getDecl());
if (ExtraArgs) {
ExprResult RetryExpr;
if (!IsArrow && BaseExpr) {
SFINAETrap Trap(*this, true);
ParsedType ObjectType;
bool MayBePseudoDestructor = false;
RetryExpr = ActOnStartCXXMemberReference(getCurScope(), BaseExpr,
OpLoc, tok::arrow, ObjectType,
MayBePseudoDestructor);
if (RetryExpr.isUsable() && !Trap.hasErrorOccurred()) {
CXXScopeSpec TempSS(SS);
RetryExpr = ActOnMemberAccessExpr(
ExtraArgs->S, RetryExpr.get(), OpLoc, tok::arrow, TempSS,
TemplateKWLoc, ExtraArgs->Id, ExtraArgs->ObjCImpDecl);
}
if (Trap.hasErrorOccurred())
RetryExpr = ExprError();
}
if (RetryExpr.isUsable()) {
Diag(OpLoc, diag::err_no_member_overloaded_arrow)
<< MemberName << DC << FixItHint::CreateReplacement(OpLoc, "->");
return RetryExpr;
}
}
Diag(R.getNameLoc(), diag::err_no_member)
<< MemberName << DC
<< (BaseExpr ? BaseExpr->getSourceRange() : SourceRange());
return ExprError();
}
if ((SS.isSet() || !BaseExpr ||
(isa<CXXThisExpr>(BaseExpr) &&
cast<CXXThisExpr>(BaseExpr)->isImplicit())) &&
!SuppressQualifierCheck &&
CheckQualifiedMemberReference(BaseExpr, BaseType, SS, R))
return ExprError();
if (R.isOverloadedResult() || R.isUnresolvableResult()) {
R.suppressDiagnostics();
UnresolvedMemberExpr *MemExpr
= UnresolvedMemberExpr::Create(Context, R.isUnresolvableResult(),
BaseExpr, BaseExprType,
IsArrow, OpLoc,
SS.getWithLocInContext(Context),
TemplateKWLoc, MemberNameInfo,
TemplateArgs, R.begin(), R.end());
return MemExpr;
}
assert(R.isSingleResult());
DeclAccessPair FoundDecl = R.begin().getPair();
NamedDecl *MemberDecl = R.getFoundDecl();
if (MemberDecl->isInvalidDecl())
return ExprError();
if (!BaseExpr) {
if (!MemberDecl->isCXXInstanceMember()) {
if (TemplateArgs || TemplateKWLoc.isValid())
return BuildTemplateIdExpr(SS, TemplateKWLoc, R, false, TemplateArgs);
return BuildDeclarationNameExpr(SS, R.getLookupNameInfo(), MemberDecl,
FoundDecl, TemplateArgs);
}
SourceLocation Loc = R.getNameLoc();
if (SS.getRange().isValid())
Loc = SS.getRange().getBegin();
BaseExpr = BuildCXXThisExpr(Loc, BaseExprType, true);
}
if (DiagnoseUseOfDecl(MemberDecl, MemberLoc))
return ExprError();
if (FieldDecl *FD = dyn_cast<FieldDecl>(MemberDecl))
return BuildFieldReferenceExpr(BaseExpr, IsArrow, OpLoc, SS, FD, FoundDecl,
MemberNameInfo);
if (MSPropertyDecl *PD = dyn_cast<MSPropertyDecl>(MemberDecl))
return BuildMSPropertyRefExpr(*this, BaseExpr, IsArrow, SS, PD,
MemberNameInfo);
if (IndirectFieldDecl *FD = dyn_cast<IndirectFieldDecl>(MemberDecl))
return BuildAnonymousStructUnionMemberReference(SS, MemberLoc, FD,
FoundDecl, BaseExpr,
OpLoc);
if (VarDecl *Var = dyn_cast<VarDecl>(MemberDecl)) {
return BuildMemberExpr(BaseExpr, IsArrow, OpLoc, &SS, TemplateKWLoc, Var,
FoundDecl, false,
MemberNameInfo, Var->getType().getNonReferenceType(),
VK_LValue, OK_Ordinary);
}
if (CXXMethodDecl *MemberFn = dyn_cast<CXXMethodDecl>(MemberDecl)) {
ExprValueKind valueKind;
QualType type;
if (MemberFn->isInstance()) {
valueKind = VK_PRValue;
type = Context.BoundMemberTy;
} else {
valueKind = VK_LValue;
type = MemberFn->getType();
}
return BuildMemberExpr(BaseExpr, IsArrow, OpLoc, &SS, TemplateKWLoc,
MemberFn, FoundDecl, false,
MemberNameInfo, type, valueKind, OK_Ordinary);
}
assert(!isa<FunctionDecl>(MemberDecl) && "member function not C++ method?");
if (EnumConstantDecl *Enum = dyn_cast<EnumConstantDecl>(MemberDecl)) {
return BuildMemberExpr(BaseExpr, IsArrow, OpLoc, &SS, TemplateKWLoc, Enum,
FoundDecl, false,
MemberNameInfo, Enum->getType(), VK_PRValue,
OK_Ordinary);
}
if (VarTemplateDecl *VarTempl = dyn_cast<VarTemplateDecl>(MemberDecl)) {
if (!TemplateArgs) {
diagnoseMissingTemplateArguments(TemplateName(VarTempl), MemberLoc);
return ExprError();
}
DeclResult VDecl = CheckVarTemplateId(VarTempl, TemplateKWLoc,
MemberNameInfo.getLoc(), *TemplateArgs);
if (VDecl.isInvalid())
return ExprError();
if (!VDecl.get())
return ActOnDependentMemberExpr(
BaseExpr, BaseExpr->getType(), IsArrow, OpLoc, SS, TemplateKWLoc,
FirstQualifierInScope, MemberNameInfo, TemplateArgs);
VarDecl *Var = cast<VarDecl>(VDecl.get());
if (!Var->getTemplateSpecializationKind())
Var->setTemplateSpecializationKind(TSK_ImplicitInstantiation, MemberLoc);
return BuildMemberExpr(
BaseExpr, IsArrow, OpLoc, &SS, TemplateKWLoc, Var, FoundDecl,
false, MemberNameInfo,
Var->getType().getNonReferenceType(), VK_LValue, OK_Ordinary);
}
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();
}
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.getObjCIdRedefinitionType();
} else if (ty->isObjCClass()) {
redef = S.Context.getObjCClassRedefinitionType();
} else {
return false;
}
opty = redef->getAs<ObjCObjectPointerType>();
if (opty && !opty->getObjectType()->getInterface())
return false;
base = S.ImpCastExprToType(base.get(), redef, CK_BitCast);
return true;
}
static bool isRecordType(QualType T) {
return T->isRecordType();
}
static bool isPointerToRecordType(QualType T) {
if (const PointerType *PT = T->getAs<PointerType>())
return PT->getPointeeType()->isRecordType();
return false;
}
ExprResult
Sema::PerformMemberExprBaseConversion(Expr *Base, bool IsArrow) {
if (IsArrow && !Base->getType()->isFunctionType())
return DefaultFunctionArrayLvalueConversion(Base);
return CheckPlaceholderExpr(Base);
}
static ExprResult LookupMemberExpr(Sema &S, LookupResult &R,
ExprResult &BaseExpr, bool &IsArrow,
SourceLocation OpLoc, CXXScopeSpec &SS,
Decl *ObjCImpDecl, bool HasTemplateArgs,
SourceLocation TemplateKWLoc) {
assert(BaseExpr.get() && "no base expression");
BaseExpr = S.PerformMemberExprBaseConversion(BaseExpr.get(), IsArrow);
if (BaseExpr.isInvalid())
return ExprError();
QualType BaseType = BaseExpr.get()->getType();
assert(!BaseType->isDependentType());
DeclarationName MemberName = R.getLookupName();
SourceLocation MemberLoc = R.getNameLoc();
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()) {
if (!S.getLangOpts().CPlusPlus) {
S.Diag(OpLoc, diag::err_typecheck_member_reference_suggestion)
<< BaseType << int(IsArrow) << BaseExpr.get()->getSourceRange()
<< FixItHint::CreateReplacement(OpLoc, ".");
}
IsArrow = false;
} else if (BaseType->isFunctionType()) {
goto fail;
} else {
S.Diag(MemberLoc, diag::err_typecheck_member_reference_arrow)
<< BaseType << BaseExpr.get()->getSourceRange();
return ExprError();
}
}
if (const auto *ATy = BaseType->getAs<AtomicType>()) {
S.DiagRuntimeBehavior(OpLoc, nullptr,
S.PDiag(diag::warn_atomic_member_access));
BaseType = ATy->getValueType().getUnqualifiedType();
BaseExpr = ImplicitCastExpr::Create(
S.Context, IsArrow ? S.Context.getPointerType(BaseType) : BaseType,
CK_AtomicToNonAtomic, BaseExpr.get(), nullptr,
BaseExpr.get()->getValueKind(), FPOptionsOverride());
}
if (const RecordType *RTy = BaseType->getAs<RecordType>()) {
TypoExpr *TE = nullptr;
if (LookupMemberExprInRecord(S, R, BaseExpr.get(), RTy, OpLoc, IsArrow, SS,
HasTemplateArgs, TemplateKWLoc, TE))
return ExprError();
return ExprResult(TE);
}
if (const ObjCObjectType *OTy = BaseType->getAs<ObjCObjectType>()) {
if (!SS.isEmpty() && !SS.isInvalid()) {
S.Diag(SS.getRange().getBegin(), diag::err_qualified_objc_access)
<< 1 << SS.getScopeRep()
<< FixItHint::CreateRemoval(SS.getRange());
SS.clear();
}
IdentifierInfo *Member = MemberName.getAsIdentifierInfo();
ObjCInterfaceDecl *IDecl = OTy->getInterface();
if (!IDecl) {
if (S.getLangOpts().ObjCAutoRefCount &&
(OTy->isObjCId() || OTy->isObjCClass()))
goto fail;
if (OTy->isObjCId() && Member->isStr("isa"))
return new (S.Context) ObjCIsaExpr(BaseExpr.get(), IsArrow, MemberLoc,
OpLoc, S.Context.getObjCClassType());
if (ShouldTryAgainWithRedefinitionType(S, BaseExpr))
return LookupMemberExpr(S, R, BaseExpr, IsArrow, OpLoc, SS,
ObjCImpDecl, HasTemplateArgs, TemplateKWLoc);
goto fail;
}
if (S.RequireCompleteType(OpLoc, BaseType,
diag::err_typecheck_incomplete_tag,
BaseExpr.get()))
return ExprError();
ObjCInterfaceDecl *ClassDeclared = nullptr;
ObjCIvarDecl *IV = IDecl->lookupInstanceVariable(Member, ClassDeclared);
if (!IV) {
DeclFilterCCC<ObjCIvarDecl> Validator{};
Validator.IsObjCIvarLookup = IsArrow;
if (TypoCorrection Corrected = S.CorrectTypo(
R.getLookupNameInfo(), Sema::LookupMemberName, nullptr, nullptr,
Validator, Sema::CTK_ErrorRecovery, IDecl)) {
IV = Corrected.getCorrectionDeclAs<ObjCIvarDecl>();
S.diagnoseTypo(
Corrected,
S.PDiag(diag::err_typecheck_member_reference_ivar_suggest)
<< IDecl->getDeclName() << MemberName);
assert(!ClassDeclared);
Decl *D = cast<Decl>(IV->getDeclContext());
if (auto *Category = dyn_cast<ObjCCategoryDecl>(D))
D = Category->getClassInterface();
if (auto *Implementation = dyn_cast<ObjCImplementationDecl>(D))
ClassDeclared = Implementation->getClassInterface();
else if (auto *Interface = dyn_cast<ObjCInterfaceDecl>(D))
ClassDeclared = Interface;
assert(ClassDeclared && "cannot query interface");
} else {
if (IsArrow &&
IDecl->FindPropertyDeclaration(
Member, ObjCPropertyQueryKind::OBJC_PR_query_instance)) {
S.Diag(MemberLoc, diag::err_property_found_suggest)
<< Member << BaseExpr.get()->getType()
<< FixItHint::CreateReplacement(OpLoc, ".");
return ExprError();
}
S.Diag(MemberLoc, diag::err_typecheck_member_reference_ivar)
<< IDecl->getDeclName() << MemberName
<< BaseExpr.get()->getSourceRange();
return ExprError();
}
}
assert(ClassDeclared);
if (IV->isInvalidDecl())
return ExprError();
if (S.DiagnoseUseOfDecl(IV, MemberLoc))
return ExprError();
if (IV->getAccessControl() != ObjCIvarDecl::Public &&
IV->getAccessControl() != ObjCIvarDecl::Package) {
ObjCInterfaceDecl *ClassOfMethodDecl = nullptr;
if (ObjCMethodDecl *MD = S.getCurMethodDecl())
ClassOfMethodDecl = MD->getClassInterface();
else if (ObjCImpDecl && S.getCurFunctionDecl()) {
if (ObjCImplementationDecl *IMPD =
dyn_cast<ObjCImplementationDecl>(ObjCImpDecl))
ClassOfMethodDecl = IMPD->getClassInterface();
else if (ObjCCategoryImplDecl* CatImplClass =
dyn_cast<ObjCCategoryImplDecl>(ObjCImpDecl))
ClassOfMethodDecl = CatImplClass->getClassInterface();
}
if (!S.getLangOpts().DebuggerSupport) {
if (IV->getAccessControl() == ObjCIvarDecl::Private) {
if (!declaresSameEntity(ClassDeclared, IDecl) ||
!declaresSameEntity(ClassOfMethodDecl, ClassDeclared))
S.Diag(MemberLoc, diag::err_private_ivar_access)
<< IV->getDeclName();
} else if (!IDecl->isSuperClassOf(ClassOfMethodDecl))
S.Diag(MemberLoc, diag::err_protected_ivar_access)
<< IV->getDeclName();
}
}
bool warn = true;
if (S.getLangOpts().ObjCWeak) {
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) {
S.Diag(DE->getLocation(), diag::err_arc_weak_ivar_access);
warn = false;
}
}
if (warn) {
if (ObjCMethodDecl *MD = S.getCurMethodDecl()) {
ObjCMethodFamily MF = MD->getMethodFamily();
warn = (MF != OMF_init && MF != OMF_dealloc &&
MF != OMF_finalize &&
!S.IvarBacksCurrentMethodAccessor(IDecl, MD, IV));
}
if (warn)
S.Diag(MemberLoc, diag::warn_direct_ivar_access) << IV->getDeclName();
}
ObjCIvarRefExpr *Result = new (S.Context) ObjCIvarRefExpr(
IV, IV->getUsageType(BaseType), MemberLoc, OpLoc, BaseExpr.get(),
IsArrow);
if (IV->getType().getObjCLifetime() == Qualifiers::OCL_Weak) {
if (!S.isUnevaluatedContext() &&
!S.Diags.isIgnored(diag::warn_arc_repeated_use_of_weak, MemberLoc))
S.getCurFunction()->recordUseOfWeak(Result);
}
return Result;
}
const ObjCObjectPointerType *OPT;
if (!IsArrow && (OPT = BaseType->getAs<ObjCObjectPointerType>())) {
if (!SS.isEmpty() && !SS.isInvalid()) {
S.Diag(SS.getRange().getBegin(), diag::err_qualified_objc_access)
<< 0 << SS.getScopeRep() << FixItHint::CreateRemoval(SS.getRange());
SS.clear();
}
BaseExpr = S.DefaultLvalueConversion(BaseExpr.get());
if (BaseExpr.isInvalid())
return ExprError();
assert(S.Context.hasSameUnqualifiedType(BaseType,
BaseExpr.get()->getType()));
IdentifierInfo *Member = MemberName.getAsIdentifierInfo();
const ObjCObjectType *OT = OPT->getObjectType();
if (OT->isObjCId()) {
Selector Sel = S.PP.getSelectorTable().getNullarySelector(Member);
if (Decl *PMDecl =
FindGetterSetterNameDecl(OPT, Member, Sel, S.Context)) {
if (ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(PMDecl)) {
if (S.DiagnoseUseOfDecl(PD, MemberLoc))
return ExprError();
return new (S.Context)
ObjCPropertyRefExpr(PD, S.Context.PseudoObjectTy, VK_LValue,
OK_ObjCProperty, MemberLoc, BaseExpr.get());
}
if (ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(PMDecl)) {
Selector SetterSel =
SelectorTable::constructSetterSelector(S.PP.getIdentifierTable(),
S.PP.getSelectorTable(),
Member);
ObjCMethodDecl *SMD = nullptr;
if (Decl *SDecl = FindGetterSetterNameDecl(OPT,
nullptr,
SetterSel, S.Context))
SMD = dyn_cast<ObjCMethodDecl>(SDecl);
return new (S.Context)
ObjCPropertyRefExpr(OMD, SMD, S.Context.PseudoObjectTy, VK_LValue,
OK_ObjCProperty, MemberLoc, BaseExpr.get());
}
}
if (IsArrow && ShouldTryAgainWithRedefinitionType(S, BaseExpr))
return LookupMemberExpr(S, R, BaseExpr, IsArrow, OpLoc, SS,
ObjCImpDecl, HasTemplateArgs, TemplateKWLoc);
return ExprError(S.Diag(MemberLoc, diag::err_property_not_found)
<< MemberName << BaseType);
}
if (OT->isObjCClass()) {
ObjCMethodDecl *MD = S.getCurMethodDecl();
if (!MD) {
if (ShouldTryAgainWithRedefinitionType(S, BaseExpr))
return LookupMemberExpr(S, R, BaseExpr, IsArrow, OpLoc, SS,
ObjCImpDecl, HasTemplateArgs, TemplateKWLoc);
goto fail;
}
Selector Sel = S.PP.getSelectorTable().getNullarySelector(Member);
ObjCInterfaceDecl *IFace = MD->getClassInterface();
if (!IFace)
goto fail;
ObjCMethodDecl *Getter;
if ((Getter = IFace->lookupClassMethod(Sel))) {
if (S.DiagnoseUseOfDecl(Getter, MemberLoc))
return ExprError();
} else
Getter = IFace->lookupPrivateMethod(Sel, false);
Selector SetterSel =
SelectorTable::constructSetterSelector(S.PP.getIdentifierTable(),
S.PP.getSelectorTable(),
Member);
ObjCMethodDecl *Setter = IFace->lookupClassMethod(SetterSel);
if (!Setter) {
Setter = IFace->lookupPrivateMethod(SetterSel, false);
}
if (Setter && S.DiagnoseUseOfDecl(Setter, MemberLoc))
return ExprError();
if (Getter || Setter) {
return new (S.Context) ObjCPropertyRefExpr(
Getter, Setter, S.Context.PseudoObjectTy, VK_LValue,
OK_ObjCProperty, MemberLoc, BaseExpr.get());
}
if (ShouldTryAgainWithRedefinitionType(S, BaseExpr))
return LookupMemberExpr(S, R, BaseExpr, IsArrow, OpLoc, SS,
ObjCImpDecl, HasTemplateArgs, TemplateKWLoc);
return ExprError(S.Diag(MemberLoc, diag::err_property_not_found)
<< MemberName << BaseType);
}
return S.HandleExprPropertyRefExpr(OPT, BaseExpr.get(), OpLoc, MemberName,
MemberLoc, SourceLocation(), QualType(),
false);
}
if (BaseType->isExtVectorBoolType()) {
S.Diag(R.getNameLoc(), diag::err_ext_vector_component_name_illegal)
<< MemberName
<< (BaseExpr.get() ? BaseExpr.get()->getSourceRange() : SourceRange());
return ExprError();
}
if (BaseType->isExtVectorType()) {
IdentifierInfo *Member = MemberName.getAsIdentifierInfo();
ExprValueKind VK;
if (IsArrow)
VK = VK_LValue;
else {
if (PseudoObjectExpr *POE = dyn_cast<PseudoObjectExpr>(BaseExpr.get()))
VK = POE->getSyntacticForm()->getValueKind();
else
VK = BaseExpr.get()->getValueKind();
}
QualType ret = CheckExtVectorComponent(S, BaseType, VK, OpLoc,
Member, MemberLoc);
if (ret.isNull())
return ExprError();
Qualifiers BaseQ =
S.Context.getCanonicalType(BaseExpr.get()->getType()).getQualifiers();
ret = S.Context.getQualifiedType(ret, BaseQ);
return new (S.Context)
ExtVectorElementExpr(ret, VK, BaseExpr.get(), *Member, MemberLoc);
}
if (IsArrow && BaseType->isSpecificBuiltinType(BuiltinType::ObjCSel) &&
!S.Context.getObjCSelRedefinitionType()->isObjCSelType()) {
BaseExpr = S.ImpCastExprToType(
BaseExpr.get(), S.Context.getObjCSelRedefinitionType(), CK_BitCast);
return LookupMemberExpr(S, R, BaseExpr, IsArrow, OpLoc, SS,
ObjCImpDecl, HasTemplateArgs, TemplateKWLoc);
}
fail:
if (const PointerType *Ptr = BaseType->getAs<PointerType>()) {
if (!IsArrow && Ptr->getPointeeType()->isRecordType() &&
MemberName.getNameKind() != DeclarationName::CXXDestructorName) {
S.Diag(OpLoc, diag::err_typecheck_member_reference_suggestion)
<< BaseType << int(IsArrow) << BaseExpr.get()->getSourceRange()
<< FixItHint::CreateReplacement(OpLoc, "->");
if (S.isSFINAEContext())
return ExprError();
IsArrow = true;
return LookupMemberExpr(S, R, BaseExpr, IsArrow, OpLoc, SS,
ObjCImpDecl, HasTemplateArgs, TemplateKWLoc);
}
}
if (S.tryToRecoverWithCall(
BaseExpr, S.PDiag(diag::err_member_reference_needs_call),
false,
IsArrow ? &isPointerToRecordType : &isRecordType)) {
if (BaseExpr.isInvalid())
return ExprError();
BaseExpr = S.DefaultFunctionArrayConversion(BaseExpr.get());
return LookupMemberExpr(S, R, BaseExpr, IsArrow, OpLoc, SS,
ObjCImpDecl, HasTemplateArgs, TemplateKWLoc);
}
S.Diag(OpLoc, diag::err_typecheck_member_reference_struct_union)
<< BaseType << BaseExpr.get()->getSourceRange() << MemberLoc;
return ExprError();
}
ExprResult Sema::ActOnMemberAccessExpr(Scope *S, Expr *Base,
SourceLocation OpLoc,
tok::TokenKind OpKind,
CXXScopeSpec &SS,
SourceLocation TemplateKWLoc,
UnqualifiedId &Id,
Decl *ObjCImpDecl) {
if (SS.isSet() && SS.isInvalid())
return ExprError();
if (getLangOpts().MicrosoftExt &&
Id.getKind() == UnqualifiedIdKind::IK_ConstructorName)
Diag(Id.getSourceRange().getBegin(),
diag::ext_ms_explicit_constructor_call);
TemplateArgumentListInfo TemplateArgsBuffer;
DeclarationNameInfo NameInfo;
const TemplateArgumentListInfo *TemplateArgs;
DecomposeUnqualifiedId(Id, TemplateArgsBuffer,
NameInfo, TemplateArgs);
DeclarationName Name = NameInfo.getName();
bool IsArrow = (OpKind == tok::arrow);
if (getLangOpts().HLSL && IsArrow)
return ExprError(Diag(OpLoc, diag::err_hlsl_operator_unsupported) << 2);
NamedDecl *FirstQualifierInScope
= (!SS.isSet() ? nullptr : FindFirstQualifierInScope(S, SS.getScopeRep()));
ExprResult Result = MaybeConvertParenListExprToParenExpr(S, Base);
if (Result.isInvalid()) return ExprError();
Base = Result.get();
if (Base->getType()->isDependentType() || Name.isDependentName() ||
isDependentScopeSpecifier(SS)) {
return ActOnDependentMemberExpr(Base, Base->getType(), IsArrow, OpLoc, SS,
TemplateKWLoc, FirstQualifierInScope,
NameInfo, TemplateArgs);
}
ActOnMemberAccessExtraArgs ExtraArgs = {S, Id, ObjCImpDecl};
ExprResult Res = BuildMemberReferenceExpr(
Base, Base->getType(), OpLoc, IsArrow, SS, TemplateKWLoc,
FirstQualifierInScope, NameInfo, TemplateArgs, S, &ExtraArgs);
if (!Res.isInvalid() && isa<MemberExpr>(Res.get()))
CheckMemberAccessOfNoDeref(cast<MemberExpr>(Res.get()));
return Res;
}
void Sema::CheckMemberAccessOfNoDeref(const MemberExpr *E) {
if (isUnevaluatedContext())
return;
QualType ResultTy = E->getType();
if (ResultTy->isArrayType()) {
if (!E->isArrow()) {
CheckAddressOfNoDeref(E->getBase());
}
} else if (E->isArrow()) {
if (const auto *Ptr = dyn_cast<PointerType>(
E->getBase()->getType().getDesugaredType(Context))) {
if (Ptr->getPointeeType()->hasAttr(attr::NoDeref))
ExprEvalContexts.back().PossibleDerefs.insert(E);
}
}
}
ExprResult
Sema::BuildFieldReferenceExpr(Expr *BaseExpr, bool IsArrow,
SourceLocation OpLoc, const CXXScopeSpec &SS,
FieldDecl *Field, DeclAccessPair FoundDecl,
const DeclarationNameInfo &MemberNameInfo) {
ExprValueKind VK = VK_LValue;
ExprObjectKind OK = OK_Ordinary;
if (!IsArrow) {
if (BaseExpr->getObjectKind() == OK_Ordinary)
VK = BaseExpr->getValueKind();
else
VK = VK_PRValue;
}
if (VK != VK_PRValue && Field->isBitField())
OK = OK_BitField;
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->castAs<PointerType>()->getPointeeType();
Qualifiers BaseQuals = BaseType.getQualifiers();
BaseQuals.removeObjCGCAttr();
if (Field->isMutable()) BaseQuals.removeConst();
Qualifiers MemberQuals =
Context.getCanonicalType(MemberType).getQualifiers();
assert(!MemberQuals.hasAddressSpace());
Qualifiers Combined = BaseQuals + MemberQuals;
if (Combined != MemberQuals)
MemberType = Context.getQualifiedType(MemberType, Combined);
if (BaseType->hasAttr(attr::NoDeref))
MemberType =
Context.getAttributedType(attr::NoDeref, MemberType, MemberType);
}
auto *CurMethod = dyn_cast<CXXMethodDecl>(CurContext);
if (!(CurMethod && CurMethod->isDefaulted()))
UnusedPrivateFields.remove(Field);
ExprResult Base = PerformObjectMemberConversion(BaseExpr, SS.getScopeRep(),
FoundDecl, Field);
if (Base.isInvalid())
return ExprError();
if (getLangOpts().OpenMP && IsArrow &&
!CurContext->isDependentContext() &&
isa<CXXThisExpr>(Base.get()->IgnoreParenImpCasts())) {
if (auto *PrivateCopy = isOpenMPCapturedDecl(Field)) {
return getOpenMPCapturedExpr(PrivateCopy, VK, OK,
MemberNameInfo.getLoc());
}
}
return BuildMemberExpr(Base.get(), IsArrow, OpLoc, &SS,
SourceLocation(), Field, FoundDecl,
false, MemberNameInfo,
MemberType, VK, OK);
}
ExprResult
Sema::BuildImplicitMemberExpr(const CXXScopeSpec &SS,
SourceLocation TemplateKWLoc,
LookupResult &R,
const TemplateArgumentListInfo *TemplateArgs,
bool IsKnownInstance, const Scope *S) {
assert(!R.empty() && !R.isAmbiguous());
SourceLocation loc = R.getNameLoc();
QualType ThisTy = getCurrentThisType();
assert(!ThisTy.isNull() && "didn't correctly pre-flight capture of 'this'");
Expr *baseExpr = nullptr; if (IsKnownInstance) {
SourceLocation Loc = R.getNameLoc();
if (SS.getRange().isValid())
Loc = SS.getRange().getBegin();
baseExpr = BuildCXXThisExpr(loc, ThisTy, true);
}
return BuildMemberReferenceExpr(baseExpr, ThisTy,
SourceLocation(),
true,
SS, TemplateKWLoc,
nullptr,
R, TemplateArgs, S);
}