diff options
Diffstat (limited to 'lib/Sema')
-rw-r--r-- | lib/Sema/Sema.h | 15 | ||||
-rw-r--r-- | lib/Sema/SemaCXXCast.cpp | 3 | ||||
-rw-r--r-- | lib/Sema/SemaCXXScopeSpec.cpp | 131 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 148 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 81 | ||||
-rw-r--r-- | lib/Sema/SemaExprCXX.cpp | 10 | ||||
-rw-r--r-- | lib/Sema/SemaOverload.cpp | 33 | ||||
-rw-r--r-- | lib/Sema/SemaTemplate.cpp | 2 | ||||
-rw-r--r-- | lib/Sema/SemaType.cpp | 75 | ||||
-rw-r--r-- | lib/Sema/TreeTransform.h | 50 |
10 files changed, 388 insertions, 160 deletions
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 0f84b46..c4de6be 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -1609,6 +1609,9 @@ public: void DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc, Expr **Args, unsigned NumArgs); + void CheckSignCompare(Expr *LHS, Expr *RHS, SourceLocation Loc, + const PartialDiagnostic &PD); + virtual ExpressionEvaluationContext PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext); @@ -1667,6 +1670,8 @@ public: OwningExprResult CreateBuiltinUnaryOp(SourceLocation OpLoc, unsigned OpcIn, ExprArg InputArg); + OwningExprResult BuildUnaryOp(Scope *S, SourceLocation OpLoc, + UnaryOperator::Opcode Opc, ExprArg input); virtual OwningExprResult ActOnUnaryOp(Scope *S, SourceLocation OpLoc, tok::TokenKind Op, ExprArg Input); @@ -1792,6 +1797,9 @@ public: virtual OwningExprResult ActOnBinOp(Scope *S, SourceLocation TokLoc, tok::TokenKind Kind, ExprArg LHS, ExprArg RHS); + OwningExprResult BuildBinOp(Scope *S, SourceLocation OpLoc, + BinaryOperator::Opcode Opc, + Expr *lhs, Expr *rhs); OwningExprResult CreateBuiltinBinOp(SourceLocation TokLoc, unsigned Opc, Expr *lhs, Expr *rhs); @@ -1893,9 +1901,7 @@ public: AccessSpecifier AS, SourceLocation UsingLoc, const CXXScopeSpec &SS, - SourceLocation IdentLoc, - IdentifierInfo *TargetName, - OverloadedOperatorKind Op, + UnqualifiedId &Name, AttributeList *AttrList, bool IsTypeName); @@ -3645,7 +3651,8 @@ public: Ref_Compatible }; - ReferenceCompareResult CompareReferenceRelationship(QualType T1, QualType T2, + ReferenceCompareResult CompareReferenceRelationship(SourceLocation Loc, + QualType T1, QualType T2, bool& DerivedToBase); bool CheckReferenceInit(Expr *&simpleInit_or_initList, QualType declType, diff --git a/lib/Sema/SemaCXXCast.cpp b/lib/Sema/SemaCXXCast.cpp index 8bb3348..76faddaa 100644 --- a/lib/Sema/SemaCXXCast.cpp +++ b/lib/Sema/SemaCXXCast.cpp @@ -527,7 +527,8 @@ TryLValueToRValueCast(Sema &Self, Expr *SrcExpr, QualType DestType, // this is the only cast possibility, so we issue an error if we fail now. // FIXME: Should allow casting away constness if CStyle. bool DerivedToBase; - if (Self.CompareReferenceRelationship(SrcExpr->getType(), R->getPointeeType(), + if (Self.CompareReferenceRelationship(SrcExpr->getLocStart(), + SrcExpr->getType(), R->getPointeeType(), DerivedToBase) < Sema::Ref_Compatible_With_Added_Qualification) { msg = diag::err_bad_lvalue_to_rvalue_cast; diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp index 10c138c..ce3fb5f 100644 --- a/lib/Sema/SemaCXXScopeSpec.cpp +++ b/lib/Sema/SemaCXXScopeSpec.cpp @@ -22,6 +22,72 @@ #include "llvm/Support/raw_ostream.h" using namespace clang; +/// \brief Find the current instantiation that associated with the given type. +static CXXRecordDecl * +getCurrentInstantiationOf(ASTContext &Context, DeclContext *CurContext, + QualType T) { + if (T.isNull()) + return 0; + + T = Context.getCanonicalType(T); + + for (DeclContext *Ctx = CurContext; Ctx; Ctx = Ctx->getParent()) { + // If we've hit a namespace or the global scope, then the + // nested-name-specifier can't refer to the current instantiation. + if (Ctx->isFileContext()) + return 0; + + // Skip non-class contexts. + CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Ctx); + if (!Record) + continue; + + // If this record type is not dependent, + if (!Record->isDependentType()) + return 0; + + // C++ [temp.dep.type]p1: + // + // In the definition of a class template, a nested class of a + // class template, a member of a class template, or a member of a + // nested class of a class template, a name refers to the current + // instantiation if it is + // -- the injected-class-name (9) of the class template or + // nested class, + // -- in the definition of a primary class template, the name + // of the class template followed by the template argument + // list of the primary template (as described below) + // enclosed in <>, + // -- in the definition of a nested class of a class template, + // the name of the nested class referenced as a member of + // the current instantiation, or + // -- in the definition of a partial specialization, the name + // of the class template followed by the template argument + // list of the partial specialization enclosed in <>. If + // the nth template parameter is a parameter pack, the nth + // template argument is a pack expansion (14.6.3) whose + // pattern is the name of the parameter pack. + // (FIXME: parameter packs) + // + // All of these options come down to having the + // nested-name-specifier type that is equivalent to the + // injected-class-name of one of the types that is currently in + // our context. + if (Context.getCanonicalType(Context.getTypeDeclType(Record)) == T) + return Record; + + if (ClassTemplateDecl *Template = Record->getDescribedClassTemplate()) { + QualType InjectedClassName + = Template->getInjectedClassNameType(Context); + if (T == Context.getCanonicalType(InjectedClassName)) + return Template->getTemplatedDecl(); + } + // FIXME: check for class template partial specializations + } + + return 0; +} + /// \brief Compute the DeclContext that is associated with the given type. /// /// \param T the type for which we are attempting to find a DeclContext. @@ -33,7 +99,7 @@ DeclContext *Sema::computeDeclContext(QualType T) { if (const TagType *Tag = T->getAs<TagType>()) return Tag->getDecl(); - return 0; + return ::getCurrentInstantiationOf(Context, CurContext, T); } /// \brief Compute the DeclContext that is associated with the given @@ -156,68 +222,7 @@ CXXRecordDecl *Sema::getCurrentInstantiationOf(NestedNameSpecifier *NNS) { return 0; QualType T = QualType(NNS->getAsType(), 0); - // If the nested name specifier does not refer to a type, then it - // does not refer to the current instantiation. - if (T.isNull()) - return 0; - - T = Context.getCanonicalType(T); - - for (DeclContext *Ctx = CurContext; Ctx; Ctx = Ctx->getParent()) { - // If we've hit a namespace or the global scope, then the - // nested-name-specifier can't refer to the current instantiation. - if (Ctx->isFileContext()) - return 0; - - // Skip non-class contexts. - CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Ctx); - if (!Record) - continue; - - // If this record type is not dependent, - if (!Record->isDependentType()) - return 0; - - // C++ [temp.dep.type]p1: - // - // In the definition of a class template, a nested class of a - // class template, a member of a class template, or a member of a - // nested class of a class template, a name refers to the current - // instantiation if it is - // -- the injected-class-name (9) of the class template or - // nested class, - // -- in the definition of a primary class template, the name - // of the class template followed by the template argument - // list of the primary template (as described below) - // enclosed in <>, - // -- in the definition of a nested class of a class template, - // the name of the nested class referenced as a member of - // the current instantiation, or - // -- in the definition of a partial specialization, the name - // of the class template followed by the template argument - // list of the partial specialization enclosed in <>. If - // the nth template parameter is a parameter pack, the nth - // template argument is a pack expansion (14.6.3) whose - // pattern is the name of the parameter pack. - // (FIXME: parameter packs) - // - // All of these options come down to having the - // nested-name-specifier type that is equivalent to the - // injected-class-name of one of the types that is currently in - // our context. - if (Context.getCanonicalType(Context.getTypeDeclType(Record)) == T) - return Record; - - if (ClassTemplateDecl *Template = Record->getDescribedClassTemplate()) { - QualType InjectedClassName - = Template->getInjectedClassNameType(Context); - if (T == Context.getCanonicalType(InjectedClassName)) - return Template->getTemplatedDecl(); - } - // FIXME: check for class template partial specializations - } - - return 0; + return ::getCurrentInstantiationOf(Context, CurContext, T); } /// \brief Require that the context specified by SS be complete. diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index bc25513..b8977cf 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -971,10 +971,70 @@ Sema::ActOnMemInitializer(DeclPtrTy ConstructorD, RParenLoc, ClassDecl); } +/// Checks an initializer expression for use of uninitialized fields, such as +/// containing the field that is being initialized. Returns true if there is an +/// uninitialized field was used an updates the SourceLocation parameter; false +/// otherwise. +static bool InitExprContainsUninitializedFields(const Stmt* S, + const FieldDecl* LhsField, + SourceLocation* L) { + const MemberExpr* ME = dyn_cast<MemberExpr>(S); + if (ME) { + const NamedDecl* RhsField = ME->getMemberDecl(); + if (RhsField == LhsField) { + // Initializing a field with itself. Throw a warning. + // But wait; there are exceptions! + // Exception #1: The field may not belong to this record. + // e.g. Foo(const Foo& rhs) : A(rhs.A) {} + const Expr* base = ME->getBase(); + if (base != NULL && !isa<CXXThisExpr>(base->IgnoreParenCasts())) { + // Even though the field matches, it does not belong to this record. + return false; + } + // None of the exceptions triggered; return true to indicate an + // uninitialized field was used. + *L = ME->getMemberLoc(); + return true; + } + } + bool found = false; + for (Stmt::const_child_iterator it = S->child_begin(); + it != S->child_end() && found == false; + ++it) { + if (isa<CallExpr>(S)) { + // Do not descend into function calls or constructors, as the use + // of an uninitialized field may be valid. One would have to inspect + // the contents of the function/ctor to determine if it is safe or not. + // i.e. Pass-by-value is never safe, but pass-by-reference and pointers + // may be safe, depending on what the function/ctor does. + continue; + } + found = InitExprContainsUninitializedFields(*it, LhsField, L); + } + return found; +} + Sema::MemInitResult Sema::BuildMemberInitializer(FieldDecl *Member, Expr **Args, unsigned NumArgs, SourceLocation IdLoc, SourceLocation RParenLoc) { + // Diagnose value-uses of fields to initialize themselves, e.g. + // foo(foo) + // where foo is not also a parameter to the constructor. + // TODO: implement -Wuninitialized and fold this into that framework. + for (unsigned i = 0; i < NumArgs; ++i) { + SourceLocation L; + if (InitExprContainsUninitializedFields(Args[i], Member, &L)) { + // FIXME: Return true in the case when other fields are used before being + // uninitialized. For example, let this field be the i'th field. When + // initializing the i'th field, throw a warning if any of the >= i'th + // fields are used, as they are not yet initialized. + // Right now we are only handling the case where the i'th field uses + // itself in its initializer. + Diag(L, diag::warn_field_is_uninit); + } + } + bool HasDependentArg = false; for (unsigned i = 0; i < NumArgs; i++) HasDependentArg |= Args[i]->isTypeDependent(); @@ -985,7 +1045,9 @@ Sema::BuildMemberInitializer(FieldDecl *Member, Expr **Args, FieldType = Array->getElementType(); if (FieldType->isDependentType()) { // Can't check init for dependent type. - } else if (FieldType->getAs<RecordType>()) { + } else if (FieldType->isRecordType()) { + // Member is a record (struct/union/class), so pass the initializer + // arguments down to the record's constructor. if (!HasDependentArg) { ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this); @@ -1005,6 +1067,8 @@ Sema::BuildMemberInitializer(FieldDecl *Member, Expr **Args, } } } else if (NumArgs != 1 && NumArgs != 0) { + // The member type is not a record type (or an array of record + // types), so it can be only be default- or copy-initialized. return Diag(IdLoc, diag::err_mem_initializer_mismatch) << Member->getDeclName() << SourceRange(IdLoc, RParenLoc); } else if (!HasDependentArg) { @@ -1158,7 +1222,7 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor, // On seeing one dependent type, we should essentially exit this routine // while preserving user-declared initializer list. When this routine is // called during instantiatiation process, this routine will rebuild the - // oderdered initializer list correctly. + // ordered initializer list correctly. // If we have a dependent base initialization, we can't determine the // association between initializers and bases; just dump the known @@ -1293,11 +1357,16 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor, continue; } + if ((*Field)->getType()->isDependentType()) { + Fields.push_back(*Field); + continue; + } + QualType FT = Context.getBaseElementType((*Field)->getType()); if (const RecordType* RT = FT->getAs<RecordType>()) { CXXConstructorDecl *Ctor = cast<CXXRecordDecl>(RT->getDecl())->getDefaultConstructor(Context); - if (!Ctor && !FT->isDependentType()) { + if (!Ctor) { Fields.push_back(*Field); continue; } @@ -1357,12 +1426,16 @@ Sema::BuildBaseOrMemberInitializers(ASTContext &C, SetBaseOrMemberInitializers(Constructor, Initializers, NumInitializers, Bases, Members); - for (unsigned int i = 0; i < Bases.size(); i++) - Diag(Bases[i]->getSourceRange().getBegin(), - diag::err_missing_default_constructor) << 0 << Bases[i]->getType(); - for (unsigned int i = 0; i < Members.size(); i++) - Diag(Members[i]->getLocation(), diag::err_missing_default_constructor) - << 1 << Members[i]->getType(); + for (unsigned int i = 0; i < Bases.size(); i++) { + if (!Bases[i]->getType()->isDependentType()) + Diag(Bases[i]->getSourceRange().getBegin(), + diag::err_missing_default_constructor) << 0 << Bases[i]->getType(); + } + for (unsigned int i = 0; i < Members.size(); i++) { + if (!Members[i]->getType()->isDependentType()) + Diag(Members[i]->getLocation(), diag::err_missing_default_constructor) + << 1 << Members[i]->getType(); + } } static void *GetKeyForTopLevelField(FieldDecl *Field) { @@ -1405,6 +1478,7 @@ static void *GetKeyForMember(CXXBaseOrMemberInitializer *Member, return GetKeyForBase(QualType(Member->getBaseClass(), 0)); } +/// ActOnMemInitializers - Handle the member initializers for a constructor. void Sema::ActOnMemInitializers(DeclPtrTy ConstructorDecl, SourceLocation ColonLoc, MemInitTy **MemInits, unsigned NumMemInits) { @@ -2700,22 +2774,37 @@ Sema::DeclPtrTy Sema::ActOnUsingDeclaration(Scope *S, AccessSpecifier AS, SourceLocation UsingLoc, const CXXScopeSpec &SS, - SourceLocation IdentLoc, - IdentifierInfo *TargetName, - OverloadedOperatorKind Op, + UnqualifiedId &Name, AttributeList *AttrList, bool IsTypeName) { - assert((TargetName || Op) && "Invalid TargetName."); assert(S->getFlags() & Scope::DeclScope && "Invalid Scope."); - DeclarationName Name; - if (TargetName) - Name = TargetName; - else - Name = Context.DeclarationNames.getCXXOperatorName(Op); - - NamedDecl *UD = BuildUsingDeclaration(UsingLoc, SS, IdentLoc, - Name, AttrList, IsTypeName); + switch (Name.getKind()) { + case UnqualifiedId::IK_Identifier: + case UnqualifiedId::IK_OperatorFunctionId: + case UnqualifiedId::IK_ConversionFunctionId: + break; + + case UnqualifiedId::IK_ConstructorName: + Diag(Name.getSourceRange().getBegin(), diag::err_using_decl_constructor) + << SS.getRange(); + return DeclPtrTy(); + + case UnqualifiedId::IK_DestructorName: + Diag(Name.getSourceRange().getBegin(), diag::err_using_decl_destructor) + << SS.getRange(); + return DeclPtrTy(); + + case UnqualifiedId::IK_TemplateId: + Diag(Name.getSourceRange().getBegin(), diag::err_using_decl_template_id) + << SourceRange(Name.TemplateId->LAngleLoc, Name.TemplateId->RAngleLoc); + return DeclPtrTy(); + } + + DeclarationName TargetName = GetNameFromUnqualifiedId(Name); + NamedDecl *UD = BuildUsingDeclaration(UsingLoc, SS, + Name.getSourceRange().getBegin(), + TargetName, AttrList, IsTypeName); if (UD) { PushOnScopeChains(UD, S); UD->setAccess(AS); @@ -3515,14 +3604,15 @@ Sema::CompleteConstructorCall(CXXConstructorDecl *Constructor, /// type, and the first type (T1) is the pointee type of the reference /// type being initialized. Sema::ReferenceCompareResult -Sema::CompareReferenceRelationship(QualType T1, QualType T2, +Sema::CompareReferenceRelationship(SourceLocation Loc, + QualType OrigT1, QualType OrigT2, bool& DerivedToBase) { - assert(!T1->isReferenceType() && + assert(!OrigT1->isReferenceType() && "T1 must be the pointee type of the reference type"); - assert(!T2->isReferenceType() && "T2 cannot be a reference type"); + assert(!OrigT2->isReferenceType() && "T2 cannot be a reference type"); - T1 = Context.getCanonicalType(T1); - T2 = Context.getCanonicalType(T2); + QualType T1 = Context.getCanonicalType(OrigT1); + QualType T2 = Context.getCanonicalType(OrigT2); QualType UnqualT1 = T1.getUnqualifiedType(); QualType UnqualT2 = T2.getUnqualifiedType(); @@ -3532,7 +3622,9 @@ Sema::CompareReferenceRelationship(QualType T1, QualType T2, // T1 is a base class of T2. if (UnqualT1 == UnqualT2) DerivedToBase = false; - else if (IsDerivedFrom(UnqualT2, UnqualT1)) + else if (!RequireCompleteType(Loc, OrigT1, PDiag()) && + !RequireCompleteType(Loc, OrigT2, PDiag()) && + IsDerivedFrom(UnqualT2, UnqualT1)) DerivedToBase = true; else return Ref_Incompatible; @@ -3608,7 +3700,7 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType, Expr::isLvalueResult InitLvalue = ForceRValue ? Expr::LV_InvalidExpression : Init->isLvalue(Context); ReferenceCompareResult RefRelationship - = CompareReferenceRelationship(T1, T2, DerivedToBase); + = CompareReferenceRelationship(DeclLoc, T1, T2, DerivedToBase); // Most paths end in a failed conversion. if (ICS) diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index ac7cced..f1d6f2b 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -3340,6 +3340,8 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, if (getLangOptions().CPlusPlus) return CXXCheckConditionalOperands(Cond, LHS, RHS, QuestionLoc); + CheckSignCompare(LHS, RHS, QuestionLoc, diag::warn_mixed_sign_conditional); + UsualUnaryConversions(Cond); UsualUnaryConversions(LHS); UsualUnaryConversions(RHS); @@ -4427,6 +4429,41 @@ QualType Sema::CheckShiftOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, return LHSTy; } +/// Implements -Wsign-compare. +void Sema::CheckSignCompare(Expr *lex, Expr *rex, SourceLocation OpLoc, + const PartialDiagnostic &PD) { + QualType lt = lex->getType(), rt = rex->getType(); + + // Only warn if both operands are integral. + if (!lt->isIntegerType() || !rt->isIntegerType()) + return; + + // The rule is that the signed operand becomes unsigned, so isolate the + // signed operand. + Expr *signedOperand; + if (lt->isSignedIntegerType()) { + if (rt->isSignedIntegerType()) return; + signedOperand = lex; + } else { + if (!rt->isSignedIntegerType()) return; + signedOperand = rex; + } + + // If the value is a non-negative integer constant, then the + // signed->unsigned conversion won't change it. + llvm::APSInt value; + if (signedOperand->isIntegerConstantExpr(value, Context)) { + assert(value.isSigned() && "result of signed expression not signed"); + + if (value.isNonNegative()) + return; + } + + Diag(OpLoc, PD) + << lex->getType() << rex->getType() + << lex->getSourceRange() << rex->getSourceRange(); +} + // C99 6.5.8, C++ [expr.rel] QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, unsigned OpaqueOpc, bool isRelational) { @@ -4435,6 +4472,8 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, if (lex->getType()->isVectorType() || rex->getType()->isVectorType()) return CheckVectorCompareOperands(lex, rex, Loc, isRelational); + CheckSignCompare(lex, rex, Loc, diag::warn_mixed_sign_comparison); + // C99 6.5.8p3 / C99 6.5.9p4 if (lex->getType()->isArithmeticType() && rex->getType()->isArithmeticType()) UsualArithmeticConversions(lex, rex); @@ -5472,6 +5511,12 @@ Action::OwningExprResult Sema::ActOnBinOp(Scope *S, SourceLocation TokLoc, // Emit warnings for tricky precedence issues, e.g. "bitfield & 0x4 == 0" DiagnoseBinOpPrecedence(*this, Opc, TokLoc, lhs, rhs); + return BuildBinOp(S, TokLoc, Opc, lhs, rhs); +} + +Action::OwningExprResult Sema::BuildBinOp(Scope *S, SourceLocation OpLoc, + BinaryOperator::Opcode Opc, + Expr *lhs, Expr *rhs) { if (getLangOptions().CPlusPlus && (lhs->getType()->isOverloadableType() || rhs->getType()->isOverloadableType())) { @@ -5482,21 +5527,22 @@ Action::OwningExprResult Sema::ActOnBinOp(Scope *S, SourceLocation TokLoc, FunctionSet Functions; OverloadedOperatorKind OverOp = BinaryOperator::getOverloadedOperator(Opc); if (OverOp != OO_None) { - LookupOverloadedOperatorName(OverOp, S, lhs->getType(), rhs->getType(), - Functions); + if (S) + LookupOverloadedOperatorName(OverOp, S, lhs->getType(), rhs->getType(), + Functions); Expr *Args[2] = { lhs, rhs }; DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(OverOp); ArgumentDependentLookup(OpName, /*Operator*/true, Args, 2, Functions); } - + // Build the (potentially-overloaded, potentially-dependent) // binary operation. - return CreateOverloadedBinOp(TokLoc, Opc, Functions, lhs, rhs); + return CreateOverloadedBinOp(OpLoc, Opc, Functions, lhs, rhs); } - + // Build a built-in binary operation. - return CreateBuiltinBinOp(TokLoc, Opc, lhs, rhs); + return CreateBuiltinBinOp(OpLoc, Opc, lhs, rhs); } Action::OwningExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, @@ -5587,12 +5633,10 @@ Action::OwningExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, return Owned(new (Context) UnaryOperator(Input, Opc, resultType, OpLoc)); } -// Unary Operators. 'Tok' is the token for the operator. -Action::OwningExprResult Sema::ActOnUnaryOp(Scope *S, SourceLocation OpLoc, - tok::TokenKind Op, ExprArg input) { +Action::OwningExprResult Sema::BuildUnaryOp(Scope *S, SourceLocation OpLoc, + UnaryOperator::Opcode Opc, + ExprArg input) { Expr *Input = (Expr*)input.get(); - UnaryOperator::Opcode Opc = ConvertTokenKindToUnaryOpcode(Op); - if (getLangOptions().CPlusPlus && Input->getType()->isOverloadableType()) { // Find all of the overloaded operators visible from this // point. We perform both an operator-name lookup from the local @@ -5601,19 +5645,26 @@ Action::OwningExprResult Sema::ActOnUnaryOp(Scope *S, SourceLocation OpLoc, FunctionSet Functions; OverloadedOperatorKind OverOp = UnaryOperator::getOverloadedOperator(Opc); if (OverOp != OO_None) { - LookupOverloadedOperatorName(OverOp, S, Input->getType(), QualType(), - Functions); + if (S) + LookupOverloadedOperatorName(OverOp, S, Input->getType(), QualType(), + Functions); DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(OverOp); ArgumentDependentLookup(OpName, /*Operator*/true, &Input, 1, Functions); } - + return CreateOverloadedUnaryOp(OpLoc, Opc, Functions, move(input)); } - + return CreateBuiltinUnaryOp(OpLoc, Opc, move(input)); } +// Unary Operators. 'Tok' is the token for the operator. +Action::OwningExprResult Sema::ActOnUnaryOp(Scope *S, SourceLocation OpLoc, + tok::TokenKind Op, ExprArg input) { + return BuildUnaryOp(S, OpLoc, ConvertTokenKindToUnaryOpcode(Op), move(input)); +} + /// ActOnAddrLabel - Parse the GNU address of label extension: "&&foo". Sema::OwningExprResult Sema::ActOnAddrLabel(SourceLocation OpLoc, SourceLocation LabLoc, diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 4868c14..dc57681 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -1603,6 +1603,8 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, if (LHS->isTypeDependent() || RHS->isTypeDependent()) return Context.DependentTy; + CheckSignCompare(LHS, RHS, QuestionLoc, diag::warn_mixed_sign_conditional); + // C++0x 5.16p2 // If either the second or the third operand has type (cv) void, ... QualType LTy = LHS->getType(); @@ -2030,7 +2032,13 @@ Sema::ActOnStartCXXMemberReference(Scope *S, ExprArg Base, SourceLocation OpLoc, QualType BaseType = BaseExpr->getType(); if (BaseType->isDependentType()) { - // FIXME: member of the current instantiation + // If we have a pointer to a dependent type and are using the -> operator, + // the object type is the type that the pointer points to. We might still + // have enough information about that type to do something useful. + if (OpKind == tok::arrow) + if (const PointerType *Ptr = BaseType->getAs<PointerType>()) + BaseType = Ptr->getPointeeType(); + ObjectType = BaseType.getAsOpaquePtr(); return move(Base); } diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 946e282..3e6778b 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -1387,8 +1387,10 @@ Sema::OverloadingResult Sema::IsUserDefinedConversion( bool AllowExplicit, bool ForceRValue, bool UserCast) { if (const RecordType *ToRecordType = ToType->getAs<RecordType>()) { - if (CXXRecordDecl *ToRecordDecl - = dyn_cast<CXXRecordDecl>(ToRecordType->getDecl())) { + if (RequireCompleteType(From->getLocStart(), ToType, PDiag())) { + // We're not going to find any constructors. + } else if (CXXRecordDecl *ToRecordDecl + = dyn_cast<CXXRecordDecl>(ToRecordType->getDecl())) { // C++ [over.match.ctor]p1: // When objects of class type are direct-initialized (8.5), or // copy-initialized from an expression of the same or a @@ -2097,8 +2099,8 @@ Sema::TryObjectArgumentInitialization(Expr *From, CXXMethodDecl *Method) { // First check the qualifiers. We don't care about lvalue-vs-rvalue // with the implicit object parameter (C++ [over.match.funcs]p5). QualType FromTypeCanon = Context.getCanonicalType(FromType); - if (ImplicitParamType.getCVRQualifiers() != FromType.getCVRQualifiers() && - !ImplicitParamType.isAtLeastAsQualifiedAs(FromType)) + if (ImplicitParamType.getCVRQualifiers() != FromTypeCanon.getCVRQualifiers() && + !ImplicitParamType.isAtLeastAsQualifiedAs(FromTypeCanon)) return ICS; // Check that we have either the same type or a derived type. It @@ -3050,6 +3052,10 @@ BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty, // We don't care about qualifiers on the type. Ty = Ty.getUnqualifiedType(); + // If we're dealing with an array type, decay to the pointer. + if (Ty->isArrayType()) + Ty = SemaRef.Context.getArrayDecayedType(Ty); + if (const PointerType *PointerTy = Ty->getAs<PointerType>()) { QualType PointeeTy = PointerTy->getPointeeType(); @@ -4787,11 +4793,20 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, // If either side is type-dependent, create an appropriate dependent // expression. if (Args[0]->isTypeDependent() || Args[1]->isTypeDependent()) { - // .* cannot be overloaded. - if (Opc == BinaryOperator::PtrMemD) - return Owned(new (Context) BinaryOperator(Args[0], Args[1], Opc, - Context.DependentTy, OpLoc)); - + if (Functions.empty()) { + // If there are no functions to store, just build a dependent + // BinaryOperator or CompoundAssignment. + if (Opc <= BinaryOperator::Assign || Opc > BinaryOperator::OrAssign) + return Owned(new (Context) BinaryOperator(Args[0], Args[1], Opc, + Context.DependentTy, OpLoc)); + + return Owned(new (Context) CompoundAssignOperator(Args[0], Args[1], Opc, + Context.DependentTy, + Context.DependentTy, + Context.DependentTy, + OpLoc)); + } + OverloadedFunctionDecl *Overloads = OverloadedFunctionDecl::Create(Context, CurContext, OpName); for (FunctionSet::iterator Func = Functions.begin(), diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 3c56358..5ef3701 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -1995,7 +1995,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, ArgType = Context.getCanonicalType(ArgType).getUnqualifiedType(); // Try to convert the argument to the parameter's type. - if (ParamType == ArgType) { + if (Context.hasSameType(ParamType, ArgType)) { // Okay: no conversion necessary } else if (IsIntegralPromotion(Arg, ArgType, ParamType) || !ParamType->isEnumeralType()) { diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index 0003b1b..f003127 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -22,6 +22,7 @@ #include "clang/Basic/PartialDiagnostic.h" #include "clang/Parse/DeclSpec.h" #include "llvm/ADT/SmallPtrSet.h" +#include "llvm/Support/ErrorHandling.h" using namespace clang; /// \brief Perform adjustment on the parameter type of a function. @@ -562,9 +563,17 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM, SourceLocation Loc = Brackets.getBegin(); // C99 6.7.5.2p1: If the element type is an incomplete or function type, // reject it (e.g. void ary[7], struct foo ary[7], void ary[7]()) - if (RequireCompleteType(Loc, T, - diag::err_illegal_decl_array_incomplete_type)) - return QualType(); + // Not in C++, though. There we only dislike void. + if (getLangOptions().CPlusPlus) { + if (T->isVoidType()) { + Diag(Loc, diag::err_illegal_decl_array_incomplete_type) << T; + return QualType(); + } + } else { + if (RequireCompleteType(Loc, T, + diag::err_illegal_decl_array_incomplete_type)) + return QualType(); + } if (T->isFunctionType()) { Diag(Loc, diag::err_illegal_decl_array_of_functions) @@ -612,24 +621,24 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM, } else if (ArraySize->isValueDependent()) { T = Context.getDependentSizedArrayType(T, ArraySize, ASM, Quals, Brackets); } else if (!ArraySize->isIntegerConstantExpr(ConstVal, Context) || - (!T->isDependentType() && !T->isConstantSizeType())) { + (!T->isDependentType() && !T->isIncompleteType() && + !T->isConstantSizeType())) { // Per C99, a variable array is an array with either a non-constant // size or an element type that has a non-constant-size T = Context.getVariableArrayType(T, ArraySize, ASM, Quals, Brackets); } else { // C99 6.7.5.2p1: If the expression is a constant expression, it shall // have a value greater than zero. - if (ConstVal.isSigned()) { - if (ConstVal.isNegative()) { - Diag(ArraySize->getLocStart(), - diag::err_typecheck_negative_array_size) - << ArraySize->getSourceRange(); - return QualType(); - } else if (ConstVal == 0) { - // GCC accepts zero sized static arrays. - Diag(ArraySize->getLocStart(), diag::ext_typecheck_zero_array_size) - << ArraySize->getSourceRange(); - } + if (ConstVal.isSigned() && ConstVal.isNegative()) { + Diag(ArraySize->getLocStart(), + diag::err_typecheck_negative_array_size) + << ArraySize->getSourceRange(); + return QualType(); + } + if (ConstVal == 0) { + // GCC accepts zero sized static arrays. + Diag(ArraySize->getLocStart(), diag::ext_typecheck_zero_array_size) + << ArraySize->getSourceRange(); } T = Context.getConstantArrayType(T, ConstVal, ASM, Quals); } @@ -1162,15 +1171,29 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, } // The scope spec must refer to a class, or be dependent. QualType ClsType; - if (isDependentScopeSpecifier(DeclType.Mem.Scope())) { + if (isDependentScopeSpecifier(DeclType.Mem.Scope()) + || dyn_cast_or_null<CXXRecordDecl>( + computeDeclContext(DeclType.Mem.Scope()))) { NestedNameSpecifier *NNS = (NestedNameSpecifier *)DeclType.Mem.Scope().getScopeRep(); - assert(NNS->getAsType() && "Nested-name-specifier must name a type"); - ClsType = QualType(NNS->getAsType(), 0); - } else if (CXXRecordDecl *RD - = dyn_cast_or_null<CXXRecordDecl>( - computeDeclContext(DeclType.Mem.Scope()))) { - ClsType = Context.getTagDeclType(RD); + NestedNameSpecifier *NNSPrefix = NNS->getPrefix(); + switch (NNS->getKind()) { + case NestedNameSpecifier::Identifier: + ClsType = Context.getTypenameType(NNSPrefix, NNS->getAsIdentifier()); + break; + + case NestedNameSpecifier::Namespace: + case NestedNameSpecifier::Global: + llvm::llvm_unreachable("Nested-name-specifier must name a type"); + break; + + case NestedNameSpecifier::TypeSpec: + case NestedNameSpecifier::TypeSpecWithTemplate: + ClsType = QualType(NNS->getAsType(), 0); + if (NNSPrefix) + ClsType = Context.getQualifiedNameType(NNSPrefix, ClsType); + break; + } } else { Diag(DeclType.Mem.Scope().getBeginLoc(), diag::err_illegal_decl_mempointer_in_nonclass) @@ -1677,8 +1700,12 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T, return false; // If we have a class template specialization or a class member of a - // class template specialization, try to instantiate it. - if (const RecordType *Record = T->getAs<RecordType>()) { + // class template specialization, or an array with known size of such, + // try to instantiate it. + QualType MaybeTemplate = T; + if (const ConstantArrayType *Array = T->getAs<ConstantArrayType>()) + MaybeTemplate = Array->getElementType(); + if (const RecordType *Record = MaybeTemplate->getAs<RecordType>()) { if (ClassTemplateSpecializationDecl *ClassTemplateSpec = dyn_cast<ClassTemplateSpecializationDecl>(Record->getDecl())) { if (ClassTemplateSpec->getSpecializationKind() == TSK_Undeclared) diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index 5713da9..767725a 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -877,7 +877,7 @@ public: OwningExprResult RebuildUnaryOperator(SourceLocation OpLoc, UnaryOperator::Opcode Opc, ExprArg SubExpr) { - return getSema().CreateBuiltinUnaryOp(OpLoc, Opc, move(SubExpr)); + return getSema().BuildUnaryOp(/*Scope=*/0, OpLoc, Opc, move(SubExpr)); } /// \brief Build a new sizeof or alignof expression with a type argument. @@ -941,7 +941,13 @@ public: NestedNameSpecifier *Qualifier, SourceRange QualifierRange, SourceLocation MemberLoc, - NamedDecl *Member) { + NamedDecl *Member, + bool HasExplicitTemplateArgs, + SourceLocation LAngleLoc, + const TemplateArgumentLoc *ExplicitTemplateArgs, + unsigned NumExplicitTemplateArgs, + SourceLocation RAngleLoc, + NamedDecl *FirstQualifierInScope) { if (!Member->getDeclName()) { // We have a reference to an unnamed field. assert(!Qualifier && "Can't have an unnamed field with a qualifier!"); @@ -963,8 +969,14 @@ public: isArrow? tok::arrow : tok::period, MemberLoc, Member->getDeclName(), + HasExplicitTemplateArgs, + LAngleLoc, + ExplicitTemplateArgs, + NumExplicitTemplateArgs, + RAngleLoc, /*FIXME?*/Sema::DeclPtrTy::make((Decl*)0), - &SS); + &SS, + FirstQualifierInScope); } /// \brief Build a new binary operator expression. @@ -974,15 +986,8 @@ public: OwningExprResult RebuildBinaryOperator(SourceLocation OpLoc, BinaryOperator::Opcode Opc, ExprArg LHS, ExprArg RHS) { - OwningExprResult Result - = getSema().CreateBuiltinBinOp(OpLoc, Opc, (Expr *)LHS.get(), - (Expr *)RHS.get()); - if (Result.isInvalid()) - return SemaRef.ExprError(); - - LHS.release(); - RHS.release(); - return move(Result); + return getSema().BuildBinOp(/*Scope=*/0, OpLoc, Opc, + LHS.takeAs<Expr>(), RHS.takeAs<Expr>()); } /// \brief Build a new conditional operator expression. @@ -3656,9 +3661,20 @@ TreeTransform<Derived>::TransformMemberExpr(MemberExpr *E, if (!getDerived().AlwaysRebuild() && Base.get() == E->getBase() && Qualifier == E->getQualifier() && - Member == E->getMemberDecl()) + Member == E->getMemberDecl() && + !E->hasExplicitTemplateArgumentList()) return SemaRef.Owned(E->Retain()); + llvm::SmallVector<TemplateArgumentLoc, 4> TransArgs; + if (E->hasExplicitTemplateArgumentList()) { + TransArgs.resize(E->getNumTemplateArgs()); + for (unsigned I = 0, N = E->getNumTemplateArgs(); I != N; ++I) { + if (getDerived().TransformTemplateArgument(E->getTemplateArgs()[I], + TransArgs[I])) + return SemaRef.ExprError(); + } + } + // FIXME: Bogus source location for the operator SourceLocation FakeOperatorLoc = SemaRef.PP.getLocForEndOfToken(E->getBase()->getSourceRange().getEnd()); @@ -3668,7 +3684,13 @@ TreeTransform<Derived>::TransformMemberExpr(MemberExpr *E, Qualifier, E->getQualifierRange(), E->getMemberLoc(), - Member); + Member, + E->hasExplicitTemplateArgumentList(), + E->getLAngleLoc(), + TransArgs.data(), + TransArgs.size(), + E->getRAngleLoc(), + 0); } template<typename Derived> |