| //===--- SemaExpr.cpp - Semantic Analysis for Expressions -----------------===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This file implements semantic analysis for expressions. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "TreeTransform.h" |
| #include "clang/AST/ASTConsumer.h" |
| #include "clang/AST/ASTContext.h" |
| #include "clang/AST/ASTLambda.h" |
| #include "clang/AST/ASTMutationListener.h" |
| #include "clang/AST/CXXInheritance.h" |
| #include "clang/AST/DeclObjC.h" |
| #include "clang/AST/DeclTemplate.h" |
| #include "clang/AST/EvaluatedExprVisitor.h" |
| #include "clang/AST/Expr.h" |
| #include "clang/AST/ExprCXX.h" |
| #include "clang/AST/ExprObjC.h" |
| #include "clang/AST/ExprOpenMP.h" |
| #include "clang/AST/RecursiveASTVisitor.h" |
| #include "clang/AST/TypeLoc.h" |
| #include "clang/Basic/FixedPoint.h" |
| #include "clang/Basic/PartialDiagnostic.h" |
| #include "clang/Basic/SourceManager.h" |
| #include "clang/Basic/TargetInfo.h" |
| #include "clang/Lex/LiteralSupport.h" |
| #include "clang/Lex/Preprocessor.h" |
| #include "clang/Sema/AnalysisBasedWarnings.h" |
| #include "clang/Sema/DeclSpec.h" |
| #include "clang/Sema/DelayedDiagnostic.h" |
| #include "clang/Sema/Designator.h" |
| #include "clang/Sema/Initialization.h" |
| #include "clang/Sema/Lookup.h" |
| #include "clang/Sema/Overload.h" |
| #include "clang/Sema/ParsedTemplate.h" |
| #include "clang/Sema/Scope.h" |
| #include "clang/Sema/ScopeInfo.h" |
| #include "clang/Sema/SemaFixItUtils.h" |
| #include "clang/Sema/SemaInternal.h" |
| #include "clang/Sema/Template.h" |
| #include "llvm/Support/ConvertUTF.h" |
| using namespace clang; |
| using namespace sema; |
| |
| /// Determine whether the use of this declaration is valid, without |
| /// emitting diagnostics. |
| bool Sema::CanUseDecl(NamedDecl *D, bool TreatUnavailableAsInvalid) { |
| // See if this is an auto-typed variable whose initializer we are parsing. |
| if (ParsingInitForAutoVars.count(D)) |
| return false; |
| |
| // See if this is a deleted function. |
| if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { |
| if (FD->isDeleted()) |
| return false; |
| |
| // If the function has a deduced return type, and we can't deduce it, |
| // then we can't use it either. |
| if (getLangOpts().CPlusPlus14 && FD->getReturnType()->isUndeducedType() && |
| DeduceReturnType(FD, SourceLocation(), /*Diagnose*/ false)) |
| return false; |
| |
| // See if this is an aligned allocation/deallocation function that is |
| // unavailable. |
| if (TreatUnavailableAsInvalid && |
| isUnavailableAlignedAllocationFunction(*FD)) |
| return false; |
| } |
| |
| // See if this function is unavailable. |
| if (TreatUnavailableAsInvalid && D->getAvailability() == AR_Unavailable && |
| cast<Decl>(CurContext)->getAvailability() != AR_Unavailable) |
| return false; |
| |
| return true; |
| } |
| |
| static void DiagnoseUnusedOfDecl(Sema &S, NamedDecl *D, SourceLocation Loc) { |
| // Warn if this is used but marked unused. |
| if (const auto *A = D->getAttr<UnusedAttr>()) { |
| // [[maybe_unused]] should not diagnose uses, but __attribute__((unused)) |
| // should diagnose them. |
| if (A->getSemanticSpelling() != UnusedAttr::CXX11_maybe_unused && |
| A->getSemanticSpelling() != UnusedAttr::C2x_maybe_unused) { |
| const Decl *DC = cast_or_null<Decl>(S.getCurObjCLexicalContext()); |
| if (DC && !DC->hasAttr<UnusedAttr>()) |
| S.Diag(Loc, diag::warn_used_but_marked_unused) << D->getDeclName(); |
| } |
| } |
| } |
| |
| /// Emit a note explaining that this function is deleted. |
| void Sema::NoteDeletedFunction(FunctionDecl *Decl) { |
| assert(Decl->isDeleted()); |
| |
| CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Decl); |
| |
| if (Method && Method->isDeleted() && Method->isDefaulted()) { |
| // If the method was explicitly defaulted, point at that declaration. |
| if (!Method->isImplicit()) |
| Diag(Decl->getLocation(), diag::note_implicitly_deleted); |
| |
| // Try to diagnose why this special member function was implicitly |
| // deleted. This might fail, if that reason no longer applies. |
| CXXSpecialMember CSM = getSpecialMember(Method); |
| if (CSM != CXXInvalid) |
| ShouldDeleteSpecialMember(Method, CSM, nullptr, /*Diagnose=*/true); |
| |
| return; |
| } |
| |
| auto *Ctor = dyn_cast<CXXConstructorDecl>(Decl); |
| if (Ctor && Ctor->isInheritingConstructor()) |
| return NoteDeletedInheritingConstructor(Ctor); |
| |
| Diag(Decl->getLocation(), diag::note_availability_specified_here) |
| << Decl << 1; |
| } |
| |
| /// Determine whether a FunctionDecl was ever declared with an |
| /// explicit storage class. |
| static bool hasAnyExplicitStorageClass(const FunctionDecl *D) { |
| for (auto I : D->redecls()) { |
| if (I->getStorageClass() != SC_None) |
| return true; |
| } |
| return false; |
| } |
| |
| /// Check whether we're in an extern inline function and referring to a |
| /// variable or function with internal linkage (C11 6.7.4p3). |
| /// |
| /// This is only a warning because we used to silently accept this code, but |
| /// in many cases it will not behave correctly. This is not enabled in C++ mode |
| /// because the restriction language is a bit weaker (C++11 [basic.def.odr]p6) |
| /// and so while there may still be user mistakes, most of the time we can't |
| /// prove that there are errors. |
| static void diagnoseUseOfInternalDeclInInlineFunction(Sema &S, |
| const NamedDecl *D, |
| SourceLocation Loc) { |
| // This is disabled under C++; there are too many ways for this to fire in |
| // contexts where the warning is a false positive, or where it is technically |
| // correct but benign. |
| if (S.getLangOpts().CPlusPlus) |
| return; |
| |
| // Check if this is an inlined function or method. |
| FunctionDecl *Current = S.getCurFunctionDecl(); |
| if (!Current) |
| return; |
| if (!Current->isInlined()) |
| return; |
| if (!Current->isExternallyVisible()) |
| return; |
| |
| // Check if the decl has internal linkage. |
| if (D->getFormalLinkage() != InternalLinkage) |
| return; |
| |
| // Downgrade from ExtWarn to Extension if |
| // (1) the supposedly external inline function is in the main file, |
| // and probably won't be included anywhere else. |
| // (2) the thing we're referencing is a pure function. |
| // (3) the thing we're referencing is another inline function. |
| // This last can give us false negatives, but it's better than warning on |
| // wrappers for simple C library functions. |
| const FunctionDecl *UsedFn = dyn_cast<FunctionDecl>(D); |
| bool DowngradeWarning = S.getSourceManager().isInMainFile(Loc); |
| if (!DowngradeWarning && UsedFn) |
| DowngradeWarning = UsedFn->isInlined() || UsedFn->hasAttr<ConstAttr>(); |
| |
| S.Diag(Loc, DowngradeWarning ? diag::ext_internal_in_extern_inline_quiet |
| : diag::ext_internal_in_extern_inline) |
| << /*IsVar=*/!UsedFn << D; |
| |
| S.MaybeSuggestAddingStaticToDecl(Current); |
| |
| S.Diag(D->getCanonicalDecl()->getLocation(), diag::note_entity_declared_at) |
| << D; |
| } |
| |
| void Sema::MaybeSuggestAddingStaticToDecl(const FunctionDecl *Cur) { |
| const FunctionDecl *First = Cur->getFirstDecl(); |
| |
| // Suggest "static" on the function, if possible. |
| if (!hasAnyExplicitStorageClass(First)) { |
| SourceLocation DeclBegin = First->getSourceRange().getBegin(); |
| Diag(DeclBegin, diag::note_convert_inline_to_static) |
| << Cur << FixItHint::CreateInsertion(DeclBegin, "static "); |
| } |
| } |
| |
| /// Determine whether the use of this declaration is valid, and |
| /// emit any corresponding diagnostics. |
| /// |
| /// This routine diagnoses various problems with referencing |
| /// declarations that can occur when using a declaration. For example, |
| /// it might warn if a deprecated or unavailable declaration is being |
| /// used, or produce an error (and return true) if a C++0x deleted |
| /// function is being used. |
| /// |
| /// \returns true if there was an error (this declaration cannot be |
| /// referenced), false otherwise. |
| /// |
| bool Sema::DiagnoseUseOfDecl(NamedDecl *D, ArrayRef<SourceLocation> Locs, |
| const ObjCInterfaceDecl *UnknownObjCClass, |
| bool ObjCPropertyAccess, |
| bool AvoidPartialAvailabilityChecks, |
| ObjCInterfaceDecl *ClassReceiver) { |
| SourceLocation Loc = Locs.front(); |
| if (getLangOpts().CPlusPlus && isa<FunctionDecl>(D)) { |
| // If there were any diagnostics suppressed by template argument deduction, |
| // emit them now. |
| auto Pos = SuppressedDiagnostics.find(D->getCanonicalDecl()); |
| if (Pos != SuppressedDiagnostics.end()) { |
| for (const PartialDiagnosticAt &Suppressed : Pos->second) |
| Diag(Suppressed.first, Suppressed.second); |
| |
| // Clear out the list of suppressed diagnostics, so that we don't emit |
| // them again for this specialization. However, we don't obsolete this |
| // entry from the table, because we want to avoid ever emitting these |
| // diagnostics again. |
| Pos->second.clear(); |
| } |
| |
| // C++ [basic.start.main]p3: |
| // The function 'main' shall not be used within a program. |
| if (cast<FunctionDecl>(D)->isMain()) |
| Diag(Loc, diag::ext_main_used); |
| |
| diagnoseUnavailableAlignedAllocation(*cast<FunctionDecl>(D), Loc); |
| } |
| |
| // See if this is an auto-typed variable whose initializer we are parsing. |
| if (ParsingInitForAutoVars.count(D)) { |
| if (isa<BindingDecl>(D)) { |
| Diag(Loc, diag::err_binding_cannot_appear_in_own_initializer) |
| << D->getDeclName(); |
| } else { |
| Diag(Loc, diag::err_auto_variable_cannot_appear_in_own_initializer) |
| << D->getDeclName() << cast<VarDecl>(D)->getType(); |
| } |
| return true; |
| } |
| |
| // See if this is a deleted function. |
| if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { |
| if (FD->isDeleted()) { |
| auto *Ctor = dyn_cast<CXXConstructorDecl>(FD); |
| if (Ctor && Ctor->isInheritingConstructor()) |
| Diag(Loc, diag::err_deleted_inherited_ctor_use) |
| << Ctor->getParent() |
| << Ctor->getInheritedConstructor().getConstructor()->getParent(); |
| else |
| Diag(Loc, diag::err_deleted_function_use); |
| NoteDeletedFunction(FD); |
| return true; |
| } |
| |
| // If the function has a deduced return type, and we can't deduce it, |
| // then we can't use it either. |
| if (getLangOpts().CPlusPlus14 && FD->getReturnType()->isUndeducedType() && |
| DeduceReturnType(FD, Loc)) |
| return true; |
| |
| if (getLangOpts().CUDA && !CheckCUDACall(Loc, FD)) |
| return true; |
| } |
| |
| if (auto *MD = dyn_cast<CXXMethodDecl>(D)) { |
| // Lambdas are only default-constructible or assignable in C++2a onwards. |
| if (MD->getParent()->isLambda() && |
| ((isa<CXXConstructorDecl>(MD) && |
| cast<CXXConstructorDecl>(MD)->isDefaultConstructor()) || |
| MD->isCopyAssignmentOperator() || MD->isMoveAssignmentOperator())) { |
| Diag(Loc, diag::warn_cxx17_compat_lambda_def_ctor_assign) |
| << !isa<CXXConstructorDecl>(MD); |
| } |
| } |
| |
| auto getReferencedObjCProp = [](const NamedDecl *D) -> |
| const ObjCPropertyDecl * { |
| if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) |
| return MD->findPropertyDecl(); |
| return nullptr; |
| }; |
| if (const ObjCPropertyDecl *ObjCPDecl = getReferencedObjCProp(D)) { |
| if (diagnoseArgIndependentDiagnoseIfAttrs(ObjCPDecl, Loc)) |
| return true; |
| } else if (diagnoseArgIndependentDiagnoseIfAttrs(D, Loc)) { |
| return true; |
| } |
| |
| // [OpenMP 4.0], 2.15 declare reduction Directive, Restrictions |
| // Only the variables omp_in and omp_out are allowed in the combiner. |
| // Only the variables omp_priv and omp_orig are allowed in the |
| // initializer-clause. |
| auto *DRD = dyn_cast<OMPDeclareReductionDecl>(CurContext); |
| if (LangOpts.OpenMP && DRD && !CurContext->containsDecl(D) && |
| isa<VarDecl>(D)) { |
| Diag(Loc, diag::err_omp_wrong_var_in_declare_reduction) |
| << getCurFunction()->HasOMPDeclareReductionCombiner; |
| Diag(D->getLocation(), diag::note_entity_declared_at) << D; |
| return true; |
| } |
| |
| // [OpenMP 5.0], 2.19.7.3. declare mapper Directive, Restrictions |
| // List-items in map clauses on this construct may only refer to the declared |
| // variable var and entities that could be referenced by a procedure defined |
| // at the same location |
| auto *DMD = dyn_cast<OMPDeclareMapperDecl>(CurContext); |
| if (LangOpts.OpenMP && DMD && !CurContext->containsDecl(D) && |
| isa<VarDecl>(D)) { |
| Diag(Loc, diag::err_omp_declare_mapper_wrong_var) |
| << DMD->getVarName().getAsString(); |
| Diag(D->getLocation(), diag::note_entity_declared_at) << D; |
| return true; |
| } |
| |
| DiagnoseAvailabilityOfDecl(D, Locs, UnknownObjCClass, ObjCPropertyAccess, |
| AvoidPartialAvailabilityChecks, ClassReceiver); |
| |
| DiagnoseUnusedOfDecl(*this, D, Loc); |
| |
| diagnoseUseOfInternalDeclInInlineFunction(*this, D, Loc); |
| |
| return false; |
| } |
| |
| /// DiagnoseSentinelCalls - This routine checks whether a call or |
| /// message-send is to a declaration with the sentinel attribute, and |
| /// if so, it checks that the requirements of the sentinel are |
| /// satisfied. |
| void Sema::DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc, |
| ArrayRef<Expr *> Args) { |
| const SentinelAttr *attr = D->getAttr<SentinelAttr>(); |
| if (!attr) |
| return; |
| |
| // The number of formal parameters of the declaration. |
| unsigned numFormalParams; |
| |
| // The kind of declaration. This is also an index into a %select in |
| // the diagnostic. |
| enum CalleeType { CT_Function, CT_Method, CT_Block } calleeType; |
| |
| if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) { |
| numFormalParams = MD->param_size(); |
| calleeType = CT_Method; |
| } else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { |
| numFormalParams = FD->param_size(); |
| calleeType = CT_Function; |
| } else if (isa<VarDecl>(D)) { |
| QualType type = cast<ValueDecl>(D)->getType(); |
| const FunctionType *fn = nullptr; |
| if (const PointerType *ptr = type->getAs<PointerType>()) { |
| fn = ptr->getPointeeType()->getAs<FunctionType>(); |
| if (!fn) return; |
| calleeType = CT_Function; |
| } else if (const BlockPointerType *ptr = type->getAs<BlockPointerType>()) { |
| fn = ptr->getPointeeType()->castAs<FunctionType>(); |
| calleeType = CT_Block; |
| } else { |
| return; |
| } |
| |
| if (const FunctionProtoType *proto = dyn_cast<FunctionProtoType>(fn)) { |
| numFormalParams = proto->getNumParams(); |
| } else { |
| numFormalParams = 0; |
| } |
| } else { |
| return; |
| } |
| |
| // "nullPos" is the number of formal parameters at the end which |
| // effectively count as part of the variadic arguments. This is |
| // useful if you would prefer to not have *any* formal parameters, |
| // but the language forces you to have at least one. |
| unsigned nullPos = attr->getNullPos(); |
| assert((nullPos == 0 || nullPos == 1) && "invalid null position on sentinel"); |
| numFormalParams = (nullPos > numFormalParams ? 0 : numFormalParams - nullPos); |
| |
| // The number of arguments which should follow the sentinel. |
| unsigned numArgsAfterSentinel = attr->getSentinel(); |
| |
| // If there aren't enough arguments for all the formal parameters, |
| // the sentinel, and the args after the sentinel, complain. |
| if (Args.size() < numFormalParams + numArgsAfterSentinel + 1) { |
| Diag(Loc, diag::warn_not_enough_argument) << D->getDeclName(); |
| Diag(D->getLocation(), diag::note_sentinel_here) << int(calleeType); |
| return; |
| } |
| |
| // Otherwise, find the sentinel expression. |
| Expr *sentinelExpr = Args[Args.size() - numArgsAfterSentinel - 1]; |
| if (!sentinelExpr) return; |
| if (sentinelExpr->isValueDependent()) return; |
| if (Context.isSentinelNullExpr(sentinelExpr)) return; |
| |
| // Pick a reasonable string to insert. Optimistically use 'nil', 'nullptr', |
| // or 'NULL' if those are actually defined in the context. Only use |
| // 'nil' for ObjC methods, where it's much more likely that the |
| // variadic arguments form a list of object pointers. |
| SourceLocation MissingNilLoc = getLocForEndOfToken(sentinelExpr->getEndLoc()); |
| std::string NullValue; |
| if (calleeType == CT_Method && PP.isMacroDefined("nil")) |
| NullValue = "nil"; |
| else if (getLangOpts().CPlusPlus11) |
| NullValue = "nullptr"; |
| else if (PP.isMacroDefined("NULL")) |
| NullValue = "NULL"; |
| else |
| NullValue = "(void*) 0"; |
| |
| if (MissingNilLoc.isInvalid()) |
| Diag(Loc, diag::warn_missing_sentinel) << int(calleeType); |
| else |
| Diag(MissingNilLoc, diag::warn_missing_sentinel) |
| << int(calleeType) |
| << FixItHint::CreateInsertion(MissingNilLoc, ", " + NullValue); |
| Diag(D->getLocation(), diag::note_sentinel_here) << int(calleeType); |
| } |
| |
| SourceRange Sema::getExprRange(Expr *E) const { |
| return E ? E->getSourceRange() : SourceRange(); |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // Standard Promotions and Conversions |
| //===----------------------------------------------------------------------===// |
| |
| /// DefaultFunctionArrayConversion (C99 6.3.2.1p3, C99 6.3.2.1p4). |
| ExprResult Sema::DefaultFunctionArrayConversion(Expr *E, bool Diagnose) { |
| // Handle any placeholder expressions which made it here. |
| if (E->getType()->isPlaceholderType()) { |
| ExprResult result = CheckPlaceholderExpr(E); |
| if (result.isInvalid()) return ExprError(); |
| E = result.get(); |
| } |
| |
| QualType Ty = E->getType(); |
| assert(!Ty.isNull() && "DefaultFunctionArrayConversion - missing type"); |
| |
| if (Ty->isFunctionType()) { |
| if (auto *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParenCasts())) |
| if (auto *FD = dyn_cast<FunctionDecl>(DRE->getDecl())) |
| if (!checkAddressOfFunctionIsAvailable(FD, Diagnose, E->getExprLoc())) |
| return ExprError(); |
| |
| E = ImpCastExprToType(E, Context.getPointerType(Ty), |
| CK_FunctionToPointerDecay).get(); |
| } else if (Ty->isArrayType()) { |
| // In C90 mode, arrays only promote to pointers if the array expression is |
| // an lvalue. The relevant legalese is C90 6.2.2.1p3: "an lvalue that has |
| // type 'array of type' is converted to an expression that has type 'pointer |
| // to type'...". In C99 this was changed to: C99 6.3.2.1p3: "an expression |
| // that has type 'array of type' ...". The relevant change is "an lvalue" |
| // (C90) to "an expression" (C99). |
| // |
| // C++ 4.2p1: |
| // An lvalue or rvalue of type "array of N T" or "array of unknown bound of |
| // T" can be converted to an rvalue of type "pointer to T". |
| // |
| if (getLangOpts().C99 || getLangOpts().CPlusPlus || E->isLValue()) |
| E = ImpCastExprToType(E, Context.getArrayDecayedType(Ty), |
| CK_ArrayToPointerDecay).get(); |
| } |
| return E; |
| } |
| |
| static void CheckForNullPointerDereference(Sema &S, Expr *E) { |
| // Check to see if we are dereferencing a null pointer. If so, |
| // and if not volatile-qualified, this is undefined behavior that the |
| // optimizer will delete, so warn about it. People sometimes try to use this |
| // to get a deterministic trap and are surprised by clang's behavior. This |
| // only handles the pattern "*null", which is a very syntactic check. |
| if (UnaryOperator *UO = dyn_cast<UnaryOperator>(E->IgnoreParenCasts())) |
| if (UO->getOpcode() == UO_Deref && |
| UO->getSubExpr()->IgnoreParenCasts()-> |
| isNullPointerConstant(S.Context, Expr::NPC_ValueDependentIsNotNull) && |
| !UO->getType().isVolatileQualified()) { |
| S.DiagRuntimeBehavior(UO->getOperatorLoc(), UO, |
| S.PDiag(diag::warn_indirection_through_null) |
| << UO->getSubExpr()->getSourceRange()); |
| S.DiagRuntimeBehavior(UO->getOperatorLoc(), UO, |
| S.PDiag(diag::note_indirection_through_null)); |
| } |
| } |
| |
| static void DiagnoseDirectIsaAccess(Sema &S, const ObjCIvarRefExpr *OIRE, |
| SourceLocation AssignLoc, |
| const Expr* RHS) { |
| const ObjCIvarDecl *IV = OIRE->getDecl(); |
| if (!IV) |
| return; |
| |
| DeclarationName MemberName = IV->getDeclName(); |
| IdentifierInfo *Member = MemberName.getAsIdentifierInfo(); |
| if (!Member || !Member->isStr("isa")) |
| return; |
| |
| const Expr *Base = OIRE->getBase(); |
| QualType BaseType = Base->getType(); |
| if (OIRE->isArrow()) |
| BaseType = BaseType->getPointeeType(); |
| if (const ObjCObjectType *OTy = BaseType->getAs<ObjCObjectType>()) |
| if (ObjCInterfaceDecl *IDecl = OTy->getInterface()) { |
| ObjCInterfaceDecl *ClassDeclared = nullptr; |
| ObjCIvarDecl *IV = IDecl->lookupInstanceVariable(Member, ClassDeclared); |
| if (!ClassDeclared->getSuperClass() |
| && (*ClassDeclared->ivar_begin()) == IV) { |
| if (RHS) { |
| NamedDecl *ObjectSetClass = |
| S.LookupSingleName(S.TUScope, |
| &S.Context.Idents.get("object_setClass"), |
| SourceLocation(), S.LookupOrdinaryName); |
| if (ObjectSetClass) { |
| SourceLocation RHSLocEnd = S.getLocForEndOfToken(RHS->getEndLoc()); |
| S.Diag(OIRE->getExprLoc(), diag::warn_objc_isa_assign) |
| << FixItHint::CreateInsertion(OIRE->getBeginLoc(), |
| "object_setClass(") |
| << FixItHint::CreateReplacement( |
| SourceRange(OIRE->getOpLoc(), AssignLoc), ",") |
| << FixItHint::CreateInsertion(RHSLocEnd, ")"); |
| } |
| else |
| S.Diag(OIRE->getLocation(), diag::warn_objc_isa_assign); |
| } else { |
| NamedDecl *ObjectGetClass = |
| S.LookupSingleName(S.TUScope, |
| &S.Context.Idents.get("object_getClass"), |
| SourceLocation(), S.LookupOrdinaryName); |
| if (ObjectGetClass) |
| S.Diag(OIRE->getExprLoc(), diag::warn_objc_isa_use) |
| << FixItHint::CreateInsertion(OIRE->getBeginLoc(), |
| "object_getClass(") |
| << FixItHint::CreateReplacement( |
| SourceRange(OIRE->getOpLoc(), OIRE->getEndLoc()), ")"); |
| else |
| S.Diag(OIRE->getLocation(), diag::warn_objc_isa_use); |
| } |
| S.Diag(IV->getLocation(), diag::note_ivar_decl); |
| } |
| } |
| } |
| |
| ExprResult Sema::DefaultLvalueConversion(Expr *E) { |
| // Handle any placeholder expressions which made it here. |
| if (E->getType()->isPlaceholderType()) { |
| ExprResult result = CheckPlaceholderExpr(E); |
| if (result.isInvalid()) return ExprError(); |
| E = result.get(); |
| } |
| |
| // C++ [conv.lval]p1: |
| // A glvalue of a non-function, non-array type T can be |
| // converted to a prvalue. |
| if (!E->isGLValue()) return E; |
| |
| QualType T = E->getType(); |
| assert(!T.isNull() && "r-value conversion on typeless expression?"); |
| |
| // We don't want to throw lvalue-to-rvalue casts on top of |
| // expressions of certain types in C++. |
| if (getLangOpts().CPlusPlus && |
| (E->getType() == Context.OverloadTy || |
| T->isDependentType() || |
| T->isRecordType())) |
| return E; |
| |
| // The C standard is actually really unclear on this point, and |
| // DR106 tells us what the result should be but not why. It's |
| // generally best to say that void types just doesn't undergo |
| // lvalue-to-rvalue at all. Note that expressions of unqualified |
| // 'void' type are never l-values, but qualified void can be. |
| if (T->isVoidType()) |
| return E; |
| |
| // OpenCL usually rejects direct accesses to values of 'half' type. |
| if (getLangOpts().OpenCL && !getOpenCLOptions().isEnabled("cl_khr_fp16") && |
| T->isHalfType()) { |
| Diag(E->getExprLoc(), diag::err_opencl_half_load_store) |
| << 0 << T; |
| return ExprError(); |
| } |
| |
| CheckForNullPointerDereference(*this, E); |
| if (const ObjCIsaExpr *OISA = dyn_cast<ObjCIsaExpr>(E->IgnoreParenCasts())) { |
| NamedDecl *ObjectGetClass = LookupSingleName(TUScope, |
| &Context.Idents.get("object_getClass"), |
| SourceLocation(), LookupOrdinaryName); |
| if (ObjectGetClass) |
| Diag(E->getExprLoc(), diag::warn_objc_isa_use) |
| << FixItHint::CreateInsertion(OISA->getBeginLoc(), "object_getClass(") |
| << FixItHint::CreateReplacement( |
| SourceRange(OISA->getOpLoc(), OISA->getIsaMemberLoc()), ")"); |
| else |
| Diag(E->getExprLoc(), diag::warn_objc_isa_use); |
| } |
| else if (const ObjCIvarRefExpr *OIRE = |
| dyn_cast<ObjCIvarRefExpr>(E->IgnoreParenCasts())) |
| DiagnoseDirectIsaAccess(*this, OIRE, SourceLocation(), /* Expr*/nullptr); |
| |
| // C++ [conv.lval]p1: |
| // [...] If T is a non-class type, the type of the prvalue is the |
| // cv-unqualified version of T. Otherwise, the type of the |
| // rvalue is T. |
| // |
| // C99 6.3.2.1p2: |
| // If the lvalue has qualified type, the value has the unqualified |
| // version of the type of the lvalue; otherwise, the value has the |
| // type of the lvalue. |
| if (T.hasQualifiers()) |
| T = T.getUnqualifiedType(); |
| |
| // Under the MS ABI, lock down the inheritance model now. |
| if (T->isMemberPointerType() && |
| Context.getTargetInfo().getCXXABI().isMicrosoft()) |
| (void)isCompleteType(E->getExprLoc(), T); |
| |
| ExprResult Res = CheckLValueToRValueConversionOperand(E); |
| if (Res.isInvalid()) |
| return Res; |
| E = Res.get(); |
| |
| // Loading a __weak object implicitly retains the value, so we need a cleanup to |
| // balance that. |
| if (E->getType().getObjCLifetime() == Qualifiers::OCL_Weak) |
| Cleanup.setExprNeedsCleanups(true); |
| |
| // C++ [conv.lval]p3: |
| // If T is cv std::nullptr_t, the result is a null pointer constant. |
| CastKind CK = T->isNullPtrType() ? CK_NullToPointer : CK_LValueToRValue; |
| Res = ImplicitCastExpr::Create(Context, T, CK, E, nullptr, VK_RValue); |
| |
| // C11 6.3.2.1p2: |
| // ... if the lvalue has atomic type, the value has the non-atomic version |
| // of the type of the lvalue ... |
| if (const AtomicType *Atomic = T->getAs<AtomicType>()) { |
| T = Atomic->getValueType().getUnqualifiedType(); |
| Res = ImplicitCastExpr::Create(Context, T, CK_AtomicToNonAtomic, Res.get(), |
| nullptr, VK_RValue); |
| } |
| |
| return Res; |
| } |
| |
| ExprResult Sema::DefaultFunctionArrayLvalueConversion(Expr *E, bool Diagnose) { |
| ExprResult Res = DefaultFunctionArrayConversion(E, Diagnose); |
| if (Res.isInvalid()) |
| return ExprError(); |
| Res = DefaultLvalueConversion(Res.get()); |
| if (Res.isInvalid()) |
| return ExprError(); |
| return Res; |
| } |
| |
| /// CallExprUnaryConversions - a special case of an unary conversion |
| /// performed on a function designator of a call expression. |
| ExprResult Sema::CallExprUnaryConversions(Expr *E) { |
| QualType Ty = E->getType(); |
| ExprResult Res = E; |
| // Only do implicit cast for a function type, but not for a pointer |
| // to function type. |
| if (Ty->isFunctionType()) { |
| Res = ImpCastExprToType(E, Context.getPointerType(Ty), |
| CK_FunctionToPointerDecay).get(); |
| if (Res.isInvalid()) |
| return ExprError(); |
| } |
| Res = DefaultLvalueConversion(Res.get()); |
| if (Res.isInvalid()) |
| return ExprError(); |
| return Res.get(); |
| } |
| |
| /// UsualUnaryConversions - Performs various conversions that are common to most |
| /// operators (C99 6.3). The conversions of array and function types are |
| /// sometimes suppressed. For example, the array->pointer conversion doesn't |
| /// apply if the array is an argument to the sizeof or address (&) operators. |
| /// In these instances, this routine should *not* be called. |
| ExprResult Sema::UsualUnaryConversions(Expr *E) { |
| // First, convert to an r-value. |
| ExprResult Res = DefaultFunctionArrayLvalueConversion(E); |
| if (Res.isInvalid()) |
| return ExprError(); |
| E = Res.get(); |
| |
| QualType Ty = E->getType(); |
| assert(!Ty.isNull() && "UsualUnaryConversions - missing type"); |
| |
| // Half FP have to be promoted to float unless it is natively supported |
| if (Ty->isHalfType() && !getLangOpts().NativeHalfType) |
| return ImpCastExprToType(Res.get(), Context.FloatTy, CK_FloatingCast); |
| |
| // Try to perform integral promotions if the object has a theoretically |
| // promotable type. |
| if (Ty->isIntegralOrUnscopedEnumerationType()) { |
| // C99 6.3.1.1p2: |
| // |
| // The following may be used in an expression wherever an int or |
| // unsigned int may be used: |
| // - an object or expression with an integer type whose integer |
| // conversion rank is less than or equal to the rank of int |
| // and unsigned int. |
| // - A bit-field of type _Bool, int, signed int, or unsigned int. |
| // |
| // If an int can represent all values of the original type, the |
| // value is converted to an int; otherwise, it is converted to an |
| // unsigned int. These are called the integer promotions. All |
| // other types are unchanged by the integer promotions. |
| |
| QualType PTy = Context.isPromotableBitField(E); |
| if (!PTy.isNull()) { |
| E = ImpCastExprToType(E, PTy, CK_IntegralCast).get(); |
| return E; |
| } |
| if (Ty->isPromotableIntegerType()) { |
| QualType PT = Context.getPromotedIntegerType(Ty); |
| E = ImpCastExprToType(E, PT, CK_IntegralCast).get(); |
| return E; |
| } |
| } |
| return E; |
| } |
| |
| /// DefaultArgumentPromotion (C99 6.5.2.2p6). Used for function calls that |
| /// do not have a prototype. Arguments that have type float or __fp16 |
| /// are promoted to double. All other argument types are converted by |
| /// UsualUnaryConversions(). |
| ExprResult Sema::DefaultArgumentPromotion(Expr *E) { |
| QualType Ty = E->getType(); |
| assert(!Ty.isNull() && "DefaultArgumentPromotion - missing type"); |
| |
| ExprResult Res = UsualUnaryConversions(E); |
| if (Res.isInvalid()) |
| return ExprError(); |
| E = Res.get(); |
| |
| // If this is a 'float' or '__fp16' (CVR qualified or typedef) |
| // promote to double. |
| // Note that default argument promotion applies only to float (and |
| // half/fp16); it does not apply to _Float16. |
| const BuiltinType *BTy = Ty->getAs<BuiltinType>(); |
| if (BTy && (BTy->getKind() == BuiltinType::Half || |
| BTy->getKind() == BuiltinType::Float)) { |
| if (getLangOpts().OpenCL && |
| !getOpenCLOptions().isEnabled("cl_khr_fp64")) { |
| if (BTy->getKind() == BuiltinType::Half) { |
| E = ImpCastExprToType(E, Context.FloatTy, CK_FloatingCast).get(); |
| } |
| } else { |
| E = ImpCastExprToType(E, Context.DoubleTy, CK_FloatingCast).get(); |
| } |
| } |
| |
| // C++ performs lvalue-to-rvalue conversion as a default argument |
| // promotion, even on class types, but note: |
| // C++11 [conv.lval]p2: |
| // When an lvalue-to-rvalue conversion occurs in an unevaluated |
| // operand or a subexpression thereof the value contained in the |
| // referenced object is not accessed. Otherwise, if the glvalue |
| // has a class type, the conversion copy-initializes a temporary |
| // of type T from the glvalue and the result of the conversion |
| // is a prvalue for the temporary. |
| // FIXME: add some way to gate this entire thing for correctness in |
| // potentially potentially evaluated contexts. |
| if (getLangOpts().CPlusPlus && E->isGLValue() && !isUnevaluatedContext()) { |
| ExprResult Temp = PerformCopyInitialization( |
| InitializedEntity::InitializeTemporary(E->getType()), |
| E->getExprLoc(), E); |
| if (Temp.isInvalid()) |
| return ExprError(); |
| E = Temp.get(); |
| } |
| |
| return E; |
| } |
| |
| /// Determine the degree of POD-ness for an expression. |
| /// Incomplete types are considered POD, since this check can be performed |
| /// when we're in an unevaluated context. |
| Sema::VarArgKind Sema::isValidVarArgType(const QualType &Ty) { |
| if (Ty->isIncompleteType()) { |
| // C++11 [expr.call]p7: |
| // After these conversions, if the argument does not have arithmetic, |
| // enumeration, pointer, pointer to member, or class type, the program |
| // is ill-formed. |
| // |
| // Since we've already performed array-to-pointer and function-to-pointer |
| // decay, the only such type in C++ is cv void. This also handles |
| // initializer lists as variadic arguments. |
| if (Ty->isVoidType()) |
| return VAK_Invalid; |
| |
| if (Ty->isObjCObjectType()) |
| return VAK_Invalid; |
| return VAK_Valid; |
| } |
| |
| if (Ty.isDestructedType() == QualType::DK_nontrivial_c_struct) |
| return VAK_Invalid; |
| |
| if (Ty.isCXX98PODType(Context)) |
| return VAK_Valid; |
| |
| // C++11 [expr.call]p7: |
| // Passing a potentially-evaluated argument of class type (Clause 9) |
| // having a non-trivial copy constructor, a non-trivial move constructor, |
| // or a non-trivial destructor, with no corresponding parameter, |
| // is conditionally-supported with implementation-defined semantics. |
| if (getLangOpts().CPlusPlus11 && !Ty->isDependentType()) |
| if (CXXRecordDecl *Record = Ty->getAsCXXRecordDecl()) |
| if (!Record->hasNonTrivialCopyConstructor() && |
| !Record->hasNonTrivialMoveConstructor() && |
| !Record->hasNonTrivialDestructor()) |
| return VAK_ValidInCXX11; |
| |
| if (getLangOpts().ObjCAutoRefCount && Ty->isObjCLifetimeType()) |
| return VAK_Valid; |
| |
| if (Ty->isObjCObjectType()) |
| return VAK_Invalid; |
| |
| if (getLangOpts().MSVCCompat) |
| return VAK_MSVCUndefined; |
| |
| // FIXME: In C++11, these cases are conditionally-supported, meaning we're |
| // permitted to reject them. We should consider doing so. |
| return VAK_Undefined; |
| } |
| |
| void Sema::checkVariadicArgument(const Expr *E, VariadicCallType CT) { |
| // Don't allow one to pass an Objective-C interface to a vararg. |
| const QualType &Ty = E->getType(); |
| VarArgKind VAK = isValidVarArgType(Ty); |
| |
| // Complain about passing non-POD types through varargs. |
| switch (VAK) { |
| case VAK_ValidInCXX11: |
| DiagRuntimeBehavior( |
| E->getBeginLoc(), nullptr, |
| PDiag(diag::warn_cxx98_compat_pass_non_pod_arg_to_vararg) << Ty << CT); |
| LLVM_FALLTHROUGH; |
| case VAK_Valid: |
| if (Ty->isRecordType()) { |
| // This is unlikely to be what the user intended. If the class has a |
| // 'c_str' member function, the user probably meant to call that. |
| DiagRuntimeBehavior(E->getBeginLoc(), nullptr, |
| PDiag(diag::warn_pass_class_arg_to_vararg) |
| << Ty << CT << hasCStrMethod(E) << ".c_str()"); |
| } |
| break; |
| |
| case VAK_Undefined: |
| case VAK_MSVCUndefined: |
| DiagRuntimeBehavior(E->getBeginLoc(), nullptr, |
| PDiag(diag::warn_cannot_pass_non_pod_arg_to_vararg) |
| << getLangOpts().CPlusPlus11 << Ty << CT); |
| break; |
| |
| case VAK_Invalid: |
| if (Ty.isDestructedType() == QualType::DK_nontrivial_c_struct) |
| Diag(E->getBeginLoc(), |
| diag::err_cannot_pass_non_trivial_c_struct_to_vararg) |
| << Ty << CT; |
| else if (Ty->isObjCObjectType()) |
| DiagRuntimeBehavior(E->getBeginLoc(), nullptr, |
| PDiag(diag::err_cannot_pass_objc_interface_to_vararg) |
| << Ty << CT); |
| else |
| Diag(E->getBeginLoc(), diag::err_cannot_pass_to_vararg) |
| << isa<InitListExpr>(E) << Ty << CT; |
| break; |
| } |
| } |
| |
| /// DefaultVariadicArgumentPromotion - Like DefaultArgumentPromotion, but |
| /// will create a trap if the resulting type is not a POD type. |
| ExprResult Sema::DefaultVariadicArgumentPromotion(Expr *E, VariadicCallType CT, |
| FunctionDecl *FDecl) { |
| if (const BuiltinType *PlaceholderTy = E->getType()->getAsPlaceholderType()) { |
| // Strip the unbridged-cast placeholder expression off, if applicable. |
| if (PlaceholderTy->getKind() == BuiltinType::ARCUnbridgedCast && |
| (CT == VariadicMethod || |
| (FDecl && FDecl->hasAttr<CFAuditedTransferAttr>()))) { |
| E = stripARCUnbridgedCast(E); |
| |
| // Otherwise, do normal placeholder checking. |
| } else { |
| ExprResult ExprRes = CheckPlaceholderExpr(E); |
| if (ExprRes.isInvalid()) |
| return ExprError(); |
| E = ExprRes.get(); |
| } |
| } |
| |
| ExprResult ExprRes = DefaultArgumentPromotion(E); |
| if (ExprRes.isInvalid()) |
| return ExprError(); |
| E = ExprRes.get(); |
| |
| // Diagnostics regarding non-POD argument types are |
| // emitted along with format string checking in Sema::CheckFunctionCall(). |
| if (isValidVarArgType(E->getType()) == VAK_Undefined) { |
| // Turn this into a trap. |
| CXXScopeSpec SS; |
| SourceLocation TemplateKWLoc; |
| UnqualifiedId Name; |
| Name.setIdentifier(PP.getIdentifierInfo("__builtin_trap"), |
| E->getBeginLoc()); |
| ExprResult TrapFn = ActOnIdExpression(TUScope, SS, TemplateKWLoc, Name, |
| /*HasTrailingLParen=*/true, |
| /*IsAddressOfOperand=*/false); |
| if (TrapFn.isInvalid()) |
| return ExprError(); |
| |
| ExprResult Call = BuildCallExpr(TUScope, TrapFn.get(), E->getBeginLoc(), |
| None, E->getEndLoc()); |
| if (Call.isInvalid()) |
| return ExprError(); |
| |
| ExprResult Comma = |
| ActOnBinOp(TUScope, E->getBeginLoc(), tok::comma, Call.get(), E); |
| if (Comma.isInvalid()) |
| return ExprError(); |
| return Comma.get(); |
| } |
| |
| if (!getLangOpts().CPlusPlus && |
| RequireCompleteType(E->getExprLoc(), E->getType(), |
| diag::err_call_incomplete_argument)) |
| return ExprError(); |
| |
| return E; |
| } |
| |
| /// Converts an integer to complex float type. Helper function of |
| /// UsualArithmeticConversions() |
| /// |
| /// \return false if the integer expression is an integer type and is |
| /// successfully converted to the complex type. |
| static bool handleIntegerToComplexFloatConversion(Sema &S, ExprResult &IntExpr, |
| ExprResult &ComplexExpr, |
| QualType IntTy, |
| QualType ComplexTy, |
| bool SkipCast) { |
| if (IntTy->isComplexType() || IntTy->isRealFloatingType()) return true; |
| if (SkipCast) return false; |
| if (IntTy->isIntegerType()) { |
| QualType fpTy = cast<ComplexType>(ComplexTy)->getElementType(); |
| IntExpr = S.ImpCastExprToType(IntExpr.get(), fpTy, CK_IntegralToFloating); |
| IntExpr = S.ImpCastExprToType(IntExpr.get(), ComplexTy, |
| CK_FloatingRealToComplex); |
| } else { |
| assert(IntTy->isComplexIntegerType()); |
| IntExpr = S.ImpCastExprToType(IntExpr.get(), ComplexTy, |
| CK_IntegralComplexToFloatingComplex); |
| } |
| return false; |
| } |
| |
| /// Handle arithmetic conversion with complex types. Helper function of |
| /// UsualArithmeticConversions() |
| static QualType handleComplexFloatConversion(Sema &S, ExprResult &LHS, |
| ExprResult &RHS, QualType LHSType, |
| QualType RHSType, |
| bool IsCompAssign) { |
| // if we have an integer operand, the result is the complex type. |
| if (!handleIntegerToComplexFloatConversion(S, RHS, LHS, RHSType, LHSType, |
| /*skipCast*/false)) |
| return LHSType; |
| if (!handleIntegerToComplexFloatConversion(S, LHS, RHS, LHSType, RHSType, |
| /*skipCast*/IsCompAssign)) |
| return RHSType; |
| |
| // This handles complex/complex, complex/float, or float/complex. |
| // When both operands are complex, the shorter operand is converted to the |
| // type of the longer, and that is the type of the result. This corresponds |
| // to what is done when combining two real floating-point operands. |
| // The fun begins when size promotion occur across type domains. |
| // From H&S 6.3.4: When one operand is complex and the other is a real |
| // floating-point type, the less precise type is converted, within it's |
| // real or complex domain, to the precision of the other type. For example, |
| // when combining a "long double" with a "double _Complex", the |
| // "double _Complex" is promoted to "long double _Complex". |
| |
| // Compute the rank of the two types, regardless of whether they are complex. |
| int Order = S.Context.getFloatingTypeOrder(LHSType, RHSType); |
| |
| auto *LHSComplexType = dyn_cast<ComplexType>(LHSType); |
| auto *RHSComplexType = dyn_cast<ComplexType>(RHSType); |
| QualType LHSElementType = |
| LHSComplexType ? LHSComplexType->getElementType() : LHSType; |
| QualType RHSElementType = |
| RHSComplexType ? RHSComplexType->getElementType() : RHSType; |
| |
| QualType ResultType = S.Context.getComplexType(LHSElementType); |
| if (Order < 0) { |
| // Promote the precision of the LHS if not an assignment. |
| ResultType = S.Context.getComplexType(RHSElementType); |
| if (!IsCompAssign) { |
| if (LHSComplexType) |
| LHS = |
| S.ImpCastExprToType(LHS.get(), ResultType, CK_FloatingComplexCast); |
| else |
| LHS = S.ImpCastExprToType(LHS.get(), RHSElementType, CK_FloatingCast); |
| } |
| } else if (Order > 0) { |
| // Promote the precision of the RHS. |
| if (RHSComplexType) |
| RHS = S.ImpCastExprToType(RHS.get(), ResultType, CK_FloatingComplexCast); |
| else |
| RHS = S.ImpCastExprToType(RHS.get(), LHSElementType, CK_FloatingCast); |
| } |
| return ResultType; |
| } |
| |
| /// Handle arithmetic conversion from integer to float. Helper function |
| /// of UsualArithmeticConversions() |
| static QualType handleIntToFloatConversion(Sema &S, ExprResult &FloatExpr, |
| ExprResult &IntExpr, |
| QualType FloatTy, QualType IntTy, |
| bool ConvertFloat, bool ConvertInt) { |
| if (IntTy->isIntegerType()) { |
| if (ConvertInt) |
| // Convert intExpr to the lhs floating point type. |
| IntExpr = S.ImpCastExprToType(IntExpr.get(), FloatTy, |
| CK_IntegralToFloating); |
| return FloatTy; |
| } |
| |
| // Convert both sides to the appropriate complex float. |
| assert(IntTy->isComplexIntegerType()); |
| QualType result = S.Context.getComplexType(FloatTy); |
| |
| // _Complex int -> _Complex float |
| if (ConvertInt) |
| IntExpr = S.ImpCastExprToType(IntExpr.get(), result, |
| CK_IntegralComplexToFloatingComplex); |
| |
| // float -> _Complex float |
| if (ConvertFloat) |
| FloatExpr = S.ImpCastExprToType(FloatExpr.get(), result, |
| CK_FloatingRealToComplex); |
| |
| return result; |
| } |
| |
| /// Handle arithmethic conversion with floating point types. Helper |
| /// function of UsualArithmeticConversions() |
| static QualType handleFloatConversion(Sema &S, ExprResult &LHS, |
| ExprResult &RHS, QualType LHSType, |
| QualType RHSType, bool IsCompAssign) { |
| bool LHSFloat = LHSType->isRealFloatingType(); |
| bool RHSFloat = RHSType->isRealFloatingType(); |
| |
| // If we have two real floating types, convert the smaller operand |
| // to the bigger result. |
| if (LHSFloat && RHSFloat) { |
| int order = S.Context.getFloatingTypeOrder(LHSType, RHSType); |
| if (order > 0) { |
| RHS = S.ImpCastExprToType(RHS.get(), LHSType, CK_FloatingCast); |
| return LHSType; |
| } |
| |
| assert(order < 0 && "illegal float comparison"); |
| if (!IsCompAssign) |
| LHS = S.ImpCastExprToType(LHS.get(), RHSType, CK_FloatingCast); |
| return RHSType; |
| } |
| |
| if (LHSFloat) { |
| // Half FP has to be promoted to float unless it is natively supported |
| if (LHSType->isHalfType() && !S.getLangOpts().NativeHalfType) |
| LHSType = S.Context.FloatTy; |
| |
| return handleIntToFloatConversion(S, LHS, RHS, LHSType, RHSType, |
| /*ConvertFloat=*/!IsCompAssign, |
| /*ConvertInt=*/ true); |
| } |
| assert(RHSFloat); |
| return handleIntToFloatConversion(S, RHS, LHS, RHSType, LHSType, |
| /*convertInt=*/ true, |
| /*convertFloat=*/!IsCompAssign); |
| } |
| |
| /// Diagnose attempts to convert between __float128 and long double if |
| /// there is no support for such conversion. Helper function of |
| /// UsualArithmeticConversions(). |
| static bool unsupportedTypeConversion(const Sema &S, QualType LHSType, |
| QualType RHSType) { |
| /* No issue converting if at least one of the types is not a floating point |
| type or the two types have the same rank. |
| */ |
| if (!LHSType->isFloatingType() || !RHSType->isFloatingType() || |
| S.Context.getFloatingTypeOrder(LHSType, RHSType) == 0) |
| return false; |
| |
| assert(LHSType->isFloatingType() && RHSType->isFloatingType() && |
| "The remaining types must be floating point types."); |
| |
| auto *LHSComplex = LHSType->getAs<ComplexType>(); |
| auto *RHSComplex = RHSType->getAs<ComplexType>(); |
| |
| QualType LHSElemType = LHSComplex ? |
| LHSComplex->getElementType() : LHSType; |
| QualType RHSElemType = RHSComplex ? |
| RHSComplex->getElementType() : RHSType; |
| |
| // No issue if the two types have the same representation |
| if (&S.Context.getFloatTypeSemantics(LHSElemType) == |
| &S.Context.getFloatTypeSemantics(RHSElemType)) |
| return false; |
| |
| bool Float128AndLongDouble = (LHSElemType == S.Context.Float128Ty && |
| RHSElemType == S.Context.LongDoubleTy); |
| Float128AndLongDouble |= (LHSElemType == S.Context.LongDoubleTy && |
| RHSElemType == S.Context.Float128Ty); |
| |
| // We've handled the situation where __float128 and long double have the same |
| // representation. We allow all conversions for all possible long double types |
| // except PPC's double double. |
| return Float128AndLongDouble && |
| (&S.Context.getFloatTypeSemantics(S.Context.LongDoubleTy) == |
| &llvm::APFloat::PPCDoubleDouble()); |
| } |
| |
| typedef ExprResult PerformCastFn(Sema &S, Expr *operand, QualType toType); |
| |
| namespace { |
| /// These helper callbacks are placed in an anonymous namespace to |
| /// permit their use as function template parameters. |
| ExprResult doIntegralCast(Sema &S, Expr *op, QualType toType) { |
| return S.ImpCastExprToType(op, toType, CK_IntegralCast); |
| } |
| |
| ExprResult doComplexIntegralCast(Sema &S, Expr *op, QualType toType) { |
| return S.ImpCastExprToType(op, S.Context.getComplexType(toType), |
| CK_IntegralComplexCast); |
| } |
| } |
| |
| /// Handle integer arithmetic conversions. Helper function of |
| /// UsualArithmeticConversions() |
| template <PerformCastFn doLHSCast, PerformCastFn doRHSCast> |
| static QualType handleIntegerConversion(Sema &S, ExprResult &LHS, |
| ExprResult &RHS, QualType LHSType, |
| QualType RHSType, bool IsCompAssign) { |
| // The rules for this case are in C99 6.3.1.8 |
| int order = S.Context.getIntegerTypeOrder(LHSType, RHSType); |
| bool LHSSigned = LHSType->hasSignedIntegerRepresentation(); |
| bool RHSSigned = RHSType->hasSignedIntegerRepresentation(); |
| if (LHSSigned == RHSSigned) { |
| // Same signedness; use the higher-ranked type |
| if (order >= 0) { |
| RHS = (*doRHSCast)(S, RHS.get(), LHSType); |
| return LHSType; |
| } else if (!IsCompAssign) |
| LHS = (*doLHSCast)(S, LHS.get(), RHSType); |
| return RHSType; |
| } else if (order != (LHSSigned ? 1 : -1)) { |
| // The unsigned type has greater than or equal rank to the |
| // signed type, so use the unsigned type |
| if (RHSSigned) { |
| RHS = (*doRHSCast)(S, RHS.get(), LHSType); |
| return LHSType; |
| } else if (!IsCompAssign) |
| LHS = (*doLHSCast)(S, LHS.get(), RHSType); |
| return RHSType; |
| } else if (S.Context.getIntWidth(LHSType) != S.Context.getIntWidth(RHSType)) { |
| // The two types are different widths; if we are here, that |
| // means the signed type is larger than the unsigned type, so |
| // use the signed type. |
| if (LHSSigned) { |
| RHS = (*doRHSCast)(S, RHS.get(), LHSType); |
| return LHSType; |
| } else if (!IsCompAssign) |
| LHS = (*doLHSCast)(S, LHS.get(), RHSType); |
| return RHSType; |
| } else { |
| // The signed type is higher-ranked than the unsigned type, |
| // but isn't actually any bigger (like unsigned int and long |
| // on most 32-bit systems). Use the unsigned type corresponding |
| // to the signed type. |
| QualType result = |
| S.Context.getCorrespondingUnsignedType(LHSSigned ? LHSType : RHSType); |
| RHS = (*doRHSCast)(S, RHS.get(), result); |
| if (!IsCompAssign) |
| LHS = (*doLHSCast)(S, LHS.get(), result); |
| return result; |
| } |
| } |
| |
| /// Handle conversions with GCC complex int extension. Helper function |
| /// of UsualArithmeticConversions() |
| static QualType handleComplexIntConversion(Sema &S, ExprResult &LHS, |
| ExprResult &RHS, QualType LHSType, |
| QualType RHSType, |
| bool IsCompAssign) { |
| const ComplexType *LHSComplexInt = LHSType->getAsComplexIntegerType(); |
| const ComplexType *RHSComplexInt = RHSType->getAsComplexIntegerType(); |
| |
| if (LHSComplexInt && RHSComplexInt) { |
| QualType LHSEltType = LHSComplexInt->getElementType(); |
| QualType RHSEltType = RHSComplexInt->getElementType(); |
| QualType ScalarType = |
| handleIntegerConversion<doComplexIntegralCast, doComplexIntegralCast> |
| (S, LHS, RHS, LHSEltType, RHSEltType, IsCompAssign); |
| |
| return S.Context.getComplexType(ScalarType); |
| } |
| |
| if (LHSComplexInt) { |
| QualType LHSEltType = LHSComplexInt->getElementType(); |
| QualType ScalarType = |
| handleIntegerConversion<doComplexIntegralCast, doIntegralCast> |
| (S, LHS, RHS, LHSEltType, RHSType, IsCompAssign); |
| QualType ComplexType = S.Context.getComplexType(ScalarType); |
| RHS = S.ImpCastExprToType(RHS.get(), ComplexType, |
| CK_IntegralRealToComplex); |
| |
| return ComplexType; |
| } |
| |
| assert(RHSComplexInt); |
| |
| QualType RHSEltType = RHSComplexInt->getElementType(); |
| QualType ScalarType = |
| handleIntegerConversion<doIntegralCast, doComplexIntegralCast> |
| (S, LHS, RHS, LHSType, RHSEltType, IsCompAssign); |
| QualType ComplexType = S.Context.getComplexType(ScalarType); |
| |
| if (!IsCompAssign) |
| LHS = S.ImpCastExprToType(LHS.get(), ComplexType, |
| CK_IntegralRealToComplex); |
| return ComplexType; |
| } |
| |
| /// Return the rank of a given fixed point or integer type. The value itself |
| /// doesn't matter, but the values must be increasing with proper increasing |
| /// rank as described in N1169 4.1.1. |
| static unsigned GetFixedPointRank(QualType Ty) { |
| const auto *BTy = Ty->getAs<BuiltinType>(); |
| assert(BTy && "Expected a builtin type."); |
| |
| switch (BTy->getKind()) { |
| case BuiltinType::ShortFract: |
| case BuiltinType::UShortFract: |
| case BuiltinType::SatShortFract: |
| case BuiltinType::SatUShortFract: |
| return 1; |
| case BuiltinType::Fract: |
| case BuiltinType::UFract: |
| case BuiltinType::SatFract: |
| case BuiltinType::SatUFract: |
| return 2; |
| case BuiltinType::LongFract: |
| case BuiltinType::ULongFract: |
| case BuiltinType::SatLongFract: |
| case BuiltinType::SatULongFract: |
| return 3; |
| case BuiltinType::ShortAccum: |
| case BuiltinType::UShortAccum: |
| case BuiltinType::SatShortAccum: |
| case BuiltinType::SatUShortAccum: |
| return 4; |
| case BuiltinType::Accum: |
| case BuiltinType::UAccum: |
| case BuiltinType::SatAccum: |
| case BuiltinType::SatUAccum: |
| return 5; |
| case BuiltinType::LongAccum: |
| case BuiltinType::ULongAccum: |
| case BuiltinType::SatLongAccum: |
| case BuiltinType::SatULongAccum: |
| return 6; |
| default: |
| if (BTy->isInteger()) |
| return 0; |
| llvm_unreachable("Unexpected fixed point or integer type"); |
| } |
| } |
| |
| /// handleFixedPointConversion - Fixed point operations between fixed |
| /// point types and integers or other fixed point types do not fall under |
| /// usual arithmetic conversion since these conversions could result in loss |
| /// of precsision (N1169 4.1.4). These operations should be calculated with |
| /// the full precision of their result type (N1169 4.1.6.2.1). |
| static QualType handleFixedPointConversion(Sema &S, QualType LHSTy, |
| QualType RHSTy) { |
| assert((LHSTy->isFixedPointType() || RHSTy->isFixedPointType()) && |
| "Expected at least one of the operands to be a fixed point type"); |
| assert((LHSTy->isFixedPointOrIntegerType() || |
| RHSTy->isFixedPointOrIntegerType()) && |
| "Special fixed point arithmetic operation conversions are only " |
| "applied to ints or other fixed point types"); |
| |
| // If one operand has signed fixed-point type and the other operand has |
| // unsigned fixed-point type, then the unsigned fixed-point operand is |
| // converted to its corresponding signed fixed-point type and the resulting |
| // type is the type of the converted operand. |
| if (RHSTy->isSignedFixedPointType() && LHSTy->isUnsignedFixedPointType()) |
| LHSTy = S.Context.getCorrespondingSignedFixedPointType(LHSTy); |
| else if (RHSTy->isUnsignedFixedPointType() && LHSTy->isSignedFixedPointType()) |
| RHSTy = S.Context.getCorrespondingSignedFixedPointType(RHSTy); |
| |
| // The result type is the type with the highest rank, whereby a fixed-point |
| // conversion rank is always greater than an integer conversion rank; if the |
| // type of either of the operands is a saturating fixedpoint type, the result |
| // type shall be the saturating fixed-point type corresponding to the type |
| // with the highest rank; the resulting value is converted (taking into |
| // account rounding and overflow) to the precision of the resulting type. |
| // Same ranks between signed and unsigned types are resolved earlier, so both |
| // types are either signed or both unsigned at this point. |
| unsigned LHSTyRank = GetFixedPointRank(LHSTy); |
| unsigned RHSTyRank = GetFixedPointRank(RHSTy); |
| |
| QualType ResultTy = LHSTyRank > RHSTyRank ? LHSTy : RHSTy; |
| |
| if (LHSTy->isSaturatedFixedPointType() || RHSTy->isSaturatedFixedPointType()) |
| ResultTy = S.Context.getCorrespondingSaturatedType(ResultTy); |
| |
| return ResultTy; |
| } |
| |
| /// UsualArithmeticConversions - Performs various conversions that are common to |
| /// binary operators (C99 6.3.1.8). If both operands aren't arithmetic, this |
| /// routine returns the first non-arithmetic type found. The client is |
| /// responsible for emitting appropriate error diagnostics. |
| QualType Sema::UsualArithmeticConversions(ExprResult &LHS, ExprResult &RHS, |
| bool IsCompAssign) { |
| if (!IsCompAssign) { |
| LHS = UsualUnaryConversions(LHS.get()); |
| if (LHS.isInvalid()) |
| return QualType(); |
| } |
| |
| RHS = UsualUnaryConversions(RHS.get()); |
| if (RHS.isInvalid()) |
| return QualType(); |
| |
| // For conversion purposes, we ignore any qualifiers. |
| // For example, "const float" and "float" are equivalent. |
| QualType LHSType = |
| Context.getCanonicalType(LHS.get()->getType()).getUnqualifiedType(); |
| QualType RHSType = |
| Context.getCanonicalType(RHS.get()->getType()).getUnqualifiedType(); |
| |
| // For conversion purposes, we ignore any atomic qualifier on the LHS. |
| if (const AtomicType *AtomicLHS = LHSType->getAs<AtomicType>()) |
| LHSType = AtomicLHS->getValueType(); |
| |
| // If both types are identical, no conversion is needed. |
| if (LHSType == RHSType) |
| return LHSType; |
| |
| // If either side is a non-arithmetic type (e.g. a pointer), we are done. |
| // The caller can deal with this (e.g. pointer + int). |
| if (!LHSType->isArithmeticType() || !RHSType->isArithmeticType()) |
| return QualType(); |
| |
| // Apply unary and bitfield promotions to the LHS's type. |
| QualType LHSUnpromotedType = LHSType; |
| if (LHSType->isPromotableIntegerType()) |
| LHSType = Context.getPromotedIntegerType(LHSType); |
| QualType LHSBitfieldPromoteTy = Context.isPromotableBitField(LHS.get()); |
| if (!LHSBitfieldPromoteTy.isNull()) |
| LHSType = LHSBitfieldPromoteTy; |
| if (LHSType != LHSUnpromotedType && !IsCompAssign) |
| LHS = ImpCastExprToType(LHS.get(), LHSType, CK_IntegralCast); |
| |
| // If both types are identical, no conversion is needed. |
| if (LHSType == RHSType) |
| return LHSType; |
| |
| // At this point, we have two different arithmetic types. |
| |
| // Diagnose attempts to convert between __float128 and long double where |
| // such conversions currently can't be handled. |
| if (unsupportedTypeConversion(*this, LHSType, RHSType)) |
| return QualType(); |
| |
| // Handle complex types first (C99 6.3.1.8p1). |
| if (LHSType->isComplexType() || RHSType->isComplexType()) |
| return handleComplexFloatConversion(*this, LHS, RHS, LHSType, RHSType, |
| IsCompAssign); |
| |
| // Now handle "real" floating types (i.e. float, double, long double). |
| if (LHSType->isRealFloatingType() || RHSType->isRealFloatingType()) |
| return handleFloatConversion(*this, LHS, RHS, LHSType, RHSType, |
| IsCompAssign); |
| |
| // Handle GCC complex int extension. |
| if (LHSType->isComplexIntegerType() || RHSType->isComplexIntegerType()) |
| return handleComplexIntConversion(*this, LHS, RHS, LHSType, RHSType, |
| IsCompAssign); |
| |
| if (LHSType->isFixedPointType() || RHSType->isFixedPointType()) |
| return handleFixedPointConversion(*this, LHSType, RHSType); |
| |
| // Finally, we have two differing integer types. |
| return handleIntegerConversion<doIntegralCast, doIntegralCast> |
| (*this, LHS, RHS, LHSType, RHSType, IsCompAssign); |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // Semantic Analysis for various Expression Types |
| //===----------------------------------------------------------------------===// |
| |
| |
| ExprResult |
| Sema::ActOnGenericSelectionExpr(SourceLocation KeyLoc, |
| SourceLocation DefaultLoc, |
| SourceLocation RParenLoc, |
| Expr *ControllingExpr, |
| ArrayRef<ParsedType> ArgTypes, |
| ArrayRef<Expr *> ArgExprs) { |
| unsigned NumAssocs = ArgTypes.size(); |
| assert(NumAssocs == ArgExprs.size()); |
| |
| TypeSourceInfo **Types = new TypeSourceInfo*[NumAssocs]; |
| for (unsigned i = 0; i < NumAssocs; ++i) { |
| if (ArgTypes[i]) |
| (void) GetTypeFromParser(ArgTypes[i], &Types[i]); |
| else |
| Types[i] = nullptr; |
| } |
| |
| ExprResult ER = CreateGenericSelectionExpr(KeyLoc, DefaultLoc, RParenLoc, |
| ControllingExpr, |
| llvm::makeArrayRef(Types, NumAssocs), |
| ArgExprs); |
| delete [] Types; |
| return ER; |
| } |
| |
| ExprResult |
| Sema::CreateGenericSelectionExpr(SourceLocation KeyLoc, |
| SourceLocation DefaultLoc, |
| SourceLocation RParenLoc, |
| Expr *ControllingExpr, |
| ArrayRef<TypeSourceInfo *> Types, |
| ArrayRef<Expr *> Exprs) { |
| unsigned NumAssocs = Types.size(); |
| assert(NumAssocs == Exprs.size()); |
| |
| // Decay and strip qualifiers for the controlling expression type, and handle |
| // placeholder type replacement. See committee discussion from WG14 DR423. |
| { |
| EnterExpressionEvaluationContext Unevaluated( |
| *this, Sema::ExpressionEvaluationContext::Unevaluated); |
| ExprResult R = DefaultFunctionArrayLvalueConversion(ControllingExpr); |
| if (R.isInvalid()) |
| return ExprError(); |
| ControllingExpr = R.get(); |
| } |
| |
| // The controlling expression is an unevaluated operand, so side effects are |
| // likely unintended. |
| if (!inTemplateInstantiation() && |
| ControllingExpr->HasSideEffects(Context, false)) |
| Diag(ControllingExpr->getExprLoc(), |
| diag::warn_side_effects_unevaluated_context); |
| |
| bool TypeErrorFound = false, |
| IsResultDependent = ControllingExpr->isTypeDependent(), |
| ContainsUnexpandedParameterPack |
| = ControllingExpr->containsUnexpandedParameterPack(); |
| |
| for (unsigned i = 0; i < NumAssocs; ++i) { |
| if (Exprs[i]->containsUnexpandedParameterPack()) |
| ContainsUnexpandedParameterPack = true; |
| |
| if (Types[i]) { |
| if (Types[i]->getType()->containsUnexpandedParameterPack()) |
| ContainsUnexpandedParameterPack = true; |
| |
| if (Types[i]->getType()->isDependentType()) { |
| IsResultDependent = true; |
| } else { |
| // C11 6.5.1.1p2 "The type name in a generic association shall specify a |
| // complete object type other than a variably modified type." |
| unsigned D = 0; |
| if (Types[i]->getType()->isIncompleteType()) |
| D = diag::err_assoc_type_incomplete; |
| else if (!Types[i]->getType()->isObjectType()) |
| D = diag::err_assoc_type_nonobject; |
| else if (Types[i]->getType()->isVariablyModifiedType()) |
| D = diag::err_assoc_type_variably_modified; |
| |
| if (D != 0) { |
| Diag(Types[i]->getTypeLoc().getBeginLoc(), D) |
| << Types[i]->getTypeLoc().getSourceRange() |
| << Types[i]->getType(); |
| TypeErrorFound = true; |
| } |
| |
| // C11 6.5.1.1p2 "No two generic associations in the same generic |
| // selection shall specify compatible types." |
| for (unsigned j = i+1; j < NumAssocs; ++j) |
| if (Types[j] && !Types[j]->getType()->isDependentType() && |
| Context.typesAreCompatible(Types[i]->getType(), |
| Types[j]->getType())) { |
| Diag(Types[j]->getTypeLoc().getBeginLoc(), |
| diag::err_assoc_compatible_types) |
| << Types[j]->getTypeLoc().getSourceRange() |
| << Types[j]->getType() |
| << Types[i]->getType(); |
| Diag(Types[i]->getTypeLoc().getBeginLoc(), |
| diag::note_compat_assoc) |
| << Types[i]->getTypeLoc().getSourceRange() |
| << Types[i]->getType(); |
| TypeErrorFound = true; |
| } |
| } |
| } |
| } |
| if (TypeErrorFound) |
| return ExprError(); |
| |
| // If we determined that the generic selection is result-dependent, don't |
| // try to compute the result expression. |
| if (IsResultDependent) |
| return GenericSelectionExpr::Create(Context, KeyLoc, ControllingExpr, Types, |
| Exprs, DefaultLoc, RParenLoc, |
| ContainsUnexpandedParameterPack); |
| |
| SmallVector<unsigned, 1> CompatIndices; |
| unsigned DefaultIndex = -1U; |
| for (unsigned i = 0; i < NumAssocs; ++i) { |
| if (!Types[i]) |
| DefaultIndex = i; |
| else if (Context.typesAreCompatible(ControllingExpr->getType(), |
| Types[i]->getType())) |
| CompatIndices.push_back(i); |
| } |
| |
| // C11 6.5.1.1p2 "The controlling expression of a generic selection shall have |
| // type compatible with at most one of the types named in its generic |
| // association list." |
| if (CompatIndices.size() > 1) { |
| // We strip parens here because the controlling expression is typically |
| // parenthesized in macro definitions. |
| ControllingExpr = ControllingExpr->IgnoreParens(); |
| Diag(ControllingExpr->getBeginLoc(), diag::err_generic_sel_multi_match) |
| << ControllingExpr->getSourceRange() << ControllingExpr->getType() |
| << (unsigned)CompatIndices.size(); |
| for (unsigned I : CompatIndices) { |
| Diag(Types[I]->getTypeLoc().getBeginLoc(), |
| diag::note_compat_assoc) |
| << Types[I]->getTypeLoc().getSourceRange() |
| << Types[I]->getType(); |
| } |
| return ExprError(); |
| } |
| |
| // C11 6.5.1.1p2 "If a generic selection has no default generic association, |
| // its controlling expression shall have type compatible with exactly one of |
| // the types named in its generic association list." |
| if (DefaultIndex == -1U && CompatIndices.size() == 0) { |
| // We strip parens here because the controlling expression is typically |
| // parenthesized in macro definitions. |
| ControllingExpr = ControllingExpr->IgnoreParens(); |
| Diag(ControllingExpr->getBeginLoc(), diag::err_generic_sel_no_match) |
| << ControllingExpr->getSourceRange() << ControllingExpr->getType(); |
| return ExprError(); |
| } |
| |
| // C11 6.5.1.1p3 "If a generic selection has a generic association with a |
| // type name that is compatible with the type of the controlling expression, |
| // then the result expression of the generic selection is the expression |
| // in that generic association. Otherwise, the result expression of the |
| // generic selection is the expression in the default generic association." |
| unsigned ResultIndex = |
| CompatIndices.size() ? CompatIndices[0] : DefaultIndex; |
| |
| return GenericSelectionExpr::Create( |
| Context, KeyLoc, ControllingExpr, Types, Exprs, DefaultLoc, RParenLoc, |
| ContainsUnexpandedParameterPack, ResultIndex); |
| } |
| |
| /// getUDSuffixLoc - Create a SourceLocation for a ud-suffix, given the |
| /// location of the token and the offset of the ud-suffix within it. |
| static SourceLocation getUDSuffixLoc(Sema &S, SourceLocation TokLoc, |
| unsigned Offset) { |
| return Lexer::AdvanceToTokenCharacter(TokLoc, Offset, S.getSourceManager(), |
| S.getLangOpts()); |
| } |
| |
| /// BuildCookedLiteralOperatorCall - A user-defined literal was found. Look up |
| /// the corresponding cooked (non-raw) literal operator, and build a call to it. |
| static ExprResult BuildCookedLiteralOperatorCall(Sema &S, Scope *Scope, |
| IdentifierInfo *UDSuffix, |
| SourceLocation UDSuffixLoc, |
| ArrayRef<Expr*> Args, |
| SourceLocation LitEndLoc) { |
| assert(Args.size() <= 2 && "too many arguments for literal operator"); |
| |
| QualType ArgTy[2]; |
| for (unsigned ArgIdx = 0; ArgIdx != Args.size(); ++ArgIdx) { |
| ArgTy[ArgIdx] = Args[ArgIdx]->getType(); |
| if (ArgTy[ArgIdx]->isArrayType()) |
| ArgTy[ArgIdx] = S.Context.getArrayDecayedType(ArgTy[ArgIdx]); |
| } |
| |
| DeclarationName OpName = |
| S.Context.DeclarationNames.getCXXLiteralOperatorName(UDSuffix); |
| DeclarationNameInfo OpNameInfo(OpName, UDSuffixLoc); |
| OpNameInfo.setCXXLiteralOperatorNameLoc(UDSuffixLoc); |
| |
| LookupResult R(S, OpName, UDSuffixLoc, Sema::LookupOrdinaryName); |
| if (S.LookupLiteralOperator(Scope, R, llvm::makeArrayRef(ArgTy, Args.size()), |
| /*AllowRaw*/ false, /*AllowTemplate*/ false, |
| /*AllowStringTemplate*/ false, |
| /*DiagnoseMissing*/ true) == Sema::LOLR_Error) |
| return ExprError(); |
| |
| return S.BuildLiteralOperatorCall(R, OpNameInfo, Args, LitEndLoc); |
| } |
| |
| /// ActOnStringLiteral - The specified tokens were lexed as pasted string |
| /// fragments (e.g. "foo" "bar" L"baz"). The result string has to handle string |
| /// concatenation ([C99 5.1.1.2, translation phase #6]), so it may come from |
| /// multiple tokens. However, the common case is that StringToks points to one |
| /// string. |
| /// |
| ExprResult |
| Sema::ActOnStringLiteral(ArrayRef<Token> StringToks, Scope *UDLScope) { |
| assert(!StringToks.empty() && "Must have at least one string!"); |
| |
| StringLiteralParser Literal(StringToks, PP); |
| if (Literal.hadError) |
| return ExprError(); |
| |
| SmallVector<SourceLocation, 4> StringTokLocs; |
| for (const Token &Tok : StringToks) |
| StringTokLocs.push_back(Tok.getLocation()); |
| |
| QualType CharTy = Context.CharTy; |
| StringLiteral::StringKind Kind = StringLiteral::Ascii; |
| if (Literal.isWide()) { |
| CharTy = Context.getWideCharType(); |
| Kind = StringLiteral::Wide; |
| } else if (Literal.isUTF8()) { |
| if (getLangOpts().Char8) |
| CharTy = Context.Char8Ty; |
| Kind = StringLiteral::UTF8; |
| } else if (Literal.isUTF16()) { |
| CharTy = Context.Char16Ty; |
| Kind = StringLiteral::UTF16; |
| } else if (Literal.isUTF32()) { |
| CharTy = Context.Char32Ty; |
| Kind = StringLiteral::UTF32; |
| } else if (Literal.isPascal()) { |
| CharTy = Context.UnsignedCharTy; |
| } |
| |
| // Warn on initializing an array of char from a u8 string literal; this |
| // becomes ill-formed in C++2a. |
| if (getLangOpts().CPlusPlus && !getLangOpts().CPlusPlus2a && |
| !getLangOpts().Char8 && Kind == StringLiteral::UTF8) { |
| Diag(StringTokLocs.front(), diag::warn_cxx2a_compat_utf8_string); |
| |
| // Create removals for all 'u8' prefixes in the string literal(s). This |
| // ensures C++2a compatibility (but may change the program behavior when |
| // built by non-Clang compilers for which the execution character set is |
| // not always UTF-8). |
| auto RemovalDiag = PDiag(diag::note_cxx2a_compat_utf8_string_remove_u8); |
| SourceLocation RemovalDiagLoc; |
| for (const Token &Tok : StringToks) { |
| if (Tok.getKind() == tok::utf8_string_literal) { |
| if (RemovalDiagLoc.isInvalid()) |
| RemovalDiagLoc = Tok.getLocation(); |
| RemovalDiag << FixItHint::CreateRemoval(CharSourceRange::getCharRange( |
| Tok.getLocation(), |
| Lexer::AdvanceToTokenCharacter(Tok.getLocation(), 2, |
| getSourceManager(), getLangOpts()))); |
| } |
| } |
| Diag(RemovalDiagLoc, RemovalDiag); |
| } |
| |
| QualType StrTy = |
| Context.getStringLiteralArrayType(CharTy, Literal.GetNumStringChars()); |
| |
| // Pass &StringTokLocs[0], StringTokLocs.size() to factory! |
| StringLiteral *Lit = StringLiteral::Create(Context, Literal.GetString(), |
| Kind, Literal.Pascal, StrTy, |
| &StringTokLocs[0], |
| StringTokLocs.size()); |
| if (Literal.getUDSuffix().empty()) |
| return Lit; |
| |
| // We're building a user-defined literal. |
| IdentifierInfo *UDSuffix = &Context.Idents.get(Literal.getUDSuffix()); |
| SourceLocation UDSuffixLoc = |
| getUDSuffixLoc(*this, StringTokLocs[Literal.getUDSuffixToken()], |
| Literal.getUDSuffixOffset()); |
| |
| // Make sure we're allowed user-defined literals here. |
| if (!UDLScope) |
| return ExprError(Diag(UDSuffixLoc, diag::err_invalid_string_udl)); |
| |
| // C++11 [lex.ext]p5: The literal L is treated as a call of the form |
| // operator "" X (str, len) |
| QualType SizeType = Context.getSizeType(); |
| |
| DeclarationName OpName = |
| Context.DeclarationNames.getCXXLiteralOperatorName(UDSuffix); |
| DeclarationNameInfo OpNameInfo(OpName, UDSuffixLoc); |
| OpNameInfo.setCXXLiteralOperatorNameLoc(UDSuffixLoc); |
| |
| QualType ArgTy[] = { |
| Context.getArrayDecayedType(StrTy), SizeType |
| }; |
| |
| LookupResult R(*this, OpName, UDSuffixLoc, LookupOrdinaryName); |
| switch (LookupLiteralOperator(UDLScope, R, ArgTy, |
| /*AllowRaw*/ false, /*AllowTemplate*/ false, |
| /*AllowStringTemplate*/ true, |
| /*DiagnoseMissing*/ true)) { |
| |
| case LOLR_Cooked: { |
| llvm::APInt Len(Context.getIntWidth(SizeType), Literal.GetNumStringChars()); |
| IntegerLiteral *LenArg = IntegerLiteral::Create(Context, Len, SizeType, |
| StringTokLocs[0]); |
| Expr *Args[] = { Lit, LenArg }; |
| |
| return BuildLiteralOperatorCall(R, OpNameInfo, Args, StringTokLocs.back()); |
| } |
| |
| case LOLR_StringTemplate: { |
| TemplateArgumentListInfo ExplicitArgs; |
| |
| unsigned CharBits = Context.getIntWidth(CharTy); |
| bool CharIsUnsigned = CharTy->isUnsignedIntegerType(); |
| llvm::APSInt Value(CharBits, CharIsUnsigned); |
| |
| TemplateArgument TypeArg(CharTy); |
| TemplateArgumentLocInfo TypeArgInfo(Context.getTrivialTypeSourceInfo(CharTy)); |
| ExplicitArgs.addArgument(TemplateArgumentLoc(TypeArg, TypeArgInfo)); |
| |
| for (unsigned I = 0, N = Lit->getLength(); I != N; ++I) { |
| Value = Lit->getCodeUnit(I); |
| TemplateArgument Arg(Context, Value, CharTy); |
| TemplateArgumentLocInfo ArgInfo; |
| ExplicitArgs.addArgument(TemplateArgumentLoc(Arg, ArgInfo)); |
| } |
| return BuildLiteralOperatorCall(R, OpNameInfo, None, StringTokLocs.back(), |
| &ExplicitArgs); |
| } |
| case LOLR_Raw: |
| case LOLR_Template: |
| case LOLR_ErrorNoDiagnostic: |
| llvm_unreachable("unexpected literal operator lookup result"); |
| case LOLR_Error: |
| return ExprError(); |
| } |
| llvm_unreachable("unexpected literal operator lookup result"); |
| } |
| |
| DeclRefExpr * |
| Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK, |
| SourceLocation Loc, |
| const CXXScopeSpec *SS) { |
| DeclarationNameInfo NameInfo(D->getDeclName(), Loc); |
| return BuildDeclRefExpr(D, Ty, VK, NameInfo, SS); |
| } |
| |
| DeclRefExpr * |
| Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK, |
| const DeclarationNameInfo &NameInfo, |
| const CXXScopeSpec *SS, NamedDecl *FoundD, |
| SourceLocation TemplateKWLoc, |
| const TemplateArgumentListInfo *TemplateArgs) { |
| NestedNameSpecifierLoc NNS = |
| SS ? SS->getWithLocInContext(Context) : NestedNameSpecifierLoc(); |
| return BuildDeclRefExpr(D, Ty, VK, NameInfo, NNS, FoundD, TemplateKWLoc, |
| TemplateArgs); |
| } |
| |
| NonOdrUseReason Sema::getNonOdrUseReasonInCurrentContext(ValueDecl *D) { |
| // A declaration named in an unevaluated operand never constitutes an odr-use. |
| if (isUnevaluatedContext()) |
| return NOUR_Unevaluated; |
| |
| // C++2a [basic.def.odr]p4: |
| // A variable x whose name appears as a potentially-evaluated expression e |
| // is odr-used by e unless [...] x is a reference that is usable in |
| // constant expressions. |
| if (VarDecl *VD = dyn_cast<VarDecl>(D)) { |
| if (VD->getType()->isReferenceType() && |
| !(getLangOpts().OpenMP && isOpenMPCapturedDecl(D)) && |
| VD->isUsableInConstantExpressions(Context)) |
| return NOUR_Constant; |
| } |
| |
| // All remaining non-variable cases constitute an odr-use. For variables, we |
| // need to wait and see how the expression is used. |
| return NOUR_None; |
| } |
| |
| /// BuildDeclRefExpr - Build an expression that references a |
| /// declaration that does not require a closure capture. |
| DeclRefExpr * |
| Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK, |
| const DeclarationNameInfo &NameInfo, |
| NestedNameSpecifierLoc NNS, NamedDecl *FoundD, |
| SourceLocation TemplateKWLoc, |
| const TemplateArgumentListInfo *TemplateArgs) { |
| bool RefersToCapturedVariable = |
| isa<VarDecl>(D) && |
| NeedToCaptureVariable(cast<VarDecl>(D), NameInfo.getLoc()); |
| |
| DeclRefExpr *E = DeclRefExpr::Create( |
| Context, NNS, TemplateKWLoc, D, RefersToCapturedVariable, NameInfo, Ty, |
| VK, FoundD, TemplateArgs, getNonOdrUseReasonInCurrentContext(D)); |
| MarkDeclRefReferenced(E); |
| |
| if (getLangOpts().ObjCWeak && isa<VarDecl>(D) && |
| Ty.getObjCLifetime() == Qualifiers::OCL_Weak && !isUnevaluatedContext() && |
| !Diags.isIgnored(diag::warn_arc_repeated_use_of_weak, E->getBeginLoc())) |
| getCurFunction()->recordUseOfWeak(E); |
| |
| FieldDecl *FD = dyn_cast<FieldDecl>(D); |
| if (IndirectFieldDecl *IFD = dyn_cast<IndirectFieldDecl>(D)) |
| FD = IFD->getAnonField(); |
| if (FD) { |
| UnusedPrivateFields.remove(FD); |
| // Just in case we're building an illegal pointer-to-member. |
| if (FD->isBitField()) |
| E->setObjectKind(OK_BitField); |
| } |
| |
| // C++ [expr.prim]/8: The expression [...] is a bit-field if the identifier |
| // designates a bit-field. |
| if (auto *BD = dyn_cast<BindingDecl>(D)) |
| if (auto *BE = BD->getBinding()) |
| E->setObjectKind(BE->getObjectKind()); |
| |
| return E; |
| } |
| |
| /// Decomposes the given name into a DeclarationNameInfo, its location, and |
| /// possibly a list of template arguments. |
| /// |
| /// If this produces template arguments, it is permitted to call |
| /// DecomposeTemplateName. |
| /// |
| /// This actually loses a lot of source location information for |
| /// non-standard name kinds; we should consider preserving that in |
| /// some way. |
| void |
| Sema::DecomposeUnqualifiedId(const UnqualifiedId &Id, |
| TemplateArgumentListInfo &Buffer, |
| DeclarationNameInfo &NameInfo, |
| const TemplateArgumentListInfo *&TemplateArgs) { |
| if (Id.getKind() == UnqualifiedIdKind::IK_TemplateId) { |
| Buffer.setLAngleLoc(Id.TemplateId->LAngleLoc); |
| Buffer.setRAngleLoc(Id.TemplateId->RAngleLoc); |
| |
| ASTTemplateArgsPtr TemplateArgsPtr(Id.TemplateId->getTemplateArgs(), |
| Id.TemplateId->NumArgs); |
| translateTemplateArguments(TemplateArgsPtr, Buffer); |
| |
| TemplateName TName = Id.TemplateId->Template.get(); |
| SourceLocation TNameLoc = Id.TemplateId->TemplateNameLoc; |
| NameInfo = Context.getNameForTemplate(TName, TNameLoc); |
| TemplateArgs = &Buffer; |
| } else { |
| NameInfo = GetNameFromUnqualifiedId(Id); |
| TemplateArgs = nullptr; |
| } |
| } |
| |
| static void emitEmptyLookupTypoDiagnostic( |
| const TypoCorrection &TC, Sema &SemaRef, const CXXScopeSpec &SS, |
| DeclarationName Typo, SourceLocation TypoLoc, ArrayRef<Expr *> Args, |
| unsigned DiagnosticID, unsigned DiagnosticSuggestID) { |
| DeclContext *Ctx = |
| SS.isEmpty() ? nullptr : SemaRef.computeDeclContext(SS, false); |
| if (!TC) { |
| // Emit a special diagnostic for failed member lookups. |
| // FIXME: computing the declaration context might fail here (?) |
| if (Ctx) |
| SemaRef.Diag(TypoLoc, diag::err_no_member) << Typo << Ctx |
| << SS.getRange(); |
| else |
| SemaRef.Diag(TypoLoc, DiagnosticID) << Typo; |
| return; |
| } |
| |
| std::string CorrectedStr = TC.getAsString(SemaRef.getLangOpts()); |
| bool DroppedSpecifier = |
| TC.WillReplaceSpecifier() && Typo.getAsString() == CorrectedStr; |
| unsigned NoteID = TC.getCorrectionDeclAs<ImplicitParamDecl>() |
| ? diag::note_implicit_param_decl |
| : diag::note_previous_decl; |
| if (!Ctx) |
| SemaRef.diagnoseTypo(TC, SemaRef.PDiag(DiagnosticSuggestID) << Typo, |
| SemaRef.PDiag(NoteID)); |
| else |
| SemaRef.diagnoseTypo(TC, SemaRef.PDiag(diag::err_no_member_suggest) |
| << Typo << Ctx << DroppedSpecifier |
| << SS.getRange(), |
| SemaRef.PDiag(NoteID)); |
| } |
| |
| /// Diagnose an empty lookup. |
| /// |
| /// \return false if new lookup candidates were found |
| bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R, |
| CorrectionCandidateCallback &CCC, |
| TemplateArgumentListInfo *ExplicitTemplateArgs, |
| ArrayRef<Expr *> Args, TypoExpr **Out) { |
| DeclarationName Name = R.getLookupName(); |
| |
| unsigned diagnostic = diag::err_undeclared_var_use; |
| unsigned diagnostic_suggest = diag::err_undeclared_var_use_suggest; |
| if (Name.getNameKind() == DeclarationName::CXXOperatorName || |
| Name.getNameKind() == DeclarationName::CXXLiteralOperatorName || |
| Name.getNameKind() == DeclarationName::CXXConversionFunctionName) { |
| diagnostic = diag::err_undeclared_use; |
| diagnostic_suggest = diag::err_undeclared_use_suggest; |
| } |
| |
| // If the original lookup was an unqualified lookup, fake an |
| // unqualified lookup. This is useful when (for example) the |
| // original lookup would not have found something because it was a |
| // dependent name. |
| DeclContext *DC = SS.isEmpty() ? CurContext : nullptr; |
| while (DC) { |
| if (isa<CXXRecordDecl>(DC)) { |
| LookupQualifiedName(R, DC); |
| |
| if (!R.empty()) { |
| // Don't give errors about ambiguities in this lookup. |
| R.suppressDiagnostics(); |
| |
| // During a default argument instantiation the CurContext points |
| // to a CXXMethodDecl; but we can't apply a this-> fixit inside a |
| // function parameter list, hence add an explicit check. |
| bool isDefaultArgument = |
| !CodeSynthesisContexts.empty() && |
| CodeSynthesisContexts.back().Kind == |
| CodeSynthesisContext::DefaultFunctionArgumentInstantiation; |
| CXXMethodDecl *CurMethod = dyn_cast<CXXMethodDecl>(CurContext); |
| bool isInstance = CurMethod && |
| CurMethod->isInstance() && |
| DC == CurMethod->getParent() && !isDefaultArgument; |
| |
| // Give a code modification hint to insert 'this->'. |
| // TODO: fixit for inserting 'Base<T>::' in the other cases. |
| // Actually quite difficult! |
| if (getLangOpts().MSVCCompat) |
| diagnostic = diag::ext_found_via_dependent_bases_lookup; |
| if (isInstance) { |
| Diag(R.getNameLoc(), diagnostic) << Name |
| << FixItHint::CreateInsertion(R.getNameLoc(), "this->"); |
| CheckCXXThisCapture(R.getNameLoc()); |
| } else { |
| Diag(R.getNameLoc(), diagnostic) << Name; |
| } |
| |
| // Do we really want to note all of these? |
| for (NamedDecl *D : R) |
| Diag(D->getLocation(), diag::note_dependent_var_use); |
| |
| // Return true if we are inside a default argument instantiation |
| // and the found name refers to an instance member function, otherwise |
| // the function calling DiagnoseEmptyLookup will try to create an |
| // implicit member call and this is wrong for default argument. |
| if (isDefaultArgument && ((*R.begin())->isCXXInstanceMember())) { |
| Diag(R.getNameLoc(), diag::err_member_call_without_object); |
| return true; |
| } |
| |
| // Tell the callee to try to recover. |
| return false; |
| } |
| |
| R.clear(); |
| } |
| |
| DC = DC->getLookupParent(); |
| } |
| |
| // We didn't find anything, so try to correct for a typo. |
| TypoCorrection Corrected; |
| if (S && Out) { |
| SourceLocation TypoLoc = R.getNameLoc(); |
| assert(!ExplicitTemplateArgs && |
| "Diagnosing an empty lookup with explicit template args!"); |
| *Out = CorrectTypoDelayed( |
| R.getLookupNameInfo(), R.getLookupKind(), S, &SS, CCC, |
| [=](const TypoCorrection &TC) { |
| emitEmptyLookupTypoDiagnostic(TC, *this, SS, Name, TypoLoc, Args, |
| diagnostic, diagnostic_suggest); |
| }, |
| nullptr, CTK_ErrorRecovery); |
| if (*Out) |
| return true; |
| } else if (S && |
| (Corrected = CorrectTypo(R.getLookupNameInfo(), R.getLookupKind(), |
| S, &SS, CCC, CTK_ErrorRecovery))) { |
| std::string CorrectedStr(Corrected.getAsString(getLangOpts())); |
| bool DroppedSpecifier = |
| Corrected.WillReplaceSpecifier() && Name.getAsString() == CorrectedStr; |
| R.setLookupName(Corrected.getCorrection()); |
| |
| bool AcceptableWithRecovery = false; |
| bool AcceptableWithoutRecovery = false; |
| NamedDecl *ND = Corrected.getFoundDecl(); |
| if (ND) { |
| if (Corrected.isOverloaded()) { |
| OverloadCandidateSet OCS(R.getNameLoc(), |
| OverloadCandidateSet::CSK_Normal); |
| OverloadCandidateSet::iterator Best; |
| for (NamedDecl *CD : Corrected) { |
| if (FunctionTemplateDecl *FTD = |
| dyn_cast<FunctionTemplateDecl>(CD)) |
| AddTemplateOverloadCandidate( |
| FTD, DeclAccessPair::make(FTD, AS_none), ExplicitTemplateArgs, |
| Args, OCS); |
| else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(CD)) |
| if (!ExplicitTemplateArgs || ExplicitTemplateArgs->size() == 0) |
| AddOverloadCandidate(FD, DeclAccessPair::make(FD, AS_none), |
| Args, OCS); |
| } |
| switch (OCS.BestViableFunction(*this, R.getNameLoc(), Best)) { |
| case OR_Success: |
| ND = Best->FoundDecl; |
| Corrected.setCorrectionDecl(ND); |
| break; |
| default: |
| // FIXME: Arbitrarily pick the first declaration for the note. |
| Corrected.setCorrectionDecl(ND); |
| break; |
| } |
| } |
| R.addDecl(ND); |
| if (getLangOpts().CPlusPlus && ND->isCXXClassMember()) { |
| CXXRecordDecl *Record = nullptr; |
| if (Corrected.getCorrectionSpecifier()) { |
| const Type *Ty = Corrected.getCorrectionSpecifier()->getAsType(); |
| Record = Ty->getAsCXXRecordDecl(); |
| } |
| if (!Record) |
| Record = cast<CXXRecordDecl>( |
| ND->getDeclContext()->getRedeclContext()); |
| R.setNamingClass(Record); |
| } |
| |
| auto *UnderlyingND = ND->getUnderlyingDecl(); |
| AcceptableWithRecovery = isa<ValueDecl>(UnderlyingND) || |
| isa<FunctionTemplateDecl>(UnderlyingND); |
| // FIXME: If we ended up with a typo for a type name or |
| // Objective-C class name, we're in trouble because the parser |
| // is in the wrong place to recover. Suggest the typo |
| // correction, but don't make it a fix-it since we're not going |
| // to recover well anyway. |
| AcceptableWithoutRecovery = isa<TypeDecl>(UnderlyingND) || |
| getAsTypeTemplateDecl(UnderlyingND) || |
| isa<ObjCInterfaceDecl>(UnderlyingND); |
| } else { |
| // FIXME: We found a keyword. Suggest it, but don't provide a fix-it |
| // because we aren't able to recover. |
| AcceptableWithoutRecovery = true; |
| } |
| |
| if (AcceptableWithRecovery || AcceptableWithoutRecovery) { |
| unsigned NoteID = Corrected.getCorrectionDeclAs<ImplicitParamDecl>() |
| ? diag::note_implicit_param_decl |
| : diag::note_previous_decl; |
| if (SS.isEmpty()) |
| diagnoseTypo(Corrected, PDiag(diagnostic_suggest) << Name, |
| PDiag(NoteID), AcceptableWithRecovery); |
| else |
| diagnoseTypo(Corrected, PDiag(diag::err_no_member_suggest) |
| << Name << computeDeclContext(SS, false) |
| << DroppedSpecifier << SS.getRange(), |
| PDiag(NoteID), AcceptableWithRecovery); |
| |
| // Tell the callee whether to try to recover. |
| return !AcceptableWithRecovery; |
| } |
| } |
| R.clear(); |
| |
| // Emit a special diagnostic for failed member lookups. |
| // FIXME: computing the declaration context might fail here (?) |
| if (!SS.isEmpty()) { |
| Diag(R.getNameLoc(), diag::err_no_member) |
| << Name << computeDeclContext(SS, false) |
| << SS.getRange(); |
| return true; |
| } |
| |
| // Give up, we can't recover. |
| Diag(R.getNameLoc(), diagnostic) << Name; |
| return true; |
| } |
| |
| /// In Microsoft mode, if we are inside a template class whose parent class has |
| /// dependent base classes, and we can't resolve an unqualified identifier, then |
| /// assume the identifier is a member of a dependent base class. We can only |
| /// recover successfully in static methods, instance methods, and other contexts |
| /// where 'this' is available. This doesn't precisely match MSVC's |
| /// instantiation model, but it's close enough. |
| static Expr * |
| recoverFromMSUnqualifiedLookup(Sema &S, ASTContext &Context, |
| DeclarationNameInfo &NameInfo, |
| SourceLocation TemplateKWLoc, |
| const TemplateArgumentListInfo *TemplateArgs) { |
| // Only try to recover from lookup into dependent bases in static methods or |
| // contexts where 'this' is available. |
| QualType ThisType = S.getCurrentThisType(); |
| const CXXRecordDecl *RD = nullptr; |
| if (!ThisType.isNull()) |
| RD = ThisType->getPointeeType()->getAsCXXRecordDecl(); |
| else if (auto *MD = dyn_cast<CXXMethodDecl>(S.CurContext)) |
| RD = MD->getParent(); |
| if (!RD || !RD->hasAnyDependentBases()) |
| return nullptr; |
| |
| // Diagnose this as unqualified lookup into a dependent base class. If 'this' |
| // is available, suggest inserting 'this->' as a fixit. |
| SourceLocation Loc = NameInfo.getLoc(); |
| auto DB = S.Diag(Loc, diag::ext_undeclared_unqual_id_with_dependent_base); |
| DB << NameInfo.getName() << RD; |
| |
| if (!ThisType.isNull()) { |
| DB << FixItHint::CreateInsertion(Loc, "this->"); |
| return CXXDependentScopeMemberExpr::Create( |
| Context, /*This=*/nullptr, ThisType, /*IsArrow=*/true, |
| /*Op=*/SourceLocation(), NestedNameSpecifierLoc(), TemplateKWLoc, |
| /*FirstQualifierFoundInScope=*/nullptr, NameInfo, TemplateArgs); |
| } |
| |
| // Synthesize a fake NNS that points to the derived class. This will |
| // perform name lookup during template instantiation. |
| CXXScopeSpec SS; |
| auto *NNS = |
| NestedNameSpecifier::Create(Context, nullptr, true, RD->getTypeForDecl()); |
| SS.MakeTrivial(Context, NNS, SourceRange(Loc, Loc)); |
| return DependentScopeDeclRefExpr::Create( |
| Context, SS.getWithLocInContext(Context), TemplateKWLoc, NameInfo, |
| TemplateArgs); |
| } |
| |
| ExprResult |
| Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS, |
| SourceLocation TemplateKWLoc, UnqualifiedId &Id, |
| bool HasTrailingLParen, bool IsAddressOfOperand, |
| CorrectionCandidateCallback *CCC, |
| bool IsInlineAsmIdentifier, Token *KeywordReplacement) { |
| assert(!(IsAddressOfOperand && HasTrailingLParen) && |
| "cannot be direct & operand and have a trailing lparen"); |
| if (SS.isInvalid()) |
| return ExprError(); |
| |
| TemplateArgumentListInfo TemplateArgsBuffer; |
| |
| // Decompose the UnqualifiedId into the following data. |
| DeclarationNameInfo NameInfo; |
| const TemplateArgumentListInfo *TemplateArgs; |
| DecomposeUnqualifiedId(Id, TemplateArgsBuffer, NameInfo, TemplateArgs); |
| |
| DeclarationName Name = NameInfo.getName(); |
| IdentifierInfo *II = Name.getAsIdentifierInfo(); |
| SourceLocation NameLoc = NameInfo.getLoc(); |
| |
| if (II && II->isEditorPlaceholder()) { |
| // FIXME: When typed placeholders are supported we can create a typed |
| // placeholder expression node. |
| return ExprError(); |
| } |
| |
| // C++ [temp.dep.expr]p3: |
| // An id-expression is type-dependent if it contains: |
| // -- an identifier that was declared with a dependent type, |
| // (note: handled after lookup) |
| // -- a template-id that is dependent, |
| // (note: handled in BuildTemplateIdExpr) |
| // -- a conversion-function-id that specifies a dependent type, |
| // -- a nested-name-specifier that contains a class-name that |
| // names a dependent type. |
| // Determine whether this is a member of an unknown specialization; |
| // we need to handle these differently. |
| bool DependentID = false; |
| if (Name.getNameKind() == DeclarationName::CXXConversionFunctionName && |
| Name.getCXXNameType()->isDependentType()) { |
| DependentID = true; |
| } else if (SS.isSet()) { |
| if (DeclContext *DC = computeDeclContext(SS, false)) { |
| if (RequireCompleteDeclContext(SS, DC)) |
| return ExprError(); |
| } else { |
| DependentID = true; |
| } |
| } |
| |
| if (DependentID) |
| return ActOnDependentIdExpression(SS, TemplateKWLoc, NameInfo, |
| IsAddressOfOperand, TemplateArgs); |
| |
| // Perform the required lookup. |
| LookupResult R(*this, NameInfo, |
| (Id.getKind() == UnqualifiedIdKind::IK_ImplicitSelfParam) |
| ? LookupObjCImplicitSelfParam |
| : LookupOrdinaryName); |
| if (TemplateKWLoc.isValid() || TemplateArgs) { |
| // Lookup the template name again to correctly establish the context in |
| // which it was found. This is really unfortunate as we already did the |
| // lookup to determine that it was a template name in the first place. If |
| // this becomes a performance hit, we can work harder to preserve those |
| // results until we get here but it's likely not worth it. |
| bool MemberOfUnknownSpecialization; |
| AssumedTemplateKind AssumedTemplate; |
| if (LookupTemplateName(R, S, SS, QualType(), /*EnteringContext=*/false, |
| MemberOfUnknownSpecialization, TemplateKWLoc, |
| &AssumedTemplate)) |
| return ExprError(); |
| |
| if (MemberOfUnknownSpecialization || |
| (R.getResultKind() == LookupResult::NotFoundInCurrentInstantiation)) |
| return ActOnDependentIdExpression(SS, TemplateKWLoc, NameInfo, |
| IsAddressOfOperand, TemplateArgs); |
| } else { |
| bool IvarLookupFollowUp = II && !SS.isSet() && getCurMethodDecl(); |
| LookupParsedName(R, S, &SS, !IvarLookupFollowUp); |
| |
| // If the result might be in a dependent base class, this is a dependent |
| // id-expression. |
| if (R.getResultKind() == LookupResult::NotFoundInCurrentInstantiation) |
| return ActOnDependentIdExpression(SS, TemplateKWLoc, NameInfo, |
| IsAddressOfOperand, TemplateArgs); |
| |
| // If this reference is in an Objective-C method, then we need to do |
| // some special Objective-C lookup, too. |
| if (IvarLookupFollowUp) { |
| ExprResult E(LookupInObjCMethod(R, S, II, true)); |
| if (E.isInvalid()) |
| return ExprError(); |
| |
| if (Expr *Ex = E.getAs<Expr>()) |
| return Ex; |
| } |
| } |
| |
| if (R.isAmbiguous()) |
| return ExprError(); |
| |
| // This could be an implicitly declared function reference (legal in C90, |
| // extension in C99, forbidden in C++). |
| if (R.empty() && HasTrailingLParen && II && !getLangOpts().CPlusPlus) { |
| NamedDecl *D = ImplicitlyDefineFunction(NameLoc, *II, S); |
| if (D) R.addDecl(D); |
| } |
| |
| // Determine whether this name might be a candidate for |
| // argument-dependent lookup. |
| bool ADL = UseArgumentDependentLookup(SS, R, HasTrailingLParen); |
| |
| if (R.empty() && !ADL) { |
| if (SS.isEmpty() && getLangOpts().MSVCCompat) { |
| if (Expr *E = recoverFromMSUnqualifiedLookup(*this, Context, NameInfo, |
| TemplateKWLoc, TemplateArgs)) |
| return E; |
| } |
| |
| // Don't diagnose an empty lookup for inline assembly. |
| if (IsInlineAsmIdentifier) |
| return ExprError(); |
| |
| // If this name wasn't predeclared and if this is not a function |
| // call, diagnose the problem. |
| TypoExpr *TE = nullptr; |
| DefaultFilterCCC DefaultValidator(II, SS.isValid() ? SS.getScopeRep() |
| : nullptr); |
| DefaultValidator.IsAddressOfOperand = IsAddressOfOperand; |
| assert((!CCC || CCC->IsAddressOfOperand == IsAddressOfOperand) && |
| "Typo correction callback misconfigured"); |
| if (CCC) { |
| // Make sure the callback knows what the typo being diagnosed is. |
| CCC->setTypoName(II); |
| if (SS.isValid()) |
| CCC->setTypoNNS(SS.getScopeRep()); |
| } |
| // FIXME: DiagnoseEmptyLookup produces bad diagnostics if we're looking for |
| // a template name, but we happen to have always already looked up the name |
| // before we get here if it must be a template name. |
| if (DiagnoseEmptyLookup(S, SS, R, CCC ? *CCC : DefaultValidator, nullptr, |
| None, &TE)) { |
| if (TE && KeywordReplacement) { |
| auto &State = getTypoExprState(TE); |
| auto BestTC = State.Consumer->getNextCorrection(); |
| if (BestTC.isKeyword()) { |
| auto *II = BestTC.getCorrectionAsIdentifierInfo(); |
| if (State.DiagHandler) |
| State.DiagHandler(BestTC); |
| KeywordReplacement->startToken(); |
| KeywordReplacement->setKind(II->getTokenID()); |
| KeywordReplacement->setIdentifierInfo(II); |
| KeywordReplacement->setLocation(BestTC.getCorrectionRange().getBegin()); |
| // Clean up the state associated with the TypoExpr, since it has |
| // now been diagnosed (without a call to CorrectDelayedTyposInExpr). |
| clearDelayedTypo(TE); |
| // Signal that a correction to a keyword was performed by returning a |
| // valid-but-null ExprResult. |
| return (Expr*)nullptr; |
| } |
| State.Consumer->resetCorrectionStream(); |
| } |
| return TE ? TE : ExprError(); |
| } |
| |
| assert(!R.empty() && |
| "DiagnoseEmptyLookup returned false but added no results"); |
| |
| // If we found an Objective-C instance variable, let |
| // LookupInObjCMethod build the appropriate expression to |
| // reference the ivar. |
| if (ObjCIvarDecl *Ivar = R.getAsSingle<ObjCIvarDecl>()) { |
| R.clear(); |
| ExprResult E(LookupInObjCMethod(R, S, Ivar->getIdentifier())); |
| // In a hopelessly buggy code, Objective-C instance variable |
| // lookup fails and no expression will be built to reference it. |
| if (!E.isInvalid() && !E.get()) |
| return ExprError(); |
| return E; |
| } |
| } |
| |
| // This is guaranteed from this point on. |
| assert(!R.empty() || ADL); |
| |
| // Check whether this might be a C++ implicit instance member access. |
| // C++ [class.mfct.non-static]p3: |
| // When an id-expression that is not part of a class member access |
| // syntax and not used to form a pointer to member is used in the |
| // body of a non-static member function of class X, if name lookup |
| // resolves the name in the id-expression to a non-static non-type |
| // member of some class C, the id-expression is transformed into a |
| // class member access expression using (*this) as the |
| // postfix-expression to the left of the . operator. |
| // |
| // But we don't actually need to do this for '&' operands if R |
| // resolved to a function or overloaded function set, because the |
| // expression is ill-formed if it actually works out to be a |
| // non-static member function: |
| // |
| // C++ [expr.ref]p4: |
| // Otherwise, if E1.E2 refers to a non-static member function. . . |
| // [t]he expression can be used only as the left-hand operand of a |
| // member function call. |
| // |
| // There are other safeguards against such uses, but it's important |
| // to get this right here so that we don't end up making a |
| // spuriously dependent expression if we're inside a dependent |
| // instance method. |
| if (!R.empty() && (*R.begin())->isCXXClassMember()) { |
| bool MightBeImplicitMember; |
| if (!IsAddressOfOperand) |
| MightBeImplicitMember = true; |
| else if (!SS.isEmpty()) |
| MightBeImplicitMember = false; |
| else if (R.isOverloadedResult()) |
| MightBeImplicitMember = false; |
| else if (R.isUnresolvableResult()) |
| MightBeImplicitMember = true; |
| else |
| MightBeImplicitMember = isa<FieldDecl>(R.getFoundDecl()) || |
| isa<IndirectFieldDecl>(R.getFoundDecl()) || |
| isa<MSPropertyDecl>(R.getFoundDecl()); |
| |
| if (MightBeImplicitMember) |
| return BuildPossibleImplicitMemberExpr(SS, TemplateKWLoc, |
| R, TemplateArgs, S); |
| } |
| |
| if (TemplateArgs || TemplateKWLoc.isValid()) { |
| |
| // In C++1y, if this is a variable template id, then check it |
| // in BuildTemplateIdExpr(). |
| // The single lookup result must be a variable template declaration. |
| if (Id.getKind() == UnqualifiedIdKind::IK_TemplateId && Id.TemplateId && |
| Id.TemplateId->Kind == TNK_Var_template) { |
| assert(R.getAsSingle<VarTemplateDecl>() && |
| "There should only be one declaration found."); |
| } |
| |
| return BuildTemplateIdExpr(SS, TemplateKWLoc, R, ADL, TemplateArgs); |
| } |
| |
| return BuildDeclarationNameExpr(SS, R, ADL); |
| } |
| |
| /// 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 |
| /// this path. |
| ExprResult Sema::BuildQualifiedDeclarationNameExpr( |
| CXXScopeSpec &SS, const DeclarationNameInfo &NameInfo, |
| bool IsAddressOfOperand, const Scope *S, TypeSourceInfo **RecoveryTSI) { |
| DeclContext *DC = computeDeclContext(SS, false); |
| if (!DC) |
| return BuildDependentDeclRefExpr(SS, /*TemplateKWLoc=*/SourceLocation(), |
| NameInfo, /*TemplateArgs=*/nullptr); |
| |
| if (RequireCompleteDeclContext(SS, DC)) |
| return ExprError(); |
| |
| LookupResult R(*this, NameInfo, LookupOrdinaryName); |
| LookupQualifiedName(R, DC); |
| |
| if (R.isAmbiguous()) |
| return ExprError(); |
| |
| if (R.getResultKind() == LookupResult::NotFoundInCurrentInstantiation) |
| return BuildDependentDeclRefExpr(SS, /*TemplateKWLoc=*/SourceLocation(), |
| NameInfo, /*TemplateArgs=*/nullptr); |
| |
| if (R.empty()) { |
| Diag(NameInfo.getLoc(), diag::err_no_member) |
| << NameInfo.getName() << DC << SS.getRange(); |
| return ExprError(); |
| } |
| |
| if (const TypeDecl *TD = R.getAsSingle<TypeDecl>()) { |
| // Diagnose a missing typename if this resolved unambiguously to a type in |
| // a dependent context. If we can recover with a type, downgrade this to |
| // a warning in Microsoft compatibility mode. |
| unsigned DiagID = diag::err_typename_missing; |
| if (RecoveryTSI && getLangOpts().MSVCCompat) |
| DiagID = diag::ext_typename_missing; |
| SourceLocation Loc = SS.getBeginLoc(); |
| auto D = Diag(Loc, DiagID); |
| D << SS.getScopeRep() << NameInfo.getName().getAsString() |
| << SourceRange(Loc, NameInfo.getEndLoc()); |
| |
| // Don't recover if the caller isn't expecting us to or if we're in a SFINAE |
| // context. |
| if (!RecoveryTSI) |
| return ExprError(); |
| |
| // Only issue the fixit if we're prepared to recover. |
| D << FixItHint::CreateInsertion(Loc, "typename "); |
| |
| // Recover by pretending this was an elaborated type. |
| QualType Ty = Context.getTypeDeclType(TD); |
| TypeLocBuilder TLB; |
| TLB.pushTypeSpec(Ty).setNameLoc(NameInfo.getLoc()); |
| |
| QualType ET = getElaboratedType(ETK_None, SS, Ty); |
| ElaboratedTypeLoc QTL = TLB.push<ElaboratedTypeLoc>(ET); |
| QTL.setElaboratedKeywordLoc(SourceLocation()); |
| QTL.setQualifierLoc(SS.getWithLocInContext(Context)); |
| |
| *RecoveryTSI = TLB.getTypeSourceInfo(Context, ET); |
| |
| return ExprEmpty(); |
| } |
| |
| // Defend against this resolving to an implicit member access. We usually |
| // won't get here if this might be a legitimate a class member (we end up in |
| // BuildMemberReferenceExpr instead), but this can be valid if we're forming |
| // a pointer-to-member or in an unevaluated context in C++11. |
| if (!R.empty() && (*R.begin())->isCXXClassMember() && !IsAddressOfOperand) |
| return BuildPossibleImplicitMemberExpr(SS, |
| /*TemplateKWLoc=*/SourceLocation(), |
| R, /*TemplateArgs=*/nullptr, S); |
| |
| return BuildDeclarationNameExpr(SS, R, /* ADL */ false); |
| } |
| |
| /// The parser has read a name in, and Sema has detected that we're currently |
| /// inside an ObjC method. Perform some additional checks and determine if we |
| /// should form a reference to an ivar. |
| /// |
| /// Ideally, most of this would be done by lookup, but there's |
| /// actually quite a lot of extra work involved. |
| DeclResult Sema::LookupIvarInObjCMethod(LookupResult &Lookup, Scope *S, |
| IdentifierInfo *II) { |
| SourceLocation Loc = Lookup.getNameLoc(); |
| ObjCMethodDecl *CurMethod = getCurMethodDecl(); |
| |
| // Check for error condition which is already reported. |
| if (!CurMethod) |
| return DeclResult(true); |
| |
| // There are two cases to handle here. 1) scoped lookup could have failed, |
| // in which case we should look for an ivar. 2) scoped lookup could have |
| // found a decl, but that decl is outside the current instance method (i.e. |
| // a global variable). In these two cases, we do a lookup for an ivar with |
| // this name, if the lookup sucedes, we replace it our current decl. |
| |
| // If we're in a class method, we don't normally want to look for |
| // ivars. But if we don't find anything else, and there's an |
| // ivar, that's an error. |
| bool IsClassMethod = CurMethod->isClassMethod(); |
| |
| bool LookForIvars; |
| if (Lookup.empty()) |
| LookForIvars = true; |
| else if (IsClassMethod) |
| LookForIvars = false; |
| else |
| LookForIvars = (Lookup.isSingleResult() && |
| Lookup.getFoundDecl()->isDefinedOutsideFunctionOrMethod()); |
| ObjCInterfaceDecl *IFace = nullptr; |
| if (LookForIvars) { |
| IFace = CurMethod->getClassInterface(); |
| ObjCInterfaceDecl *ClassDeclared; |
| ObjCIvarDecl *IV = nullptr; |
| if (IFace && (IV = IFace->lookupInstanceVariable(II, ClassDeclared))) { |
| // Diagnose using an ivar in a class method. |
| if (IsClassMethod) { |
| Diag(Loc, diag::err_ivar_use_in_class_method) << IV->getDeclName(); |
| return DeclResult(true); |
| } |
| |
| // Diagnose the use of an ivar outside of the declaring class. |
| if (IV->getAccessControl() == ObjCIvarDecl::Private && |
| !declaresSameEntity(ClassDeclared, IFace) && |
| !getLangOpts().DebuggerSupport) |
| Diag(Loc, diag::err_private_ivar_access) << IV->getDeclName(); |
| |
| // Success. |
| return IV; |
| } |
| } else if (CurMethod->isInstanceMethod()) { |
| // We should warn if a local variable hides an ivar. |
| if (ObjCInterfaceDecl *IFace = CurMethod->getClassInterface()) { |
| ObjCInterfaceDecl *ClassDeclared; |
| if (ObjCIvarDecl *IV = IFace->lookupInstanceVariable(II, ClassDeclared)) { |
| if (IV->getAccessControl() != ObjCIvarDecl::Private || |
| declaresSameEntity(IFace, ClassDeclared)) |
| Diag(Loc, diag::warn_ivar_use_hidden) << IV->getDeclName(); |
| } |
| } |
| } else if (Lookup.isSingleResult() && |
| Lookup.getFoundDecl()->isDefinedOutsideFunctionOrMethod()) { |
| // If accessing a stand-alone ivar in a class method, this is an error. |
| if (const ObjCIvarDecl *IV = |
| dyn_cast<ObjCIvarDecl>(Lookup.getFoundDecl())) { |
| Diag(Loc, diag::err_ivar_use_in_class_method) << IV->getDeclName(); |
| return DeclResult(true); |
| } |
| } |
| |
| // Didn't encounter an error, didn't find an ivar. |
| return DeclResult(false); |
| } |
| |
| ExprResult Sema::BuildIvarRefExpr(Scope *S, SourceLocation Loc, |
| ObjCIvarDecl *IV) { |
| ObjCMethodDecl *CurMethod = getCurMethodDecl(); |
| assert(CurMethod && CurMethod->isInstanceMethod() && |
| "should not reference ivar from this context"); |
| |
| ObjCInterfaceDecl *IFace = CurMethod->getClassInterface(); |
| assert(IFace && "should not reference ivar from this context"); |
| |
| // If we're referencing an invalid decl, just return this as a silent |
| // error node. The error diagnostic was already emitted on the decl. |
| if (IV->isInvalidDecl()) |
| return ExprError(); |
| |
| // Check if referencing a field with __attribute__((deprecated)). |
| if (DiagnoseUseOfDecl(IV, Loc)) |
| return ExprError(); |
| |
| // FIXME: This should use a new expr for a direct reference, don't |
| // turn this into Self->ivar, just return a BareIVarExpr or something. |
| IdentifierInfo &II = Context.Idents.get("self"); |
| UnqualifiedId SelfName; |
| SelfName.setIdentifier(&II, SourceLocation()); |
| SelfName.setKind(UnqualifiedIdKind::IK_ImplicitSelfParam); |
| CXXScopeSpec SelfScopeSpec; |
| SourceLocation TemplateKWLoc; |
| ExprResult SelfExpr = |
| ActOnIdExpression(S, SelfScopeSpec, TemplateKWLoc, SelfName, |
| /*HasTrailingLParen=*/false, |
| /*IsAddressOfOperand=*/false); |
| if (SelfExpr.isInvalid()) |
| return ExprError(); |
| |
| SelfExpr = DefaultLvalueConversion(SelfExpr.get()); |
| if (SelfExpr.isInvalid()) |
| return ExprError(); |
| |
| MarkAnyDeclReferenced(Loc, IV, true); |
| |
| ObjCMethodFamily MF = CurMethod->getMethodFamily(); |
| if (MF != OMF_init && MF != OMF_dealloc && MF != OMF_finalize && |
| !IvarBacksCurrentMethodAccessor(IFace, CurMethod, IV)) |
| Diag(Loc, diag::warn_direct_ivar_access) << IV->getDeclName(); |
| |
| ObjCIvarRefExpr *Result = new (Context) |
| ObjCIvarRefExpr(IV, IV->getUsageType(SelfExpr.get()->getType()), Loc, |
| IV->getLocation(), SelfExpr.get(), true, true); |
| |
| if (IV->getType().getObjCLifetime() == Qualifiers::OCL_Weak) { |
| if (!isUnevaluatedContext() && |
| !Diags.isIgnored(diag::warn_arc_repeated_use_of_weak, Loc)) |
| getCurFunction()->recordUseOfWeak(Result); |
| } |
| if (getLangOpts().ObjCAutoRefCount) |
| if (const BlockDecl *BD = CurContext->getInnermostBlockDecl()) |
| ImplicitlyRetainedSelfLocs.push_back({Loc, BD}); |
| |
| return Result; |
| } |
| |
| /// The parser has read a name in, and Sema has detected that we're currently |
| /// inside an ObjC method. Perform some additional checks and determine if we |
| /// should form a reference to an ivar. If so, build an expression referencing |
| /// that ivar. |
| ExprResult |
| Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S, |
| IdentifierInfo *II, bool AllowBuiltinCreation) { |
| // FIXME: Integrate this lookup step into LookupParsedName. |
| DeclResult Ivar = LookupIvarInObjCMethod(Lookup, S, II); |
| if (Ivar.isInvalid()) |
| return ExprError(); |
| if (Ivar.isUsable()) |
| return BuildIvarRefExpr(S, Lookup.getNameLoc(), |
| cast<ObjCIvarDecl>(Ivar.get())); |
| |
| if (Lookup.empty() && II && AllowBuiltinCreation) |
| LookupBuiltin(Lookup); |
| |
| // Sentinel value saying that we didn't do anything special. |
| return ExprResult(false); |
| } |
| |
| /// Cast a base object to a member's actual type. |
| /// |
| /// Logically this happens in three phases: |
| /// |
| /// * First we cast from the base type to the naming class. |
| /// The naming class is the class into which we were looking |
| /// when we found the member; it's the qualifier type if a |
| /// qualifier was provided, and otherwise it's the base type. |
| /// |
| /// * Next we cast from the naming class to the declaring class. |
| /// If the member we found was brought into a class's scope by |
| /// a using declaration, this is that class; otherwise it's |
| /// the class declaring the member. |
| /// |
| /// * Finally we cast from the declaring class to the "true" |
| /// declaring class of the member. This conversion does not |
| /// obey access control. |
| ExprResult |
| Sema::PerformObjectMemberConversion(Expr *From, |
| NestedNameSpecifier *Qualifier, |
| NamedDecl *FoundDecl, |
| NamedDecl *Member) { |
| CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(Member->getDeclContext()); |
| if (!RD) |
| return From; |
| |
| QualType DestRecordType; |
| QualType DestType; |
| QualType FromRecordType; |
| QualType FromType = From->getType(); |
| bool PointerConversions = false; |
| if (isa<FieldDecl>(Member)) { |
| DestRecordType = Context.getCanonicalType(Context.getTypeDeclType(RD)); |
| auto FromPtrType = FromType->getAs<PointerType>(); |
| DestRecordType = Context.getAddrSpaceQualType( |
| DestRecordType, FromPtrType |
| ? FromType->getPointeeType().getAddressSpace() |
| : FromType.getAddressSpace()); |
| |
| if (FromPtrType) { |
| DestType = Context.getPointerType(DestRecordType); |
| FromRecordType = FromPtrType->getPointeeType(); |
| PointerConversions = true; |
| } else { |
| DestType = DestRecordType; |
| FromRecordType = FromType; |
| } |
| } else if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Member)) { |
| if (Method->isStatic()) |
| return From; |
| |
| DestType = Method->getThisType(); |
| DestRecordType = DestType->getPointeeType(); |
| |
| if (FromType->getAs<PointerType>()) { |
| FromRecordType = FromType->getPointeeType(); |
| PointerConversions = true; |
| } else { |
| FromRecordType = FromType; |
| DestType = DestRecordType; |
|