mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-11-27 23:51:56 +00:00
More capturing of 'this': implicit member expressions. Getting that
right for anonymous struct/union members led to me discovering some seemingly broken code in that area of Sema, which I fixed, partly by changing the representation of member pointer constants so that IndirectFieldDecls aren't expanded. This led to assorted cleanups with member pointers in CodeGen, and while I was doing that I saw some random other things to clean up. llvm-svn: 124785
This commit is contained in:
parent
981ca313d7
commit
f3a8860ee1
@ -1784,11 +1784,11 @@ public:
|
||||
const DeclarationNameInfo &NameInfo,
|
||||
const CXXScopeSpec *SS = 0);
|
||||
ExprResult
|
||||
BuildAnonymousStructUnionMemberReference(SourceLocation Loc,
|
||||
const CXXScopeSpec &SS,
|
||||
IndirectFieldDecl *IndirectField,
|
||||
Expr *BaseObjectExpr = 0,
|
||||
SourceLocation OpLoc = SourceLocation());
|
||||
BuildAnonymousStructUnionMemberReference(const CXXScopeSpec &SS,
|
||||
SourceLocation nameLoc,
|
||||
IndirectFieldDecl *indirectField,
|
||||
Expr *baseObjectExpr = 0,
|
||||
SourceLocation opLoc = SourceLocation());
|
||||
ExprResult BuildPossibleImplicitMemberExpr(const CXXScopeSpec &SS,
|
||||
LookupResult &R,
|
||||
const TemplateArgumentListInfo *TemplateArgs);
|
||||
@ -2271,7 +2271,12 @@ public:
|
||||
|
||||
|
||||
//// ActOnCXXThis - Parse 'this' pointer.
|
||||
ExprResult ActOnCXXThis(SourceLocation ThisLoc);
|
||||
ExprResult ActOnCXXThis(SourceLocation loc);
|
||||
|
||||
/// tryCaptureCXXThis - Try to capture a 'this' pointer. Returns a
|
||||
/// pointer to an instance method whose 'this' pointer is
|
||||
/// capturable, or null if this is not possible.
|
||||
CXXMethodDecl *tryCaptureCXXThis();
|
||||
|
||||
/// ActOnCXXBoolLiteral - Parse {true,false} literals.
|
||||
ExprResult ActOnCXXBoolLiteral(SourceLocation OpLoc, tok::TokenKind Kind);
|
||||
|
@ -105,10 +105,9 @@ llvm::Constant *CGCXXABI::EmitMemberPointer(const CXXMethodDecl *MD) {
|
||||
MD->getParent()->getTypeForDecl()));
|
||||
}
|
||||
|
||||
llvm::Constant *CGCXXABI::EmitMemberPointer(const FieldDecl *FD) {
|
||||
return GetBogusMemberPointer(CGM,
|
||||
CGM.getContext().getMemberPointerType(FD->getType(),
|
||||
FD->getParent()->getTypeForDecl()));
|
||||
llvm::Constant *CGCXXABI::EmitMemberDataPointer(const MemberPointerType *MPT,
|
||||
CharUnits offset) {
|
||||
return GetBogusMemberPointer(CGM, QualType(MPT, 0));
|
||||
}
|
||||
|
||||
bool CGCXXABI::isZeroInitializable(const MemberPointerType *MPT) {
|
||||
|
@ -122,7 +122,8 @@ public:
|
||||
virtual llvm::Constant *EmitMemberPointer(const CXXMethodDecl *MD);
|
||||
|
||||
/// Create a member pointer for the given field.
|
||||
virtual llvm::Constant *EmitMemberPointer(const FieldDecl *FD);
|
||||
virtual llvm::Constant *EmitMemberDataPointer(const MemberPointerType *MPT,
|
||||
CharUnits offset);
|
||||
|
||||
/// Emit a comparison between two member pointers. Returns an i1.
|
||||
virtual llvm::Value *
|
||||
|
@ -1178,24 +1178,10 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) {
|
||||
setObjCGCLValueClass(getContext(), E, LV);
|
||||
return LV;
|
||||
}
|
||||
|
||||
// If we're emitting an instance method as an independent lvalue,
|
||||
// we're actually emitting a member pointer.
|
||||
if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(ND))
|
||||
if (MD->isInstance()) {
|
||||
llvm::Value *V = CGM.getCXXABI().EmitMemberPointer(MD);
|
||||
return MakeAddrLValue(V, MD->getType(), Alignment);
|
||||
}
|
||||
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND))
|
||||
return EmitFunctionDeclLValue(*this, E, FD);
|
||||
|
||||
// If we're emitting a field as an independent lvalue, we're
|
||||
// actually emitting a member pointer.
|
||||
if (const FieldDecl *FD = dyn_cast<FieldDecl>(ND)) {
|
||||
llvm::Value *V = CGM.getCXXABI().EmitMemberPointer(FD);
|
||||
return MakeAddrLValue(V, FD->getType(), Alignment);
|
||||
}
|
||||
|
||||
|
||||
if (const FunctionDecl *fn = dyn_cast<FunctionDecl>(ND))
|
||||
return EmitFunctionDeclLValue(*this, E, fn);
|
||||
|
||||
assert(false && "Unhandled DeclRefExpr");
|
||||
|
||||
// an invalid LValue, but the assert will
|
||||
|
@ -450,17 +450,10 @@ public:
|
||||
llvm::Constant *VisitCompoundLiteralExpr(CompoundLiteralExpr *E) {
|
||||
return Visit(E->getInitializer());
|
||||
}
|
||||
|
||||
|
||||
llvm::Constant *VisitUnaryAddrOf(UnaryOperator *E) {
|
||||
if (const MemberPointerType *MPT =
|
||||
E->getType()->getAs<MemberPointerType>()) {
|
||||
DeclRefExpr *DRE = cast<DeclRefExpr>(E->getSubExpr());
|
||||
NamedDecl *ND = DRE->getDecl();
|
||||
if (MPT->isMemberFunctionPointer())
|
||||
return CGM.getCXXABI().EmitMemberPointer(cast<CXXMethodDecl>(ND));
|
||||
else
|
||||
return CGM.getCXXABI().EmitMemberPointer(cast<FieldDecl>(ND));
|
||||
}
|
||||
if (E->getType()->isMemberPointerType())
|
||||
return CGM.getMemberPointerConstant(E);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -934,6 +927,38 @@ llvm::Constant *CodeGenModule::EmitConstantExpr(const Expr *E,
|
||||
return C;
|
||||
}
|
||||
|
||||
static uint64_t getFieldOffset(ASTContext &C, const FieldDecl *field) {
|
||||
const ASTRecordLayout &layout = C.getASTRecordLayout(field->getParent());
|
||||
return layout.getFieldOffset(field->getFieldIndex());
|
||||
}
|
||||
|
||||
llvm::Constant *
|
||||
CodeGenModule::getMemberPointerConstant(const UnaryOperator *uo) {
|
||||
// Member pointer constants always have a very particular form.
|
||||
const MemberPointerType *type = cast<MemberPointerType>(uo->getType());
|
||||
const ValueDecl *decl = cast<DeclRefExpr>(uo->getSubExpr())->getDecl();
|
||||
|
||||
// A member function pointer.
|
||||
if (const CXXMethodDecl *method = dyn_cast<CXXMethodDecl>(decl))
|
||||
return getCXXABI().EmitMemberPointer(method);
|
||||
|
||||
// Otherwise, a member data pointer.
|
||||
uint64_t fieldOffset;
|
||||
if (const FieldDecl *field = dyn_cast<FieldDecl>(decl))
|
||||
fieldOffset = getFieldOffset(getContext(), field);
|
||||
else {
|
||||
const IndirectFieldDecl *ifield = cast<IndirectFieldDecl>(decl);
|
||||
|
||||
fieldOffset = 0;
|
||||
for (IndirectFieldDecl::chain_iterator ci = ifield->chain_begin(),
|
||||
ce = ifield->chain_end(); ci != ce; ++ci)
|
||||
fieldOffset += getFieldOffset(getContext(), cast<FieldDecl>(*ci));
|
||||
}
|
||||
|
||||
CharUnits chars = getContext().toCharUnitsFromBits((int64_t) fieldOffset);
|
||||
return getCXXABI().EmitMemberDataPointer(type, chars);
|
||||
}
|
||||
|
||||
static void
|
||||
FillInNullDataMemberPointers(CodeGenModule &CGM, QualType T,
|
||||
std::vector<llvm::Constant *> &Elements,
|
||||
@ -1000,9 +1025,10 @@ FillInNullDataMemberPointers(CodeGenModule &CGM, QualType T,
|
||||
uint64_t StartIndex = StartOffset / 8;
|
||||
uint64_t EndIndex = StartIndex + CGM.getContext().getTypeSize(T) / 8;
|
||||
|
||||
// FIXME: hardcodes Itanium member pointer representation!
|
||||
llvm::Constant *NegativeOne =
|
||||
llvm::ConstantInt::get(llvm::Type::getInt8Ty(CGM.getLLVMContext()),
|
||||
-1ULL, /*isSigned=*/true);
|
||||
-1ULL, /*isSigned*/true);
|
||||
|
||||
// Fill in the null data member pointer.
|
||||
for (uint64_t I = StartIndex; I != EndIndex; ++I)
|
||||
@ -1123,6 +1149,5 @@ llvm::Constant *CodeGenModule::EmitNullConstant(QualType T) {
|
||||
|
||||
// Itanium C++ ABI 2.3:
|
||||
// A NULL pointer is represented as -1.
|
||||
return llvm::ConstantInt::get(getTypes().ConvertTypeForMem(T), -1ULL,
|
||||
/*isSigned=*/true);
|
||||
return getCXXABI().EmitNullMemberPointer(T->castAs<MemberPointerType>());
|
||||
}
|
||||
|
@ -307,9 +307,9 @@ public:
|
||||
|
||||
|
||||
Value *VisitUnaryAddrOf(const UnaryOperator *E) {
|
||||
// If the sub-expression is an instance member reference,
|
||||
// EmitDeclRefLValue will magically emit it with the appropriate
|
||||
// value as the "address".
|
||||
if (isa<MemberPointerType>(E->getType())) // never sugared
|
||||
return CGF.CGM.getMemberPointerConstant(E);
|
||||
|
||||
return EmitLValue(E->getSubExpr()).getAddress();
|
||||
}
|
||||
Value *VisitUnaryDeref(const UnaryOperator *E) {
|
||||
|
@ -254,7 +254,7 @@ public:
|
||||
static LValue MakeAddr(llvm::Value *V, QualType T, unsigned Alignment,
|
||||
ASTContext &Context,
|
||||
llvm::MDNode *TBAAInfo = 0) {
|
||||
Qualifiers Quals = Context.getCanonicalType(T).getQualifiers();
|
||||
Qualifiers Quals = T.getQualifiers();
|
||||
Quals.setObjCGCAttr(Context.getObjCGCAttrKind(T));
|
||||
|
||||
LValue R;
|
||||
|
@ -438,6 +438,8 @@ public:
|
||||
Types.UpdateCompletedType(TD);
|
||||
}
|
||||
|
||||
llvm::Constant *getMemberPointerConstant(const UnaryOperator *e);
|
||||
|
||||
/// EmitConstantExpr - Try to emit the given expression as a
|
||||
/// constant; returns 0 if the expression cannot be emitted as a
|
||||
/// constant.
|
||||
|
@ -79,7 +79,8 @@ public:
|
||||
llvm::Constant *EmitNullMemberPointer(const MemberPointerType *MPT);
|
||||
|
||||
llvm::Constant *EmitMemberPointer(const CXXMethodDecl *MD);
|
||||
llvm::Constant *EmitMemberPointer(const FieldDecl *FD);
|
||||
llvm::Constant *EmitMemberDataPointer(const MemberPointerType *MPT,
|
||||
CharUnits offset);
|
||||
|
||||
llvm::Value *EmitMemberPointerComparison(CodeGenFunction &CGF,
|
||||
llvm::Value *L,
|
||||
@ -493,43 +494,13 @@ ItaniumCXXABI::EmitNullMemberPointer(const MemberPointerType *MPT) {
|
||||
/*Packed=*/false);
|
||||
}
|
||||
|
||||
static uint64_t getFieldOffset(const FieldDecl *FD, CodeGenModule &CGM) {
|
||||
const CGRecordLayout &RL = CGM.getTypes().getCGRecordLayout(FD->getParent());
|
||||
const llvm::StructType *ClassLTy = RL.getLLVMType();
|
||||
|
||||
unsigned FieldNo = RL.getLLVMFieldNo(FD);
|
||||
return
|
||||
CGM.getTargetData().getStructLayout(ClassLTy)->getElementOffset(FieldNo);
|
||||
}
|
||||
|
||||
llvm::Constant *ItaniumCXXABI::EmitMemberPointer(const FieldDecl *FD) {
|
||||
llvm::Constant *
|
||||
ItaniumCXXABI::EmitMemberDataPointer(const MemberPointerType *MPT,
|
||||
CharUnits offset) {
|
||||
// Itanium C++ ABI 2.3:
|
||||
// A pointer to data member is an offset from the base address of
|
||||
// the class object containing it, represented as a ptrdiff_t
|
||||
|
||||
const RecordDecl *parent = FD->getParent();
|
||||
if (!parent->isAnonymousStructOrUnion())
|
||||
return llvm::ConstantInt::get(getPtrDiffTy(), getFieldOffset(FD, CGM));
|
||||
|
||||
// Handle a field injected from an anonymous struct or union.
|
||||
|
||||
assert(FD->getDeclName() && "Requested pointer to member with no name!");
|
||||
|
||||
// Find the record which the field was injected into.
|
||||
while (parent->isAnonymousStructOrUnion())
|
||||
parent = cast<RecordDecl>(parent->getParent());
|
||||
|
||||
RecordDecl::lookup_const_result lookup = parent->lookup(FD->getDeclName());
|
||||
assert(lookup.first != lookup.second && "Didn't find the field!");
|
||||
const IndirectFieldDecl *indirectFD = cast<IndirectFieldDecl>(*lookup.first);
|
||||
|
||||
uint64_t Offset = 0;
|
||||
for (IndirectFieldDecl::chain_iterator
|
||||
I= indirectFD->chain_begin(), E= indirectFD->chain_end(); I!=E; ++I) {
|
||||
Offset += getFieldOffset(cast<FieldDecl>(*I), CGM);
|
||||
}
|
||||
|
||||
return llvm::ConstantInt::get(getPtrDiffTy(), Offset);
|
||||
return llvm::ConstantInt::get(getPtrDiffTy(), offset.getQuantity());
|
||||
}
|
||||
|
||||
llvm::Constant *ItaniumCXXABI::EmitMemberPointer(const CXXMethodDecl *MD) {
|
||||
|
@ -889,109 +889,116 @@ BuildFieldReferenceExpr(Sema &S, Expr *BaseExpr, bool IsArrow,
|
||||
const DeclarationNameInfo &MemberNameInfo);
|
||||
|
||||
ExprResult
|
||||
Sema::BuildAnonymousStructUnionMemberReference(SourceLocation Loc,
|
||||
const CXXScopeSpec &SS,
|
||||
IndirectFieldDecl *IndirectField,
|
||||
Expr *BaseObjectExpr,
|
||||
SourceLocation OpLoc) {
|
||||
// Build the expression that refers to the base object, from
|
||||
// which we will build a sequence of member references to each
|
||||
// of the anonymous union objects and, eventually, the field we
|
||||
// found via name lookup.
|
||||
bool BaseObjectIsPointer = false;
|
||||
Qualifiers BaseQuals;
|
||||
VarDecl *BaseObject = IndirectField->getVarDecl();
|
||||
if (BaseObject) {
|
||||
// BaseObject is an anonymous struct/union variable (and is,
|
||||
// therefore, not part of another non-anonymous record).
|
||||
MarkDeclarationReferenced(Loc, BaseObject);
|
||||
BaseObjectExpr =
|
||||
new (Context) DeclRefExpr(BaseObject, BaseObject->getType(),
|
||||
VK_LValue, Loc);
|
||||
BaseQuals
|
||||
= Context.getCanonicalType(BaseObject->getType()).getQualifiers();
|
||||
} else if (BaseObjectExpr) {
|
||||
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();
|
||||
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(SS, 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 *ObjectPtr = ObjectType->getAs<PointerType>()) {
|
||||
BaseObjectIsPointer = true;
|
||||
ObjectType = ObjectPtr->getPointeeType();
|
||||
QualType objectType = baseObjectExpr->getType();
|
||||
|
||||
if (const PointerType *ptr = objectType->getAs<PointerType>()) {
|
||||
baseObjectIsPointer = true;
|
||||
objectType = ptr->getPointeeType();
|
||||
} else {
|
||||
baseObjectIsPointer = false;
|
||||
}
|
||||
BaseQuals
|
||||
= Context.getCanonicalType(ObjectType).getQualifiers();
|
||||
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".
|
||||
DeclContext *DC = getFunctionLevelDeclContext();
|
||||
if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(DC)) {
|
||||
if (!MD->isStatic()) {
|
||||
QualType AnonFieldType
|
||||
= Context.getTagDeclType(
|
||||
cast<RecordDecl>(
|
||||
(*IndirectField->chain_begin())->getDeclContext()));
|
||||
QualType ThisType = Context.getTagDeclType(MD->getParent());
|
||||
if ((Context.getCanonicalType(AnonFieldType)
|
||||
== Context.getCanonicalType(ThisType)) ||
|
||||
IsDerivedFrom(ThisType, AnonFieldType)) {
|
||||
// Our base object expression is "this".
|
||||
BaseObjectExpr = new (Context) CXXThisExpr(Loc,
|
||||
MD->getThisType(Context),
|
||||
/*isImplicit=*/true);
|
||||
BaseObjectIsPointer = true;
|
||||
}
|
||||
} else {
|
||||
return ExprError(Diag(Loc,diag::err_invalid_member_use_in_static_method)
|
||||
<< IndirectField->getDeclName());
|
||||
}
|
||||
BaseQuals = Qualifiers::fromCVRMask(MD->getTypeQualifiers());
|
||||
CXXMethodDecl *method = tryCaptureCXXThis();
|
||||
if (!method) {
|
||||
Diag(loc, diag::err_invalid_member_use_in_static_method)
|
||||
<< indirectField->getDeclName();
|
||||
return ExprError();
|
||||
}
|
||||
|
||||
if (!BaseObjectExpr) {
|
||||
// The field is referenced for a pointer-to-member expression, e.g:
|
||||
//
|
||||
// struct S {
|
||||
// union {
|
||||
// char c;
|
||||
// };
|
||||
// };
|
||||
// char S::*foo = &S::c;
|
||||
//
|
||||
FieldDecl *field = IndirectField->getAnonField();
|
||||
DeclarationNameInfo NameInfo(field->getDeclName(), Loc);
|
||||
return BuildDeclRefExpr(field, field->getType().getNonReferenceType(),
|
||||
VK_LValue, NameInfo, &SS);
|
||||
}
|
||||
// Our base object expression is "this".
|
||||
baseObjectExpr =
|
||||
new (Context) CXXThisExpr(loc, method->getThisType(Context),
|
||||
/*isImplicit=*/ true);
|
||||
baseObjectIsPointer = true;
|
||||
baseQuals = Qualifiers::fromCVRMask(method->getTypeQualifiers());
|
||||
}
|
||||
|
||||
// Build the implicit member references to the field of the
|
||||
// anonymous struct/union.
|
||||
Expr *Result = BaseObjectExpr;
|
||||
Expr *result = baseObjectExpr;
|
||||
IndirectFieldDecl::chain_iterator
|
||||
FI = indirectField->chain_begin(), FEnd = indirectField->chain_end();
|
||||
|
||||
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);
|
||||
|
||||
// Skip the first VarDecl if present.
|
||||
if (BaseObject)
|
||||
FI++;
|
||||
for (; FI != FEnd; FI++) {
|
||||
FieldDecl *Field = cast<FieldDecl>(*FI);
|
||||
// FIXME: use the real found-decl info!
|
||||
DeclAccessPair foundDecl = DeclAccessPair::make(field, field->getAccess());
|
||||
|
||||
// FIXME: these are somewhat meaningless
|
||||
DeclarationNameInfo MemberNameInfo(Field->getDeclName(), Loc);
|
||||
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,
|
||||
SS, Field, FoundDecl, MemberNameInfo)
|
||||
.take();
|
||||
result = BuildFieldReferenceExpr(*this, result, baseObjectIsPointer,
|
||||
SS, field, foundDecl,
|
||||
memberNameInfo).take();
|
||||
baseObjectIsPointer = false;
|
||||
|
||||
// All the implicit accesses are dot-accesses.
|
||||
BaseObjectIsPointer = false;
|
||||
// FIXME: check qualified member access
|
||||
}
|
||||
|
||||
return Owned(Result);
|
||||
// In all cases, we should now skip the first declaration in the chain.
|
||||
++FI;
|
||||
|
||||
for (; FI != FEnd; FI++) {
|
||||
FieldDecl *field = cast<FieldDecl>(*FI);
|
||||
|
||||
// FIXME: these are somewhat meaningless
|
||||
DeclarationNameInfo memberNameInfo(field->getDeclName(), loc);
|
||||
DeclAccessPair foundDecl = DeclAccessPair::make(field, field->getAccess());
|
||||
CXXScopeSpec memberSS;
|
||||
|
||||
result = BuildFieldReferenceExpr(*this, result, /*isarrow*/ false,
|
||||
memberSS, field, foundDecl, memberNameInfo)
|
||||
.take();
|
||||
}
|
||||
|
||||
return Owned(result);
|
||||
}
|
||||
|
||||
/// Decomposes the given name into a DeclarationNameInfo, its location, and
|
||||
@ -1186,23 +1193,24 @@ static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef,
|
||||
/// Diagnose a reference to a field with no object available.
|
||||
static void DiagnoseInstanceReference(Sema &SemaRef,
|
||||
const CXXScopeSpec &SS,
|
||||
const LookupResult &R) {
|
||||
SourceLocation Loc = R.getNameLoc();
|
||||
NamedDecl *rep,
|
||||
const DeclarationNameInfo &nameInfo) {
|
||||
SourceLocation Loc = nameInfo.getLoc();
|
||||
SourceRange Range(Loc);
|
||||
if (SS.isSet()) Range.setBegin(SS.getRange().getBegin());
|
||||
|
||||
if (R.getAsSingle<FieldDecl>() || R.getAsSingle<IndirectFieldDecl>()) {
|
||||
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 << R.getLookupName();
|
||||
<< Range << nameInfo.getName();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
SemaRef.Diag(Loc, diag::err_invalid_non_static_member_use)
|
||||
<< R.getLookupName() << Range;
|
||||
<< nameInfo.getName() << Range;
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1678,7 +1686,8 @@ Sema::BuildPossibleImplicitMemberExpr(const CXXScopeSpec &SS,
|
||||
|
||||
case IMA_Error_StaticContext:
|
||||
case IMA_Error_Unrelated:
|
||||
DiagnoseInstanceReference(*this, SS, R);
|
||||
DiagnoseInstanceReference(*this, SS, R.getRepresentativeDecl(),
|
||||
R.getLookupNameInfo());
|
||||
return ExprError();
|
||||
}
|
||||
|
||||
@ -2075,29 +2084,30 @@ Sema::BuildImplicitMemberExpr(const CXXScopeSpec &SS,
|
||||
bool IsKnownInstance) {
|
||||
assert(!R.empty() && !R.isAmbiguous());
|
||||
|
||||
SourceLocation Loc = R.getNameLoc();
|
||||
SourceLocation loc = R.getNameLoc();
|
||||
|
||||
// We may have found a field within an anonymous union or struct
|
||||
// (C++ [class.union]).
|
||||
// FIXME: This needs to happen post-isImplicitMemberReference?
|
||||
// FIXME: template-ids inside anonymous structs?
|
||||
if (IndirectFieldDecl *FD = R.getAsSingle<IndirectFieldDecl>())
|
||||
return BuildAnonymousStructUnionMemberReference(Loc, SS, FD);
|
||||
return BuildAnonymousStructUnionMemberReference(SS, R.getNameLoc(), FD);
|
||||
|
||||
|
||||
// If this is known to be an instance access, go ahead and build a
|
||||
// If this is known to be an instance access, go ahead and build an
|
||||
// implicit 'this' expression now.
|
||||
// 'this' expression now.
|
||||
DeclContext *DC = getFunctionLevelDeclContext();
|
||||
QualType ThisType = cast<CXXMethodDecl>(DC)->getThisType(Context);
|
||||
Expr *This = 0; // null signifies implicit access
|
||||
CXXMethodDecl *method = tryCaptureCXXThis();
|
||||
assert(method && "didn't correctly pre-flight capture of 'this'");
|
||||
|
||||
QualType thisType = method->getThisType(Context);
|
||||
Expr *baseExpr = 0; // null signifies implicit access
|
||||
if (IsKnownInstance) {
|
||||
SourceLocation Loc = R.getNameLoc();
|
||||
if (SS.getRange().isValid())
|
||||
Loc = SS.getRange().getBegin();
|
||||
This = new (Context) CXXThisExpr(Loc, ThisType, /*isImplicit=*/true);
|
||||
baseExpr = new (Context) CXXThisExpr(loc, thisType, /*isImplicit=*/true);
|
||||
}
|
||||
|
||||
return BuildMemberReferenceExpr(This, ThisType,
|
||||
return BuildMemberReferenceExpr(baseExpr, thisType,
|
||||
/*OpLoc*/ SourceLocation(),
|
||||
/*IsArrow*/ true,
|
||||
SS,
|
||||
@ -2221,6 +2231,7 @@ static ExprValueKind getValueKindForDecl(ASTContext &Context,
|
||||
// FIXME: It's not clear to me why NonTypeTemplateParmDecl is a VarDecl.
|
||||
if (isa<VarDecl>(D) && !isa<NonTypeTemplateParmDecl>(D)) return VK_LValue;
|
||||
if (isa<FieldDecl>(D)) return VK_LValue;
|
||||
if (isa<IndirectFieldDecl>(D)) return VK_LValue;
|
||||
if (!Context.getLangOptions().CPlusPlus) return VK_RValue;
|
||||
if (isa<FunctionDecl>(D)) {
|
||||
if (isa<CXXMethodDecl>(D) && cast<CXXMethodDecl>(D)->isInstance())
|
||||
@ -2273,9 +2284,13 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
|
||||
if (VD->isInvalidDecl())
|
||||
return ExprError();
|
||||
|
||||
// Handle anonymous.
|
||||
if (IndirectFieldDecl *FD = dyn_cast<IndirectFieldDecl>(VD))
|
||||
return BuildAnonymousStructUnionMemberReference(Loc, SS, FD);
|
||||
// Handle members of anonymous structs and unions. If we got here,
|
||||
// and the reference is to a class member indirect field, then this
|
||||
// must be the subject of a pointer-to-member expression.
|
||||
if (IndirectFieldDecl *indirectField = dyn_cast<IndirectFieldDecl>(VD))
|
||||
if (!indirectField->isCXXClassMember())
|
||||
return BuildAnonymousStructUnionMemberReference(SS, NameInfo.getLoc(),
|
||||
indirectField);
|
||||
|
||||
ExprValueKind VK = getValueKindForDecl(Context, VD);
|
||||
|
||||
@ -3161,14 +3176,15 @@ static void DiagnoseQualifiedMemberReference(Sema &SemaRef,
|
||||
Expr *BaseExpr,
|
||||
QualType BaseType,
|
||||
const CXXScopeSpec &SS,
|
||||
const LookupResult &R) {
|
||||
NamedDecl *rep,
|
||||
const DeclarationNameInfo &nameInfo) {
|
||||
// If this is an implicit member access, use a different set of
|
||||
// diagnostics.
|
||||
if (!BaseExpr)
|
||||
return DiagnoseInstanceReference(SemaRef, SS, R);
|
||||
return DiagnoseInstanceReference(SemaRef, SS, rep, nameInfo);
|
||||
|
||||
SemaRef.Diag(R.getNameLoc(), diag::err_qualified_member_of_unrelated)
|
||||
<< SS.getRange() << R.getRepresentativeDecl() << BaseType;
|
||||
SemaRef.Diag(nameInfo.getLoc(), diag::err_qualified_member_of_unrelated)
|
||||
<< SS.getRange() << rep << BaseType;
|
||||
}
|
||||
|
||||
// Check whether the declarations we found through a nested-name
|
||||
@ -3217,7 +3233,9 @@ bool Sema::CheckQualifiedMemberReference(Expr *BaseExpr,
|
||||
return false;
|
||||
}
|
||||
|
||||
DiagnoseQualifiedMemberReference(*this, BaseExpr, BaseType, SS, R);
|
||||
DiagnoseQualifiedMemberReference(*this, BaseExpr, BaseType, SS,
|
||||
R.getRepresentativeDecl(),
|
||||
R.getLookupNameInfo());
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -3455,7 +3473,7 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
|
||||
if (IndirectFieldDecl *FD = dyn_cast<IndirectFieldDecl>(MemberDecl))
|
||||
// We may have found a field within an anonymous union or struct
|
||||
// (C++ [class.union]).
|
||||
return BuildAnonymousStructUnionMemberReference(MemberLoc, SS, FD,
|
||||
return BuildAnonymousStructUnionMemberReference(SS, MemberLoc, FD,
|
||||
BaseExpr, OpLoc);
|
||||
|
||||
if (VarDecl *Var = dyn_cast<VarDecl>(MemberDecl)) {
|
||||
@ -7255,7 +7273,7 @@ void Sema::ConvertPropertyForLValue(Expr *&LHS, Expr *&RHS, QualType &LHSTy) {
|
||||
/// - *(x + 1) -> x, if x is an array
|
||||
/// - &"123"[2] -> 0
|
||||
/// - & __real__ x -> x
|
||||
static NamedDecl *getPrimaryDecl(Expr *E) {
|
||||
static ValueDecl *getPrimaryDecl(Expr *E) {
|
||||
switch (E->getStmtClass()) {
|
||||
case Stmt::DeclRefExprClass:
|
||||
return cast<DeclRefExpr>(E)->getDecl();
|
||||
@ -7332,7 +7350,7 @@ static QualType CheckAddressOfOperand(Sema &S, Expr *OrigOp,
|
||||
// Technically, there should be a check for array subscript
|
||||
// expressions here, but the result of one is always an lvalue anyway.
|
||||
}
|
||||
NamedDecl *dcl = getPrimaryDecl(op);
|
||||
ValueDecl *dcl = getPrimaryDecl(op);
|
||||
Expr::LValueClassification lval = op->ClassifyLValue(S.Context);
|
||||
|
||||
if (lval == Expr::LV_ClassTemporary) {
|
||||
@ -7408,17 +7426,17 @@ static QualType CheckAddressOfOperand(Sema &S, Expr *OrigOp,
|
||||
}
|
||||
} else if (isa<FunctionTemplateDecl>(dcl)) {
|
||||
return S.Context.OverloadTy;
|
||||
} else if (FieldDecl *FD = dyn_cast<FieldDecl>(dcl)) {
|
||||
} else if (isa<FieldDecl>(dcl) || isa<IndirectFieldDecl>(dcl)) {
|
||||
// Okay: we can take the address of a field.
|
||||
// Could be a pointer to member, though, if there is an explicit
|
||||
// scope qualifier for the class.
|
||||
if (isa<DeclRefExpr>(op) && cast<DeclRefExpr>(op)->getQualifier()) {
|
||||
DeclContext *Ctx = dcl->getDeclContext();
|
||||
if (Ctx && Ctx->isRecord()) {
|
||||
if (FD->getType()->isReferenceType()) {
|
||||
if (dcl->getType()->isReferenceType()) {
|
||||
S.Diag(OpLoc,
|
||||
diag::err_cannot_form_pointer_to_member_of_reference_type)
|
||||
<< FD->getDeclName() << FD->getType();
|
||||
<< dcl->getDeclName() << dcl->getType();
|
||||
return QualType();
|
||||
}
|
||||
|
||||
|
@ -559,19 +559,22 @@ bool Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *&E) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ExprResult Sema::ActOnCXXThis(SourceLocation ThisLoc) {
|
||||
/// C++ 9.3.2: In the body of a non-static member function, the keyword this
|
||||
/// is a non-lvalue expression whose value is the address of the object for
|
||||
/// which the function is called.
|
||||
|
||||
// Ignore block scopes (but nothing else).
|
||||
CXXMethodDecl *Sema::tryCaptureCXXThis() {
|
||||
// Ignore block scopes: we can capture through them.
|
||||
// Ignore nested enum scopes: we'll diagnose non-constant expressions
|
||||
// where they're invalid, and other uses are legitimate.
|
||||
// Don't ignore nested class scopes: you can't use 'this' in a local class.
|
||||
DeclContext *DC = CurContext;
|
||||
while (isa<BlockDecl>(DC)) DC = cast<BlockDecl>(DC)->getDeclContext();
|
||||
while (true) {
|
||||
if (isa<BlockDecl>(DC)) DC = cast<BlockDecl>(DC)->getDeclContext();
|
||||
else if (isa<EnumDecl>(DC)) DC = cast<EnumDecl>(DC)->getDeclContext();
|
||||
else break;
|
||||
}
|
||||
|
||||
// If we're not an instance method, error out.
|
||||
// If we're not in an instance method, error out.
|
||||
CXXMethodDecl *method = dyn_cast<CXXMethodDecl>(DC);
|
||||
if (!method || !method->isInstance())
|
||||
return ExprError(Diag(ThisLoc, diag::err_invalid_this_use));
|
||||
return 0;
|
||||
|
||||
// Mark that we're closing on 'this' in all the block scopes, if applicable.
|
||||
for (unsigned idx = FunctionScopes.size() - 1;
|
||||
@ -579,7 +582,18 @@ ExprResult Sema::ActOnCXXThis(SourceLocation ThisLoc) {
|
||||
--idx)
|
||||
cast<BlockScopeInfo>(FunctionScopes[idx])->CapturesCXXThis = true;
|
||||
|
||||
return Owned(new (Context) CXXThisExpr(ThisLoc, method->getThisType(Context),
|
||||
return method;
|
||||
}
|
||||
|
||||
ExprResult Sema::ActOnCXXThis(SourceLocation loc) {
|
||||
/// C++ 9.3.2: In the body of a non-static member function, the keyword this
|
||||
/// is a non-lvalue expression whose value is the address of the object for
|
||||
/// which the function is called.
|
||||
|
||||
CXXMethodDecl *method = tryCaptureCXXThis();
|
||||
if (!method) return Diag(loc, diag::err_invalid_this_use);
|
||||
|
||||
return Owned(new (Context) CXXThisExpr(loc, method->getThisType(Context),
|
||||
/*isImplicit=*/false));
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user