diff options
author | dim <dim@FreeBSD.org> | 2011-06-12 18:01:31 +0000 |
---|---|---|
committer | dim <dim@FreeBSD.org> | 2011-06-12 18:01:31 +0000 |
commit | d4c7939beafe09c033866ebd290e274af0cc826d (patch) | |
tree | a9b264321873e7d25e69b8671c9f705ebc6d30ee /contrib/llvm/tools/clang/lib | |
parent | b164882ef981a8ed5c085469231831e221fa1323 (diff) | |
parent | ece02cd5829cea836e9365b0845a8ef042d17b0a (diff) | |
download | FreeBSD-src-d4c7939beafe09c033866ebd290e274af0cc826d.zip FreeBSD-src-d4c7939beafe09c033866ebd290e274af0cc826d.tar.gz |
Upgrade our copy of llvm/clang to r132879, from upstream's trunk.
Diffstat (limited to 'contrib/llvm/tools/clang/lib')
163 files changed, 11672 insertions, 4954 deletions
diff --git a/contrib/llvm/tools/clang/lib/AST/APValue.cpp b/contrib/llvm/tools/clang/lib/AST/APValue.cpp index 731d5e0..ebe99b1 100644 --- a/contrib/llvm/tools/clang/lib/AST/APValue.cpp +++ b/contrib/llvm/tools/clang/lib/AST/APValue.cpp @@ -18,12 +18,12 @@ using namespace clang; namespace { struct LV { - Expr* Base; + const Expr* Base; CharUnits Offset; }; } -APValue::APValue(Expr* B) : Kind(Uninitialized) { +APValue::APValue(const Expr* B) : Kind(Uninitialized) { MakeLValue(); setLValue(B, CharUnits::Zero()); } @@ -118,7 +118,7 @@ void APValue::print(llvm::raw_ostream &OS) const { } } -Expr* APValue::getLValueBase() const { +const Expr* APValue::getLValueBase() const { assert(isLValue() && "Invalid accessor"); return ((const LV*)(const void*)Data)->Base; } @@ -128,7 +128,7 @@ CharUnits APValue::getLValueOffset() const { return ((const LV*)(const void*)Data)->Offset; } -void APValue::setLValue(Expr *B, const CharUnits &O) { +void APValue::setLValue(const Expr *B, const CharUnits &O) { assert(isLValue() && "Invalid accessor"); ((LV*)(char*)Data)->Base = B; ((LV*)(char*)Data)->Offset = O; diff --git a/contrib/llvm/tools/clang/lib/AST/ASTContext.cpp b/contrib/llvm/tools/clang/lib/AST/ASTContext.cpp index 8316ea6..9094aba 100644 --- a/contrib/llvm/tools/clang/lib/AST/ASTContext.cpp +++ b/contrib/llvm/tools/clang/lib/AST/ASTContext.cpp @@ -31,6 +31,7 @@ #include "llvm/Support/MathExtras.h" #include "llvm/Support/raw_ostream.h" #include "CXXABI.h" +#include <map> using namespace clang; @@ -38,8 +39,12 @@ unsigned ASTContext::NumImplicitDefaultConstructors; unsigned ASTContext::NumImplicitDefaultConstructorsDeclared; unsigned ASTContext::NumImplicitCopyConstructors; unsigned ASTContext::NumImplicitCopyConstructorsDeclared; +unsigned ASTContext::NumImplicitMoveConstructors; +unsigned ASTContext::NumImplicitMoveConstructorsDeclared; unsigned ASTContext::NumImplicitCopyAssignmentOperators; unsigned ASTContext::NumImplicitCopyAssignmentOperatorsDeclared; +unsigned ASTContext::NumImplicitMoveAssignmentOperators; +unsigned ASTContext::NumImplicitMoveAssignmentOperatorsDeclared; unsigned ASTContext::NumImplicitDestructors; unsigned ASTContext::NumImplicitDestructorsDeclared; @@ -317,9 +322,17 @@ void ASTContext::PrintStats() const { fprintf(stderr, " %u/%u implicit copy constructors created\n", NumImplicitCopyConstructorsDeclared, NumImplicitCopyConstructors); + if (getLangOptions().CPlusPlus) + fprintf(stderr, " %u/%u implicit move constructors created\n", + NumImplicitMoveConstructorsDeclared, + NumImplicitMoveConstructors); fprintf(stderr, " %u/%u implicit copy assignment operators created\n", NumImplicitCopyAssignmentOperatorsDeclared, NumImplicitCopyAssignmentOperators); + if (getLangOptions().CPlusPlus) + fprintf(stderr, " %u/%u implicit move assignment operators created\n", + NumImplicitMoveAssignmentOperatorsDeclared, + NumImplicitMoveAssignmentOperators); fprintf(stderr, " %u/%u implicit destructors created\n", NumImplicitDestructorsDeclared, NumImplicitDestructors); @@ -546,8 +559,28 @@ bool ASTContext::ZeroBitfieldFollowsNonBitfield(const FieldDecl *FD, bool ASTContext::ZeroBitfieldFollowsBitfield(const FieldDecl *FD, const FieldDecl *LastFD) const { return (FD->isBitField() && LastFD && LastFD->isBitField() && - FD->getBitWidth()-> EvaluateAsInt(*this).getZExtValue() == 0); + FD->getBitWidth()-> EvaluateAsInt(*this).getZExtValue() == 0 && + LastFD->getBitWidth()-> EvaluateAsInt(*this).getZExtValue() != 0); + +} +bool ASTContext::BitfieldFollowsBitfield(const FieldDecl *FD, + const FieldDecl *LastFD) const { + return (FD->isBitField() && LastFD && LastFD->isBitField() && + FD->getBitWidth()-> EvaluateAsInt(*this).getZExtValue() && + LastFD->getBitWidth()-> EvaluateAsInt(*this).getZExtValue()); +} + +bool ASTContext::NoneBitfieldFollowsBitfield(const FieldDecl *FD, + const FieldDecl *LastFD) const { + return (!FD->isBitField() && LastFD && LastFD->isBitField() && + LastFD->getBitWidth()-> EvaluateAsInt(*this).getZExtValue()); +} + +bool ASTContext::BitfieldFollowsNoneBitfield(const FieldDecl *FD, + const FieldDecl *LastFD) const { + return (FD->isBitField() && LastFD && !LastFD->isBitField() && + FD->getBitWidth()-> EvaluateAsInt(*this).getZExtValue()); } ASTContext::overridden_cxx_method_iterator @@ -627,6 +660,10 @@ CharUnits ASTContext::getDeclAlign(const Decl *D, bool RefAsPointee) const { UseAlignAttrOnly = true; } } + else if (isa<FieldDecl>(D)) + UseAlignAttrOnly = + D->hasAttr<PackedAttr>() || + cast<FieldDecl>(D)->getParent()->hasAttr<PackedAttr>(); // If we're using the align attribute only, just ignore everything // else about the declaration and its type. @@ -950,6 +987,9 @@ ASTContext::getTypeInfo(const Type *T) const { return getTypeInfo(cast<DecltypeType>(T)->getUnderlyingExpr()->getType() .getTypePtr()); + case Type::UnaryTransform: + return getTypeInfo(cast<UnaryTransformType>(T)->getUnderlyingType()); + case Type::Elaborated: return getTypeInfo(cast<ElaboratedType>(T)->getNamedType().getTypePtr()); @@ -957,13 +997,18 @@ ASTContext::getTypeInfo(const Type *T) const { return getTypeInfo( cast<AttributedType>(T)->getEquivalentType().getTypePtr()); - case Type::TemplateSpecialization: + case Type::TemplateSpecialization: { assert(getCanonicalType(T) != T && "Cannot request the size of a dependent type"); - // FIXME: this is likely to be wrong once we support template - // aliases, since a template alias could refer to a typedef that - // has an __aligned__ attribute on it. - return getTypeInfo(getCanonicalType(T)); + const TemplateSpecializationType *TST = cast<TemplateSpecializationType>(T); + // A type alias template specialization may refer to a typedef with the + // aligned attribute on it. + if (TST->isTypeAlias()) + return getTypeInfo(TST->getAliasedType().getTypePtr()); + else + return getTypeInfo(getCanonicalType(T)); + } + } assert(Align && (Align & (Align-1)) == 0 && "Alignment must be power of 2"); @@ -1393,6 +1438,9 @@ QualType ASTContext::getBlockPointerType(QualType T) const { /// lvalue reference to the specified type. QualType ASTContext::getLValueReferenceType(QualType T, bool SpelledAsLValue) const { + assert(getCanonicalType(T) != OverloadTy && + "Unresolved overloaded function type"); + // Unique pointers, to guarantee there is only one pointer of a particular // structure. llvm::FoldingSetNodeID ID; @@ -1572,6 +1620,7 @@ QualType ASTContext::getVariableArrayDecayedType(QualType type) const { case Type::TypeOfExpr: case Type::TypeOf: case Type::Decltype: + case Type::UnaryTransform: case Type::DependentName: case Type::InjectedClassName: case Type::TemplateSpecialization: @@ -2235,10 +2284,10 @@ TypeSourceInfo * ASTContext::getTemplateSpecializationTypeInfo(TemplateName Name, SourceLocation NameLoc, const TemplateArgumentListInfo &Args, - QualType CanonType) const { + QualType Underlying) const { assert(!Name.getAsDependentTemplateName() && "No dependent template names here!"); - QualType TST = getTemplateSpecializationType(Name, Args, CanonType); + QualType TST = getTemplateSpecializationType(Name, Args, Underlying); TypeSourceInfo *DI = CreateTypeSourceInfo(TST); TemplateSpecializationTypeLoc TL @@ -2254,7 +2303,7 @@ ASTContext::getTemplateSpecializationTypeInfo(TemplateName Name, QualType ASTContext::getTemplateSpecializationType(TemplateName Template, const TemplateArgumentListInfo &Args, - QualType Canon) const { + QualType Underlying) const { assert(!Template.getAsDependentTemplateName() && "No dependent template names here!"); @@ -2266,35 +2315,46 @@ ASTContext::getTemplateSpecializationType(TemplateName Template, ArgVec.push_back(Args[i].getArgument()); return getTemplateSpecializationType(Template, ArgVec.data(), NumArgs, - Canon); + Underlying); } QualType ASTContext::getTemplateSpecializationType(TemplateName Template, const TemplateArgument *Args, unsigned NumArgs, - QualType Canon) const { + QualType Underlying) const { assert(!Template.getAsDependentTemplateName() && "No dependent template names here!"); // Look through qualified template names. if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName()) Template = TemplateName(QTN->getTemplateDecl()); - if (!Canon.isNull()) - Canon = getCanonicalType(Canon); - else - Canon = getCanonicalTemplateSpecializationType(Template, Args, NumArgs); + bool isTypeAlias = + Template.getAsTemplateDecl() && + isa<TypeAliasTemplateDecl>(Template.getAsTemplateDecl()); + + QualType CanonType; + if (!Underlying.isNull()) + CanonType = getCanonicalType(Underlying); + else { + assert(!isTypeAlias && + "Underlying type for template alias must be computed by caller"); + CanonType = getCanonicalTemplateSpecializationType(Template, Args, + NumArgs); + } // Allocate the (non-canonical) template specialization type, but don't // try to unique it: these types typically have location information that // we don't unique and don't want to lose. - void *Mem = Allocate((sizeof(TemplateSpecializationType) + - sizeof(TemplateArgument) * NumArgs), + void *Mem = Allocate(sizeof(TemplateSpecializationType) + + sizeof(TemplateArgument) * NumArgs + + (isTypeAlias ? sizeof(QualType) : 0), TypeAlignment); TemplateSpecializationType *Spec = new (Mem) TemplateSpecializationType(Template, Args, NumArgs, - Canon); + CanonType, + isTypeAlias ? Underlying : QualType()); Types.push_back(Spec); return QualType(Spec, 0); @@ -2306,6 +2366,10 @@ ASTContext::getCanonicalTemplateSpecializationType(TemplateName Template, unsigned NumArgs) const { assert(!Template.getAsDependentTemplateName() && "No dependent template names here!"); + assert((!Template.getAsTemplateDecl() || + !isa<TypeAliasTemplateDecl>(Template.getAsTemplateDecl())) && + "Underlying type for template alias must be computed by caller"); + // Look through qualified template names. if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName()) Template = TemplateName(QTN->getTemplateDecl()); @@ -2334,7 +2398,7 @@ ASTContext::getCanonicalTemplateSpecializationType(TemplateName Template, TypeAlignment); Spec = new (Mem) TemplateSpecializationType(CanonTemplate, CanonArgs.data(), NumArgs, - QualType()); + QualType(), QualType()); Types.push_back(Spec); TemplateSpecializationTypes.InsertNode(Spec, InsertPos); } @@ -2754,6 +2818,21 @@ QualType ASTContext::getDecltypeType(Expr *e) const { return QualType(dt, 0); } +/// getUnaryTransformationType - We don't unique these, since the memory +/// savings are minimal and these are rare. +QualType ASTContext::getUnaryTransformType(QualType BaseType, + QualType UnderlyingType, + UnaryTransformType::UTTKind Kind) + const { + UnaryTransformType *Ty = + new (*this, TypeAlignment) UnaryTransformType (BaseType, UnderlyingType, + Kind, + UnderlyingType->isDependentType() ? + QualType() : UnderlyingType); + Types.push_back(Ty); + return QualType(Ty, 0); +} + /// getAutoType - We only unique auto types after they've been deduced. QualType ASTContext::getAutoType(QualType DeducedType) const { void *InsertPos = 0; @@ -3457,7 +3536,8 @@ QualType ASTContext::getCFConstantStringType() const { SourceLocation(), 0, FieldTypes[i], /*TInfo=*/0, /*BitWidth=*/0, - /*Mutable=*/false); + /*Mutable=*/false, + /*HasInit=*/false); Field->setAccess(AS_public); CFConstantStringTypeDecl->addDecl(Field); } @@ -3498,7 +3578,8 @@ QualType ASTContext::getNSConstantStringType() const { SourceLocation(), 0, FieldTypes[i], /*TInfo=*/0, /*BitWidth=*/0, - /*Mutable=*/false); + /*Mutable=*/false, + /*HasInit=*/false); Field->setAccess(AS_public); NSConstantStringTypeDecl->addDecl(Field); } @@ -3537,7 +3618,8 @@ QualType ASTContext::getObjCFastEnumerationStateType() const { SourceLocation(), 0, FieldTypes[i], /*TInfo=*/0, /*BitWidth=*/0, - /*Mutable=*/false); + /*Mutable=*/false, + /*HasInit=*/false); Field->setAccess(AS_public); ObjCFastEnumerationStateTypeDecl->addDecl(Field); } @@ -3574,7 +3656,8 @@ QualType ASTContext::getBlockDescriptorType() const { &Idents.get(FieldNames[i]), FieldTypes[i], /*TInfo=*/0, /*BitWidth=*/0, - /*Mutable=*/false); + /*Mutable=*/false, + /*HasInit=*/false); Field->setAccess(AS_public); T->addDecl(Field); } @@ -3622,7 +3705,8 @@ QualType ASTContext::getBlockDescriptorExtendedType() const { &Idents.get(FieldNames[i]), FieldTypes[i], /*TInfo=*/0, /*BitWidth=*/0, - /*Mutable=*/false); + /*Mutable=*/false, + /*HasInit=*/false); Field->setAccess(AS_public); T->addDecl(Field); } @@ -3650,7 +3734,7 @@ bool ASTContext::BlockRequiresCopying(QualType Ty) const { if (getLangOptions().CPlusPlus) { if (const RecordType *RT = Ty->getAs<RecordType>()) { CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); - return RD->hasConstCopyConstructor(*this); + return RD->hasConstCopyConstructor(); } } @@ -3707,7 +3791,8 @@ ASTContext::BuildByRefType(llvm::StringRef DeclName, QualType Ty) const { SourceLocation(), &Idents.get(FieldNames[i]), FieldTypes[i], /*TInfo=*/0, - /*BitWidth=*/0, /*Mutable=*/false); + /*BitWidth=*/0, /*Mutable=*/false, + /*HasInit=*/false); Field->setAccess(AS_public); T->addDecl(Field); } @@ -3736,6 +3821,9 @@ static bool isTypeTypedefedAsBOOL(QualType T) { /// getObjCEncodingTypeSize returns size of type for objective-c encoding /// purpose. CharUnits ASTContext::getObjCEncodingTypeSize(QualType type) const { + if (!type->isIncompleteArrayType() && type->isIncompleteType()) + return CharUnits::Zero(); + CharUnits sz = getTypeSizeInChars(type); // Make all integer and enum types at least as large as an int @@ -3803,7 +3891,7 @@ std::string ASTContext::getObjCEncodingForBlock(const BlockExpr *Expr) const { return S; } -void ASTContext::getObjCEncodingForFunctionDecl(const FunctionDecl *Decl, +bool ASTContext::getObjCEncodingForFunctionDecl(const FunctionDecl *Decl, std::string& S) { // Encode result type. getObjCEncodingForType(Decl->getResultType(), S); @@ -3813,8 +3901,11 @@ void ASTContext::getObjCEncodingForFunctionDecl(const FunctionDecl *Decl, E = Decl->param_end(); PI != E; ++PI) { QualType PType = (*PI)->getType(); CharUnits sz = getObjCEncodingTypeSize(PType); + if (sz.isZero()) + return true; + assert (sz.isPositive() && - "getObjCEncodingForMethodDecl - Incomplete param type"); + "getObjCEncodingForFunctionDecl - Incomplete param type"); ParmOffset += sz; } S += charUnitsToString(ParmOffset); @@ -3837,11 +3928,13 @@ void ASTContext::getObjCEncodingForFunctionDecl(const FunctionDecl *Decl, S += charUnitsToString(ParmOffset); ParmOffset += getObjCEncodingTypeSize(PType); } + + return false; } /// getObjCEncodingForMethodDecl - Return the encoded type for this method /// declaration. -void ASTContext::getObjCEncodingForMethodDecl(const ObjCMethodDecl *Decl, +bool ASTContext::getObjCEncodingForMethodDecl(const ObjCMethodDecl *Decl, std::string& S) const { // FIXME: This is not very efficient. // Encode type qualifer, 'in', 'inout', etc. for the return type. @@ -3860,6 +3953,9 @@ void ASTContext::getObjCEncodingForMethodDecl(const ObjCMethodDecl *Decl, E = Decl->sel_param_end(); PI != E; ++PI) { QualType PType = (*PI)->getType(); CharUnits sz = getObjCEncodingTypeSize(PType); + if (sz.isZero()) + return true; + assert (sz.isPositive() && "getObjCEncodingForMethodDecl - Incomplete param type"); ParmOffset += sz; @@ -3889,6 +3985,8 @@ void ASTContext::getObjCEncodingForMethodDecl(const ObjCMethodDecl *Decl, S += charUnitsToString(ParmOffset); ParmOffset += getObjCEncodingTypeSize(PType); } + + return false; } /// getObjCEncodingForPropertyDecl - Return the encoded type for this @@ -4108,7 +4206,8 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, bool ExpandStructures, const FieldDecl *FD, bool OutermostType, - bool EncodingProperty) const { + bool EncodingProperty, + bool StructField) const { if (T->getAs<BuiltinType>()) { if (FD && FD->isBitField()) return EncodeBitField(this, S, T, FD); @@ -4193,7 +4292,7 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, if (const ArrayType *AT = // Ignore type qualifiers etc. dyn_cast<ArrayType>(T->getCanonicalTypeInternal())) { - if (isa<IncompleteArrayType>(AT)) { + if (isa<IncompleteArrayType>(AT) && !StructField) { // Incomplete arrays are encoded as a pointer to the array element. S += '^'; @@ -4202,11 +4301,15 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, } else { S += '['; - if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(AT)) - S += llvm::utostr(CAT->getSize().getZExtValue()); - else { + if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(AT)) { + if (getTypeSize(CAT->getElementType()) == 0) + S += '0'; + else + S += llvm::utostr(CAT->getSize().getZExtValue()); + } else { //Variable length arrays are encoded as a regular array with 0 elements. - assert(isa<VariableArrayType>(AT) && "Unknown array type!"); + assert((isa<VariableArrayType>(AT) || isa<IncompleteArrayType>(AT)) && + "Unknown array type!"); S += '0'; } @@ -4244,24 +4347,30 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, } if (ExpandStructures) { S += '='; - for (RecordDecl::field_iterator Field = RDecl->field_begin(), - FieldEnd = RDecl->field_end(); - Field != FieldEnd; ++Field) { - if (FD) { - S += '"'; - S += Field->getNameAsString(); - S += '"'; - } + if (!RDecl->isUnion()) { + getObjCEncodingForStructureImpl(RDecl, S, FD); + } else { + for (RecordDecl::field_iterator Field = RDecl->field_begin(), + FieldEnd = RDecl->field_end(); + Field != FieldEnd; ++Field) { + if (FD) { + S += '"'; + S += Field->getNameAsString(); + S += '"'; + } - // Special case bit-fields. - if (Field->isBitField()) { - getObjCEncodingForTypeImpl(Field->getType(), S, false, true, - (*Field)); - } else { - QualType qt = Field->getType(); - getLegacyIntegralTypeEncoding(qt); - getObjCEncodingForTypeImpl(qt, S, false, true, - FD); + // Special case bit-fields. + if (Field->isBitField()) { + getObjCEncodingForTypeImpl(Field->getType(), S, false, true, + (*Field)); + } else { + QualType qt = Field->getType(); + getLegacyIntegralTypeEncoding(qt); + getObjCEncodingForTypeImpl(qt, S, false, true, + FD, /*OutermostType*/false, + /*EncodingProperty*/false, + /*StructField*/true); + } } } } @@ -4382,6 +4491,135 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, assert(0 && "@encode for type not implemented!"); } +void ASTContext::getObjCEncodingForStructureImpl(RecordDecl *RDecl, + std::string &S, + const FieldDecl *FD, + bool includeVBases) const { + assert(RDecl && "Expected non-null RecordDecl"); + assert(!RDecl->isUnion() && "Should not be called for unions"); + if (!RDecl->getDefinition()) + return; + + CXXRecordDecl *CXXRec = dyn_cast<CXXRecordDecl>(RDecl); + std::multimap<uint64_t, NamedDecl *> FieldOrBaseOffsets; + const ASTRecordLayout &layout = getASTRecordLayout(RDecl); + + if (CXXRec) { + for (CXXRecordDecl::base_class_iterator + BI = CXXRec->bases_begin(), + BE = CXXRec->bases_end(); BI != BE; ++BI) { + if (!BI->isVirtual()) { + CXXRecordDecl *base = BI->getType()->getAsCXXRecordDecl(); + uint64_t offs = layout.getBaseClassOffsetInBits(base); + FieldOrBaseOffsets.insert(FieldOrBaseOffsets.upper_bound(offs), + std::make_pair(offs, base)); + } + } + } + + unsigned i = 0; + for (RecordDecl::field_iterator Field = RDecl->field_begin(), + FieldEnd = RDecl->field_end(); + Field != FieldEnd; ++Field, ++i) { + uint64_t offs = layout.getFieldOffset(i); + FieldOrBaseOffsets.insert(FieldOrBaseOffsets.upper_bound(offs), + std::make_pair(offs, *Field)); + } + + if (CXXRec && includeVBases) { + for (CXXRecordDecl::base_class_iterator + BI = CXXRec->vbases_begin(), + BE = CXXRec->vbases_end(); BI != BE; ++BI) { + CXXRecordDecl *base = BI->getType()->getAsCXXRecordDecl(); + uint64_t offs = layout.getVBaseClassOffsetInBits(base); + FieldOrBaseOffsets.insert(FieldOrBaseOffsets.upper_bound(offs), + std::make_pair(offs, base)); + } + } + + CharUnits size; + if (CXXRec) { + size = includeVBases ? layout.getSize() : layout.getNonVirtualSize(); + } else { + size = layout.getSize(); + } + + uint64_t CurOffs = 0; + std::multimap<uint64_t, NamedDecl *>::iterator + CurLayObj = FieldOrBaseOffsets.begin(); + + if (CurLayObj != FieldOrBaseOffsets.end() && CurLayObj->first != 0) { + assert(CXXRec && CXXRec->isDynamicClass() && + "Offset 0 was empty but no VTable ?"); + if (FD) { + S += "\"_vptr$"; + std::string recname = CXXRec->getNameAsString(); + if (recname.empty()) recname = "?"; + S += recname; + S += '"'; + } + S += "^^?"; + CurOffs += getTypeSize(VoidPtrTy); + } + + if (!RDecl->hasFlexibleArrayMember()) { + // Mark the end of the structure. + uint64_t offs = toBits(size); + FieldOrBaseOffsets.insert(FieldOrBaseOffsets.upper_bound(offs), + std::make_pair(offs, (NamedDecl*)0)); + } + + for (; CurLayObj != FieldOrBaseOffsets.end(); ++CurLayObj) { + assert(CurOffs <= CurLayObj->first); + + if (CurOffs < CurLayObj->first) { + uint64_t padding = CurLayObj->first - CurOffs; + // FIXME: There doesn't seem to be a way to indicate in the encoding that + // packing/alignment of members is different that normal, in which case + // the encoding will be out-of-sync with the real layout. + // If the runtime switches to just consider the size of types without + // taking into account alignment, we could make padding explicit in the + // encoding (e.g. using arrays of chars). The encoding strings would be + // longer then though. + CurOffs += padding; + } + + NamedDecl *dcl = CurLayObj->second; + if (dcl == 0) + break; // reached end of structure. + + if (CXXRecordDecl *base = dyn_cast<CXXRecordDecl>(dcl)) { + // We expand the bases without their virtual bases since those are going + // in the initial structure. Note that this differs from gcc which + // expands virtual bases each time one is encountered in the hierarchy, + // making the encoding type bigger than it really is. + getObjCEncodingForStructureImpl(base, S, FD, /*includeVBases*/false); + if (!base->isEmpty()) + CurOffs += toBits(getASTRecordLayout(base).getNonVirtualSize()); + } else { + FieldDecl *field = cast<FieldDecl>(dcl); + if (FD) { + S += '"'; + S += field->getNameAsString(); + S += '"'; + } + + if (field->isBitField()) { + EncodeBitField(this, S, field->getType(), field); + CurOffs += field->getBitWidth()->EvaluateAsInt(*this).getZExtValue(); + } else { + QualType qt = field->getType(); + getLegacyIntegralTypeEncoding(qt); + getObjCEncodingForTypeImpl(qt, S, false, true, FD, + /*OutermostType*/false, + /*EncodingProperty*/false, + /*StructField*/true); + CurOffs += getTypeSize(field->getType()); + } + } + } +} + void ASTContext::getObjCEncodingForTypeQualifier(Decl::ObjCDeclQualifier QT, std::string& S) const { if (QT & Decl::OBJC_TQ_In) @@ -6068,7 +6306,7 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D) { if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { // Forward declarations aren't required. - if (!FD->isThisDeclarationADefinition()) + if (!FD->doesThisDeclarationHaveABody()) return false; // Constructors and destructors are required. @@ -6105,10 +6343,13 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D) { // Structs that have non-trivial constructors or destructors are required. // FIXME: Handle references. + // FIXME: Be more selective about which constructors we care about. if (const RecordType *RT = VD->getType()->getAs<RecordType>()) { if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl())) { - if (RD->hasDefinition() && - (!RD->hasTrivialConstructor() || !RD->hasTrivialDestructor())) + if (RD->hasDefinition() && !(RD->hasTrivialDefaultConstructor() && + RD->hasTrivialCopyConstructor() && + RD->hasTrivialMoveConstructor() && + RD->hasTrivialDestructor())) return true; } } diff --git a/contrib/llvm/tools/clang/lib/AST/ASTDiagnostic.cpp b/contrib/llvm/tools/clang/lib/AST/ASTDiagnostic.cpp index 897b4a4..16d2f85 100644 --- a/contrib/llvm/tools/clang/lib/AST/ASTDiagnostic.cpp +++ b/contrib/llvm/tools/clang/lib/AST/ASTDiagnostic.cpp @@ -56,9 +56,11 @@ static QualType Desugar(ASTContext &Context, QualType QT, bool &ShouldAKA) { continue; } - // Don't desugar template specializations. - if (isa<TemplateSpecializationType>(Ty)) - break; + // Don't desugar template specializations, unless it's an alias template. + if (const TemplateSpecializationType *TST + = dyn_cast<TemplateSpecializationType>(Ty)) + if (!TST->isTypeAlias()) + break; // Don't desugar magic Objective-C types. if (QualType(Ty,0) == Context.getObjCIdType() || diff --git a/contrib/llvm/tools/clang/lib/AST/ASTImporter.cpp b/contrib/llvm/tools/clang/lib/AST/ASTImporter.cpp index dc881ba..100e604 100644 --- a/contrib/llvm/tools/clang/lib/AST/ASTImporter.cpp +++ b/contrib/llvm/tools/clang/lib/AST/ASTImporter.cpp @@ -64,6 +64,7 @@ namespace { // FIXME: DependentTypeOfExprType QualType VisitTypeOfType(const TypeOfType *T); QualType VisitDecltypeType(const DecltypeType *T); + QualType VisitUnaryTransformType(const UnaryTransformType *T); QualType VisitAutoType(const AutoType *T); // FIXME: DependentDecltypeType QualType VisitRecordType(const RecordType *T); @@ -604,7 +605,14 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, cast<TypeOfType>(T2)->getUnderlyingType())) return false; break; - + + case Type::UnaryTransform: + if (!IsStructurallyEquivalent(Context, + cast<UnaryTransformType>(T1)->getUnderlyingType(), + cast<UnaryTransformType>(T1)->getUnderlyingType())) + return false; + break; + case Type::Decltype: if (!IsStructurallyEquivalent(Context, cast<DecltypeType>(T1)->getUnderlyingExpr(), @@ -1572,6 +1580,17 @@ QualType ASTNodeImporter::VisitDecltypeType(const DecltypeType *T) { return Importer.getToContext().getDecltypeType(ToExpr); } +QualType ASTNodeImporter::VisitUnaryTransformType(const UnaryTransformType *T) { + QualType ToBaseType = Importer.Import(T->getBaseType()); + QualType ToUnderlyingType = Importer.Import(T->getUnderlyingType()); + if (ToBaseType.isNull() || ToUnderlyingType.isNull()) + return QualType(); + + return Importer.getToContext().getUnaryTransformType(ToBaseType, + ToUnderlyingType, + T->getUTTKind()); +} + QualType ASTNodeImporter::VisitAutoType(const AutoType *T) { // FIXME: Make sure that the "to" context supports C++0x! QualType FromDeduced = T->getDeducedType(); @@ -2493,9 +2512,12 @@ Decl *ASTNodeImporter::VisitFieldDecl(FieldDecl *D) { FieldDecl *ToField = FieldDecl::Create(Importer.getToContext(), DC, Importer.Import(D->getInnerLocStart()), Loc, Name.getAsIdentifierInfo(), - T, TInfo, BitWidth, D->isMutable()); + T, TInfo, BitWidth, D->isMutable(), + D->hasInClassInitializer()); ToField->setAccess(D->getAccess()); ToField->setLexicalDeclContext(LexicalDC); + if (ToField->hasInClassInitializer()) + ToField->setInClassInitializer(D->getInClassInitializer()); Importer.Imported(D, ToField); LexicalDC->addDecl(ToField); return ToField; @@ -2851,7 +2873,8 @@ Decl *ASTNodeImporter::VisitObjCMethodDecl(ObjCMethodDecl *D) { D->isVariadic(), D->isSynthesized(), D->isDefined(), - D->getImplementationControl()); + D->getImplementationControl(), + D->hasRelatedResultType()); // FIXME: When we decide to merge method definitions, we'll need to // deal with implicit parameters. diff --git a/contrib/llvm/tools/clang/lib/AST/Decl.cpp b/contrib/llvm/tools/clang/lib/AST/Decl.cpp index b21ba9a..12357c0 100644 --- a/contrib/llvm/tools/clang/lib/AST/Decl.cpp +++ b/contrib/llvm/tools/clang/lib/AST/Decl.cpp @@ -1422,6 +1422,31 @@ bool FunctionDecl::hasBody(const FunctionDecl *&Definition) const { return false; } +bool FunctionDecl::hasTrivialBody() const +{ + Stmt *S = getBody(); + if (!S) { + // Since we don't have a body for this function, we don't know if it's + // trivial or not. + return false; + } + + if (isa<CompoundStmt>(S) && cast<CompoundStmt>(S)->body_empty()) + return true; + return false; +} + +bool FunctionDecl::isDefined(const FunctionDecl *&Definition) const { + for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I) { + if (I->IsDeleted || I->IsDefaulted || I->Body || I->IsLateTemplateParsed) { + Definition = I->IsDeleted ? I->getCanonicalDecl() : *I; + return true; + } + } + + return false; +} + Stmt *FunctionDecl::getBody(const FunctionDecl *&Definition) const { for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I) { if (I->Body) { @@ -1450,10 +1475,34 @@ void FunctionDecl::setPure(bool P) { } bool FunctionDecl::isMain() const { - ASTContext &Context = getASTContext(); - return !Context.getLangOptions().Freestanding && - getDeclContext()->getRedeclContext()->isTranslationUnit() && - getIdentifier() && getIdentifier()->isStr("main"); + const TranslationUnitDecl *tunit = + dyn_cast<TranslationUnitDecl>(getDeclContext()->getRedeclContext()); + return tunit && + !tunit->getASTContext().getLangOptions().Freestanding && + getIdentifier() && + getIdentifier()->isStr("main"); +} + +bool FunctionDecl::isReservedGlobalPlacementOperator() const { + assert(getDeclName().getNameKind() == DeclarationName::CXXOperatorName); + assert(getDeclName().getCXXOverloadedOperator() == OO_New || + getDeclName().getCXXOverloadedOperator() == OO_Delete || + getDeclName().getCXXOverloadedOperator() == OO_Array_New || + getDeclName().getCXXOverloadedOperator() == OO_Array_Delete); + + if (isa<CXXRecordDecl>(getDeclContext())) return false; + assert(getDeclContext()->getRedeclContext()->isTranslationUnit()); + + const FunctionProtoType *proto = getType()->castAs<FunctionProtoType>(); + if (proto->getNumArgs() != 2 || proto->isVariadic()) return false; + + ASTContext &Context = + cast<TranslationUnitDecl>(getDeclContext()->getRedeclContext()) + ->getASTContext(); + + // The result type and first argument type are constant across all + // these operators. The second argument must be exactly void*. + return (proto->getArgType(1).getCanonicalType() == Context.VoidPtrTy); } bool FunctionDecl::isExternC() const { @@ -1690,11 +1739,11 @@ bool FunctionDecl::isInlined() const { /// an externally visible symbol, but "extern inline" will not create an /// externally visible symbol. bool FunctionDecl::isInlineDefinitionExternallyVisible() const { - assert(isThisDeclarationADefinition() && "Must have the function definition"); + assert(doesThisDeclarationHaveABody() && "Must have the function definition"); assert(isInlined() && "Function must be inline"); ASTContext &Context = getASTContext(); - if (!Context.getLangOptions().C99 || hasAttr<GNUInlineAttr>()) { + if (Context.getLangOptions().GNUInline || hasAttr<GNUInlineAttr>()) { // If it's not the case that both 'inline' and 'extern' are // specified on the definition, then this inline definition is // externally visible. @@ -2028,9 +2077,10 @@ SourceRange FunctionDecl::getSourceRange() const { FieldDecl *FieldDecl::Create(const ASTContext &C, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, IdentifierInfo *Id, QualType T, - TypeSourceInfo *TInfo, Expr *BW, bool Mutable) { + TypeSourceInfo *TInfo, Expr *BW, bool Mutable, + bool HasInit) { return new (C) FieldDecl(Decl::Field, DC, StartLoc, IdLoc, Id, T, TInfo, - BW, Mutable); + BW, Mutable, HasInit); } bool FieldDecl::isAnonymousStructOrUnion() const { @@ -2059,8 +2109,7 @@ unsigned FieldDecl::getFieldIndex() const { if (IsMsStruct) { // Zero-length bitfields following non-bitfield members are ignored. - if (getASTContext().ZeroBitfieldFollowsNonBitfield((*i), LastFD) || - getASTContext().ZeroBitfieldFollowsBitfield((*i), LastFD)) { + if (getASTContext().ZeroBitfieldFollowsNonBitfield((*i), LastFD)) { ++i; continue; } @@ -2076,10 +2125,17 @@ unsigned FieldDecl::getFieldIndex() const { SourceRange FieldDecl::getSourceRange() const { if (isBitField()) - return SourceRange(getInnerLocStart(), BitWidth->getLocEnd()); + return SourceRange(getInnerLocStart(), getBitWidth()->getLocEnd()); return DeclaratorDecl::getSourceRange(); } +void FieldDecl::setInClassInitializer(Expr *Init) { + assert(!InitializerOrBitWidth.getPointer() && + "bit width or initializer already set"); + InitializerOrBitWidth.setPointer(Init); + InitializerOrBitWidth.setInt(0); +} + //===----------------------------------------------------------------------===// // TagDecl Implementation //===----------------------------------------------------------------------===// diff --git a/contrib/llvm/tools/clang/lib/AST/DeclBase.cpp b/contrib/llvm/tools/clang/lib/AST/DeclBase.cpp index 6d517c5..1766d39 100644 --- a/contrib/llvm/tools/clang/lib/AST/DeclBase.cpp +++ b/contrib/llvm/tools/clang/lib/AST/DeclBase.cpp @@ -439,6 +439,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { case Typedef: case TypeAlias: + case TypeAliasTemplate: case UnresolvedUsingTypename: case TemplateTypeParm: return IDNS_Ordinary | IDNS_Type; @@ -1165,10 +1166,10 @@ void DeclContext::makeDeclVisibleInContextImpl(NamedDecl *D) { if (!D->getDeclName()) return; - // FIXME: This feels like a hack. Should DeclarationName support - // template-ids, or is there a better way to keep specializations - // from being visible? - if (isa<ClassTemplateSpecializationDecl>(D) || D->isTemplateParameter()) + // Skip entities that can't be found by name lookup into a particular + // context. + if ((D->getIdentifierNamespace() == 0 && !isa<UsingDirectiveDecl>(D)) || + D->isTemplateParameter()) return; ASTContext *C = 0; diff --git a/contrib/llvm/tools/clang/lib/AST/DeclCXX.cpp b/contrib/llvm/tools/clang/lib/AST/DeclCXX.cpp index 9099cd5..08ac2a5 100644 --- a/contrib/llvm/tools/clang/lib/AST/DeclCXX.cpp +++ b/contrib/llvm/tools/clang/lib/AST/DeclCXX.cpp @@ -29,19 +29,21 @@ using namespace clang; CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D) : UserDeclaredConstructor(false), UserDeclaredCopyConstructor(false), - UserDeclaredCopyAssignment(false), UserDeclaredDestructor(false), + UserDeclaredMoveConstructor(false), UserDeclaredCopyAssignment(false), + UserDeclaredMoveAssignment(false), UserDeclaredDestructor(false), Aggregate(true), PlainOldData(true), Empty(true), Polymorphic(false), Abstract(false), IsStandardLayout(true), HasNoNonEmptyBases(true), HasPrivateFields(false), HasProtectedFields(false), HasPublicFields(false), - HasTrivialConstructor(true), HasConstExprNonCopyMoveConstructor(false), - HasTrivialCopyConstructor(true), HasTrivialMoveConstructor(true), - HasTrivialCopyAssignment(true), HasTrivialMoveAssignment(true), - HasTrivialDestructor(true), HasNonLiteralTypeFieldsOrBases(false), - ComputedVisibleConversions(false), - DeclaredDefaultConstructor(false), DeclaredCopyConstructor(false), - DeclaredCopyAssignment(false), DeclaredDestructor(false), - NumBases(0), NumVBases(0), Bases(), VBases(), - Definition(D), FirstFriend(0) { + HasMutableFields(false), HasTrivialDefaultConstructor(true), + HasConstExprNonCopyMoveConstructor(false), HasTrivialCopyConstructor(true), + HasTrivialMoveConstructor(true), HasTrivialCopyAssignment(true), + HasTrivialMoveAssignment(true), HasTrivialDestructor(true), + HasNonLiteralTypeFieldsOrBases(false), ComputedVisibleConversions(false), + UserProvidedDefaultConstructor(false), DeclaredDefaultConstructor(false), + DeclaredCopyConstructor(false), DeclaredMoveConstructor(false), + DeclaredCopyAssignment(false), DeclaredMoveAssignment(false), + DeclaredDestructor(false), NumBases(0), NumVBases(0), Bases(), VBases(), + Definition(D), FirstFriend(0) { } CXXRecordDecl::CXXRecordDecl(Kind K, TagKind TK, DeclContext *DC, @@ -165,8 +167,9 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases, data().Empty = false; // C++ [class.ctor]p5: - // A constructor is trivial if its class has no virtual base classes. - data().HasTrivialConstructor = false; + // A default constructor is trivial [...] if: + // -- its class has [...] no virtual bases + data().HasTrivialDefaultConstructor = false; // C++0x [class.copy]p13: // A copy/move constructor for class X is trivial if it is neither @@ -188,10 +191,11 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases, data().IsStandardLayout = false; } else { // C++ [class.ctor]p5: - // A constructor is trivial if all the direct base classes of its - // class have trivial constructors. - if (!BaseClassDecl->hasTrivialConstructor()) - data().HasTrivialConstructor = false; + // A default constructor is trivial [...] if: + // -- all the direct base classes of its class have trivial default + // constructors. + if (!BaseClassDecl->hasTrivialDefaultConstructor()) + data().HasTrivialDefaultConstructor = false; // C++0x [class.copy]p13: // A copy/move constructor for class X is trivial if [...] @@ -223,6 +227,10 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases, // have trivial destructors. if (!BaseClassDecl->hasTrivialDestructor()) data().HasTrivialDestructor = false; + + // Keep track of the presence of mutable fields. + if (BaseClassDecl->hasMutableFields()) + data().HasMutableFields = true; } if (VBases.empty()) @@ -262,8 +270,8 @@ bool CXXRecordDecl::hasAnyDependentBases() const { return !forallBases(SawBase, 0); } -bool CXXRecordDecl::hasConstCopyConstructor(const ASTContext &Context) const { - return getCopyConstructor(Context, Qualifiers::Const) != 0; +bool CXXRecordDecl::hasConstCopyConstructor() const { + return getCopyConstructor(Qualifiers::Const) != 0; } bool CXXRecordDecl::isTriviallyCopyable() const { @@ -306,8 +314,8 @@ GetBestOverloadCandidateSimple( return Cands[Best].first; } -CXXConstructorDecl *CXXRecordDecl::getCopyConstructor(const ASTContext &Context, - unsigned TypeQuals) const{ +CXXConstructorDecl *CXXRecordDecl::getCopyConstructor(unsigned TypeQuals) const{ + ASTContext &Context = getASTContext(); QualType ClassType = Context.getTypeDeclType(const_cast<CXXRecordDecl*>(this)); DeclarationName ConstructorName @@ -337,6 +345,14 @@ CXXConstructorDecl *CXXRecordDecl::getCopyConstructor(const ASTContext &Context, GetBestOverloadCandidateSimple(Found)); } +CXXConstructorDecl *CXXRecordDecl::getMoveConstructor() const { + for (ctor_iterator I = ctor_begin(), E = ctor_end(); I != E; ++I) + if (I->isMoveConstructor()) + return *I; + + return 0; +} + CXXMethodDecl *CXXRecordDecl::getCopyAssignmentOperator(bool ArgIsConst) const { ASTContext &Context = getASTContext(); QualType Class = Context.getTypeDeclType(const_cast<CXXRecordDecl *>(this)); @@ -387,6 +403,14 @@ CXXMethodDecl *CXXRecordDecl::getCopyAssignmentOperator(bool ArgIsConst) const { return GetBestOverloadCandidateSimple(Found); } +CXXMethodDecl *CXXRecordDecl::getMoveAssignmentOperator() const { + for (method_iterator I = method_begin(), E = method_end(); I != E; ++I) + if (I->isMoveAssignmentOperator()) + return *I; + + return 0; +} + void CXXRecordDecl::markedVirtualFunctionPure() { // C++ [class.abstract]p2: // A class is abstract if it has at least one pure virtual function. @@ -421,8 +445,10 @@ void CXXRecordDecl::addedMember(Decl *D) { // polymorphic class. data().Polymorphic = true; - // None of the special member functions are trivial. - data().HasTrivialConstructor = false; + // C++0x [class.ctor]p5 + // A default constructor is trivial [...] if: + // -- its class has no virtual functions [...] + data().HasTrivialDefaultConstructor = false; // C++0x [class.copy]p13: // A copy/move constructor for class X is trivial if [...] @@ -451,32 +477,32 @@ void CXXRecordDecl::addedMember(Decl *D) { if (ASTMutationListener *L = getASTMutationListener()) L->AddedCXXImplicitMember(data().Definition, D); + // If this is a special member function, note that it was added and then + // return early. if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) { - // If this is the implicit default constructor, note that we have now - // declared it. if (Constructor->isDefaultConstructor()) data().DeclaredDefaultConstructor = true; - // If this is the implicit copy constructor, note that we have now - // declared it. else if (Constructor->isCopyConstructor()) data().DeclaredCopyConstructor = true; + else if (Constructor->isMoveConstructor()) + data().DeclaredMoveConstructor = true; + else + goto NotASpecialMember; return; - } - - if (isa<CXXDestructorDecl>(D)) { + } else if (isa<CXXDestructorDecl>(D)) { data().DeclaredDestructor = true; return; - } - - if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) { - // If this is the implicit copy constructor, note that we have now - // declared it. - // FIXME: Move constructors - if (Method->getOverloadedOperator() == OO_Equal) + } else if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) { + if (Method->isCopyAssignmentOperator()) data().DeclaredCopyAssignment = true; + else if (Method->isMoveAssignmentOperator()) + data().DeclaredMoveAssignment = true; + else + goto NotASpecialMember; return; } +NotASpecialMember:; // Any other implicit declarations are handled like normal declarations. } @@ -485,23 +511,20 @@ void CXXRecordDecl::addedMember(Decl *D) { // Note that we have a user-declared constructor. data().UserDeclaredConstructor = true; - // Note that we have no need of an implicitly-declared default constructor. - data().DeclaredDefaultConstructor = true; - - // C++ [dcl.init.aggr]p1: - // An aggregate is an array or a class (clause 9) with no - // user-declared constructors (12.1) [...]. - data().Aggregate = false; - - // C++ [class]p4: - // A POD-struct is an aggregate class [...] - data().PlainOldData = false; - - // C++ [class.ctor]p5: - // A constructor is trivial if it is an implicitly-declared default - // constructor. - // FIXME: C++0x: don't do this for "= default" default constructors. - data().HasTrivialConstructor = false; + // FIXME: Under C++0x, /only/ special member functions may be user-provided. + // This is probably a defect. + bool UserProvided = false; + + // C++0x [class.ctor]p5: + // A default constructor is trivial if it is not user-provided [...] + if (Constructor->isDefaultConstructor()) { + data().DeclaredDefaultConstructor = true; + if (Constructor->isUserProvided()) { + data().HasTrivialDefaultConstructor = false; + data().UserProvidedDefaultConstructor = true; + UserProvided = true; + } + } // Note when we have a user-declared copy or move constructor, which will // suppress the implicit declaration of those constructors. @@ -511,16 +534,23 @@ void CXXRecordDecl::addedMember(Decl *D) { data().DeclaredCopyConstructor = true; // C++0x [class.copy]p13: - // A copy/move constructor for class X is trivial if it is neither - // user-provided nor deleted - // FIXME: C++0x: don't do this for "= default" copy constructors. - data().HasTrivialCopyConstructor = false; + // A copy/move constructor for class X is trivial if it is not + // user-provided [...] + if (Constructor->isUserProvided()) { + data().HasTrivialCopyConstructor = false; + UserProvided = true; + } } else if (Constructor->isMoveConstructor()) { + data().UserDeclaredMoveConstructor = true; + data().DeclaredMoveConstructor = true; + // C++0x [class.copy]p13: - // A copy/move constructor for class X is trivial if it is neither - // user-provided nor deleted - // FIXME: C++0x: don't do this for "= default" move constructors. - data().HasTrivialMoveConstructor = false; + // A copy/move constructor for class X is trivial if it is not + // user-provided [...] + if (Constructor->isUserProvided()) { + data().HasTrivialMoveConstructor = false; + UserProvided = true; + } } } if (Constructor->isConstExpr() && @@ -530,88 +560,81 @@ void CXXRecordDecl::addedMember(Decl *D) { data().HasConstExprNonCopyMoveConstructor = true; } + // C++ [dcl.init.aggr]p1: + // An aggregate is an array or a class with no user-declared + // constructors [...]. + // C++0x [dcl.init.aggr]p1: + // An aggregate is an array or a class with no user-provided + // constructors [...]. + if (!getASTContext().getLangOptions().CPlusPlus0x || UserProvided) + data().Aggregate = false; + + // C++ [class]p4: + // A POD-struct is an aggregate class [...] + // Since the POD bit is meant to be C++03 POD-ness, clear it even if the + // type is technically an aggregate in C++0x since it wouldn't be in 03. + data().PlainOldData = false; + return; } // Handle (user-declared) destructors. - if (isa<CXXDestructorDecl>(D)) { + if (CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(D)) { data().DeclaredDestructor = true; data().UserDeclaredDestructor = true; // C++ [class]p4: // A POD-struct is an aggregate class that has [...] no user-defined // destructor. + // This bit is the C++03 POD bit, not the 0x one. data().PlainOldData = false; - // C++ [class.dtor]p3: - // A destructor is trivial if it is an implicitly-declared destructor and - // [...]. - // - // FIXME: C++0x: don't do this for "= default" destructors - data().HasTrivialDestructor = false; + // C++0x [class.dtor]p5: + // A destructor is trivial if it is not user-provided and [...] + if (DD->isUserProvided()) + data().HasTrivialDestructor = false; return; } // Handle (user-declared) member functions. if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) { - if (Method->getOverloadedOperator() == OO_Equal) { - // We're interested specifically in copy assignment operators. - const FunctionProtoType *FnType - = Method->getType()->getAs<FunctionProtoType>(); - assert(FnType && "Overloaded operator has no proto function type."); - assert(FnType->getNumArgs() == 1 && !FnType->isVariadic()); - - // Copy assignment operators must be non-templates. - if (Method->getPrimaryTemplate() || FunTmpl) - return; - - ASTContext &Context = getASTContext(); - QualType ClassType = Context.getCanonicalType(Context.getTypeDeclType( - const_cast<CXXRecordDecl*>(this))); - - bool isRValueRefArg = false; - QualType ArgType = FnType->getArgType(0); - if (const LValueReferenceType *Ref = - ArgType->getAs<LValueReferenceType>()) { - ArgType = Ref->getPointeeType(); - } else if (const RValueReferenceType *Ref = - ArgType->getAs<RValueReferenceType>()) { - ArgType = Ref->getPointeeType(); - isRValueRefArg = true; - } - if (!Context.hasSameUnqualifiedType(ClassType, ArgType)) - return; - + if (Method->isCopyAssignmentOperator()) { // C++ [class]p4: // A POD-struct is an aggregate class that [...] has no user-defined // copy assignment operator [...]. - // FIXME: This should be probably determined dynamically in terms of - // other more precise attributes to correctly model how it is specified - // in C++0x. Setting it here happens to do the right thing. + // This is the C++03 bit only. data().PlainOldData = false; - if (!isRValueRefArg) { - // This is a copy assignment operator. + // This is a copy assignment operator. - // Suppress the implicit declaration of a copy constructor. - data().UserDeclaredCopyAssignment = true; - data().DeclaredCopyAssignment = true; + // Suppress the implicit declaration of a copy constructor. + data().UserDeclaredCopyAssignment = true; + data().DeclaredCopyAssignment = true; - // C++0x [class.copy]p27: - // A copy/move assignment operator for class X is trivial if it is - // neither user-provided nor deleted [...] - // FIXME: C++0x: don't do this for "= default" copy operators. + // C++0x [class.copy]p27: + // A copy/move assignment operator for class X is trivial if it is + // neither user-provided nor deleted [...] + if (Method->isUserProvided()) data().HasTrivialCopyAssignment = false; - } else { - // This is a move assignment operator. - // C++0x [class.copy]p27: - // A copy/move assignment operator for class X is trivial if it is - // neither user-provided nor deleted [...] - // FIXME: C++0x: don't do this for "= default" copy operators. + return; + } + + if (Method->isMoveAssignmentOperator()) { + // This is an extension in C++03 mode, but we'll keep consistency by + // taking a move assignment operator to induce non-POD-ness + data().PlainOldData = false; + + // This is a move assignment operator. + data().UserDeclaredMoveAssignment = true; + data().DeclaredMoveAssignment = true; + + // C++0x [class.copy]p27: + // A copy/move assignment operator for class X is trivial if it is + // neither user-provided nor deleted [...] + if (Method->isUserProvided()) data().HasTrivialMoveAssignment = false; - } } // Keep the list of conversion functions up-to-date. @@ -667,6 +690,10 @@ void CXXRecordDecl::addedMember(Decl *D) { data().HasPublicFields) > 1) data().IsStandardLayout = false; + // Keep track of the presence of mutable fields. + if (Field->isMutable()) + data().HasMutableFields = true; + // C++0x [class]p9: // A POD struct is a class that is both a trivial class and a // standard-layout class, and has no non-static data members of type @@ -676,7 +703,7 @@ void CXXRecordDecl::addedMember(Decl *D) { if (!T->isPODType()) data().PlainOldData = false; if (T->isReferenceType()) { - data().HasTrivialConstructor = false; + data().HasTrivialDefaultConstructor = false; // C++0x [class]p7: // A standard-layout class is a class that: @@ -688,11 +715,32 @@ void CXXRecordDecl::addedMember(Decl *D) { if (!hasNonLiteralTypeFieldsOrBases() && !T->isLiteralType()) data().HasNonLiteralTypeFieldsOrBases = true; + if (Field->hasInClassInitializer()) { + // C++0x [class]p5: + // A default constructor is trivial if [...] no non-static data member + // of its class has a brace-or-equal-initializer. + data().HasTrivialDefaultConstructor = false; + + // C++0x [dcl.init.aggr]p1: + // An aggregate is a [...] class with [...] no + // brace-or-equal-initializers for non-static data members. + data().Aggregate = false; + + // C++0x [class]p10: + // A POD struct is [...] a trivial class. + data().PlainOldData = false; + } + if (const RecordType *RecordTy = T->getAs<RecordType>()) { CXXRecordDecl* FieldRec = cast<CXXRecordDecl>(RecordTy->getDecl()); if (FieldRec->getDefinition()) { - if (!FieldRec->hasTrivialConstructor()) - data().HasTrivialConstructor = false; + // C++0x [class.ctor]p5: + // A defulat constructor is trivial [...] if: + // -- for all the non-static data members of its class that are of + // class type (or array thereof), each such class has a trivial + // default constructor. + if (!FieldRec->hasTrivialDefaultConstructor()) + data().HasTrivialDefaultConstructor = false; // C++0x [class.copy]p13: // A copy/move constructor for class X is trivial if [...] @@ -753,6 +801,10 @@ void CXXRecordDecl::addedMember(Decl *D) { } } } + + // Keep track of the presence of mutable fields. + if (FieldRec->hasMutableFields()) + data().HasMutableFields = true; } } @@ -1135,14 +1187,13 @@ bool CXXMethodDecl::isUsualDeallocationFunction() const { } bool CXXMethodDecl::isCopyAssignmentOperator() const { - // C++0x [class.copy]p19: + // C++0x [class.copy]p17: // A user-declared copy assignment operator X::operator= is a non-static // non-template member function of class X with exactly one parameter of // type X, X&, const X&, volatile X& or const volatile X&. if (/*operator=*/getOverloadedOperator() != OO_Equal || /*non-static*/ isStatic() || - /*non-template*/getPrimaryTemplate() || getDescribedFunctionTemplate() || - /*exactly one parameter*/getNumParams() != 1) + /*non-template*/getPrimaryTemplate() || getDescribedFunctionTemplate()) return false; QualType ParamType = getParamDecl(0)->getType(); @@ -1155,6 +1206,26 @@ bool CXXMethodDecl::isCopyAssignmentOperator() const { return Context.hasSameUnqualifiedType(ClassType, ParamType); } +bool CXXMethodDecl::isMoveAssignmentOperator() const { + // C++0x [class.copy]p19: + // A user-declared move assignment operator X::operator= is a non-static + // non-template member function of class X with exactly one parameter of type + // X&&, const X&&, volatile X&&, or const volatile X&&. + if (getOverloadedOperator() != OO_Equal || isStatic() || + getPrimaryTemplate() || getDescribedFunctionTemplate()) + return false; + + QualType ParamType = getParamDecl(0)->getType(); + if (!isa<RValueReferenceType>(ParamType)) + return false; + ParamType = ParamType->getPointeeType(); + + ASTContext &Context = getASTContext(); + QualType ClassType + = Context.getCanonicalType(Context.getTypeDeclType(getParent())); + return Context.hasSameUnqualifiedType(ClassType, ParamType); +} + void CXXMethodDecl::addOverriddenMethod(const CXXMethodDecl *MD) { assert(MD->isCanonicalDecl() && "Method is not canonical!"); assert(!MD->getParent()->isDependentContext() && @@ -1290,11 +1361,21 @@ const Type *CXXCtorInitializer::getBaseClass() const { SourceLocation CXXCtorInitializer::getSourceLocation() const { if (isAnyMemberInitializer() || isDelegatingInitializer()) return getMemberLocation(); + + if (isInClassMemberInitializer()) + return getAnyMember()->getLocation(); return getBaseClassLoc().getLocalSourceRange().getBegin(); } SourceRange CXXCtorInitializer::getSourceRange() const { + if (isInClassMemberInitializer()) { + FieldDecl *D = getAnyMember(); + if (Expr *I = D->getInClassInitializer()) + return I->getSourceRange(); + return SourceRange(); + } + return SourceRange(getSourceLocation(), getRParenLoc()); } diff --git a/contrib/llvm/tools/clang/lib/AST/DeclObjC.cpp b/contrib/llvm/tools/clang/lib/AST/DeclObjC.cpp index 24d281e..e2c4f38 100644 --- a/contrib/llvm/tools/clang/lib/AST/DeclObjC.cpp +++ b/contrib/llvm/tools/clang/lib/AST/DeclObjC.cpp @@ -339,12 +339,14 @@ ObjCMethodDecl *ObjCMethodDecl::Create(ASTContext &C, bool isSynthesized, bool isDefined, ImplementationControl impControl, + bool HasRelatedResultType, unsigned numSelectorArgs) { return new (C) ObjCMethodDecl(beginLoc, endLoc, SelInfo, T, ResultTInfo, contextDecl, isInstance, isVariadic, isSynthesized, isDefined, impControl, + HasRelatedResultType, numSelectorArgs); } @@ -446,6 +448,7 @@ ObjCMethodFamily ObjCMethodDecl::getMethodFamily() const { case OMF_release: case OMF_autorelease: case OMF_retainCount: + case OMF_self: if (!isInstanceMethod()) family = OMF_None; break; diff --git a/contrib/llvm/tools/clang/lib/AST/DeclPrinter.cpp b/contrib/llvm/tools/clang/lib/AST/DeclPrinter.cpp index 2fd88d7..421770e 100644 --- a/contrib/llvm/tools/clang/lib/AST/DeclPrinter.cpp +++ b/contrib/llvm/tools/clang/lib/AST/DeclPrinter.cpp @@ -400,7 +400,7 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { if (D->getNumParams()) POut << ", "; POut << "..."; } - } else if (D->isThisDeclarationADefinition() && !D->hasPrototype()) { + } else if (D->doesThisDeclarationHaveABody() && !D->hasPrototype()) { for (unsigned i = 0, e = D->getNumParams(); i != e; ++i) { if (i) Proto += ", "; @@ -450,62 +450,67 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { if (D->hasAttr<NoReturnAttr>()) Proto += " __attribute((noreturn))"; if (CXXConstructorDecl *CDecl = dyn_cast<CXXConstructorDecl>(D)) { - if (CDecl->getNumCtorInitializers() > 0) { - Proto += " : "; - Out << Proto; - Proto.clear(); - for (CXXConstructorDecl::init_const_iterator B = CDecl->init_begin(), - E = CDecl->init_end(); - B != E; ++B) { - CXXCtorInitializer * BMInitializer = (*B); - if (B != CDecl->init_begin()) - Out << ", "; - if (BMInitializer->isAnyMemberInitializer()) { - FieldDecl *FD = BMInitializer->getAnyMember(); - Out << FD; - } else { - Out << QualType(BMInitializer->getBaseClass(), - 0).getAsString(Policy); - } + bool HasInitializerList = false; + for (CXXConstructorDecl::init_const_iterator B = CDecl->init_begin(), + E = CDecl->init_end(); + B != E; ++B) { + CXXCtorInitializer * BMInitializer = (*B); + if (BMInitializer->isInClassMemberInitializer()) + continue; + + if (!HasInitializerList) { + Proto += " : "; + Out << Proto; + Proto.clear(); + HasInitializerList = true; + } else + Out << ", "; + + if (BMInitializer->isAnyMemberInitializer()) { + FieldDecl *FD = BMInitializer->getAnyMember(); + Out << FD; + } else { + Out << QualType(BMInitializer->getBaseClass(), + 0).getAsString(Policy); + } + + Out << "("; + if (!BMInitializer->getInit()) { + // Nothing to print + } else { + Expr *Init = BMInitializer->getInit(); + if (ExprWithCleanups *Tmp = dyn_cast<ExprWithCleanups>(Init)) + Init = Tmp->getSubExpr(); + + Init = Init->IgnoreParens(); - Out << "("; - if (!BMInitializer->getInit()) { - // Nothing to print - } else { - Expr *Init = BMInitializer->getInit(); - if (ExprWithCleanups *Tmp = dyn_cast<ExprWithCleanups>(Init)) - Init = Tmp->getSubExpr(); - - Init = Init->IgnoreParens(); - - Expr *SimpleInit = 0; - Expr **Args = 0; - unsigned NumArgs = 0; - if (ParenListExpr *ParenList = dyn_cast<ParenListExpr>(Init)) { - Args = ParenList->getExprs(); - NumArgs = ParenList->getNumExprs(); - } else if (CXXConstructExpr *Construct - = dyn_cast<CXXConstructExpr>(Init)) { - Args = Construct->getArgs(); - NumArgs = Construct->getNumArgs(); - } else - SimpleInit = Init; - - if (SimpleInit) - SimpleInit->printPretty(Out, Context, 0, Policy, Indentation); - else { - for (unsigned I = 0; I != NumArgs; ++I) { - if (isa<CXXDefaultArgExpr>(Args[I])) - break; - - if (I) - Out << ", "; - Args[I]->printPretty(Out, Context, 0, Policy, Indentation); - } + Expr *SimpleInit = 0; + Expr **Args = 0; + unsigned NumArgs = 0; + if (ParenListExpr *ParenList = dyn_cast<ParenListExpr>(Init)) { + Args = ParenList->getExprs(); + NumArgs = ParenList->getNumExprs(); + } else if (CXXConstructExpr *Construct + = dyn_cast<CXXConstructExpr>(Init)) { + Args = Construct->getArgs(); + NumArgs = Construct->getNumArgs(); + } else + SimpleInit = Init; + + if (SimpleInit) + SimpleInit->printPretty(Out, Context, 0, Policy, Indentation); + else { + for (unsigned I = 0; I != NumArgs; ++I) { + if (isa<CXXDefaultArgExpr>(Args[I])) + break; + + if (I) + Out << ", "; + Args[I]->printPretty(Out, Context, 0, Policy, Indentation); } } - Out << ")"; } + Out << ")"; } } else @@ -518,9 +523,9 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { if (D->isPure()) Out << " = 0"; - else if (D->isDeleted()) + else if (D->isDeletedAsWritten()) Out << " = delete"; - else if (D->isThisDeclarationADefinition()) { + else if (D->doesThisDeclarationHaveABody()) { if (!D->hasPrototype() && D->getNumParams()) { // This is a K&R function definition, so we need to print the // parameters. @@ -553,6 +558,12 @@ void DeclPrinter::VisitFieldDecl(FieldDecl *D) { Out << " : "; D->getBitWidth()->printPretty(Out, Context, 0, Policy, Indentation); } + + Expr *Init = D->getInClassInitializer(); + if (!Policy.SuppressInitializers && Init) { + Out << " = "; + Init->printPretty(Out, Context, 0, Policy, Indentation); + } } void DeclPrinter::VisitLabelDecl(LabelDecl *D) { @@ -932,6 +943,11 @@ void DeclPrinter::VisitObjCPropertyDecl(ObjCPropertyDecl *PDecl) { Out << (first ? ' ' : ',') << "nonatomic"; first = false; } + if (PDecl->getPropertyAttributes() & + ObjCPropertyDecl::OBJC_PR_atomic) { + Out << (first ? ' ' : ',') << "atomic"; + first = false; + } Out << " )"; } Out << ' ' << PDecl->getType().getAsString(Policy) << ' ' << PDecl; diff --git a/contrib/llvm/tools/clang/lib/AST/DeclTemplate.cpp b/contrib/llvm/tools/clang/lib/AST/DeclTemplate.cpp index 6272340..bc375d0a 100644 --- a/contrib/llvm/tools/clang/lib/AST/DeclTemplate.cpp +++ b/contrib/llvm/tools/clang/lib/AST/DeclTemplate.cpp @@ -735,3 +735,34 @@ FriendTemplateDecl *FriendTemplateDecl::Create(ASTContext &Context, EmptyShell Empty) { return new (Context) FriendTemplateDecl(Empty); } + +//===----------------------------------------------------------------------===// +// TypeAliasTemplateDecl Implementation +//===----------------------------------------------------------------------===// + +TypeAliasTemplateDecl *TypeAliasTemplateDecl::Create(ASTContext &C, + DeclContext *DC, + SourceLocation L, + DeclarationName Name, + TemplateParameterList *Params, + NamedDecl *Decl) { + AdoptTemplateParameterList(Params, DC); + return new (C) TypeAliasTemplateDecl(DC, L, Name, Params, Decl); +} + +TypeAliasTemplateDecl *TypeAliasTemplateDecl::Create(ASTContext &C, + EmptyShell) { + return new (C) TypeAliasTemplateDecl(0, SourceLocation(), DeclarationName(), + 0, 0); +} + +void TypeAliasTemplateDecl::DeallocateCommon(void *Ptr) { + static_cast<Common *>(Ptr)->~Common(); +} +RedeclarableTemplateDecl::CommonBase * +TypeAliasTemplateDecl::newCommon(ASTContext &C) { + Common *CommonPtr = new (C) Common; + C.AddDeallocation(DeallocateCommon, CommonPtr); + return CommonPtr; +} + diff --git a/contrib/llvm/tools/clang/lib/AST/DumpXML.cpp b/contrib/llvm/tools/clang/lib/AST/DumpXML.cpp index 7d593bc..dfe0119 100644 --- a/contrib/llvm/tools/clang/lib/AST/DumpXML.cpp +++ b/contrib/llvm/tools/clang/lib/AST/DumpXML.cpp @@ -482,18 +482,20 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>, setFlag("trivial", D->isTrivial()); setFlag("returnzero", D->hasImplicitReturnZero()); setFlag("prototype", D->hasWrittenPrototype()); - setFlag("deleted", D->isDeleted()); + setFlag("deleted", D->isDeletedAsWritten()); if (D->getStorageClass() != SC_None) set("storage", VarDecl::getStorageClassSpecifierString(D->getStorageClass())); setFlag("inline", D->isInlineSpecified()); + if (const AsmLabelAttr *ALA = D->getAttr<AsmLabelAttr>()) + set("asmlabel", ALA->getLabel()); // TODO: instantiation, etc. } void visitFunctionDeclChildren(FunctionDecl *D) { for (FunctionDecl::param_iterator I = D->param_begin(), E = D->param_end(); I != E; ++I) dispatch(*I); - if (D->isThisDeclarationADefinition()) + if (D->doesThisDeclarationHaveABody()) dispatch(D->getBody()); } @@ -619,7 +621,8 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>, // TemplateDecl void visitTemplateDeclChildren(TemplateDecl *D) { visitTemplateParameters(D->getTemplateParameters()); - dispatch(D->getTemplatedDecl()); + if (D->getTemplatedDecl()) + dispatch(D->getTemplatedDecl()); } // FunctionTemplateDecl @@ -845,6 +848,7 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>, setFlag("variadic", D->isVariadic()); setFlag("synthesized", D->isSynthesized()); setFlag("defined", D->isDefined()); + setFlag("related_result_type", D->hasRelatedResultType()); } void visitObjCMethodDeclChildren(ObjCMethodDecl *D) { dispatch(D->getResultType()); diff --git a/contrib/llvm/tools/clang/lib/AST/Expr.cpp b/contrib/llvm/tools/clang/lib/AST/Expr.cpp index 6499f32..9872139 100644 --- a/contrib/llvm/tools/clang/lib/AST/Expr.cpp +++ b/contrib/llvm/tools/clang/lib/AST/Expr.cpp @@ -22,6 +22,7 @@ #include "clang/AST/StmtVisitor.h" #include "clang/Lex/LiteralSupport.h" #include "clang/Lex/Lexer.h" +#include "clang/Sema/SemaDiagnostic.h" #include "clang/Basic/Builtins.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetInfo.h" @@ -1653,7 +1654,8 @@ static Expr::CanThrowResult CanSubExprsThrow(ASTContext &C, const Expr *CE) { return R; } -static Expr::CanThrowResult CanCalleeThrow(ASTContext &Ctx, const Decl *D, +static Expr::CanThrowResult CanCalleeThrow(ASTContext &Ctx, const Expr *E, + const Decl *D, bool NullThrows = true) { if (!D) return NullThrows ? Expr::CT_Can : Expr::CT_Cannot; @@ -1683,6 +1685,15 @@ static Expr::CanThrowResult CanCalleeThrow(ASTContext &Ctx, const Decl *D, if (!FT) return Expr::CT_Can; + if (FT->getExceptionSpecType() == EST_Delayed) { + assert(isa<CXXConstructorDecl>(D) && + "only constructor exception specs can be unknown"); + Ctx.getDiagnostics().Report(E->getLocStart(), + diag::err_exception_spec_unknown) + << E->getSourceRange(); + return Expr::CT_Can; + } + return FT->isNothrow(Ctx) ? Expr::CT_Cannot : Expr::CT_Can; } @@ -1693,6 +1704,9 @@ static Expr::CanThrowResult CanDynamicCastThrow(const CXXDynamicCastExpr *DC) { if (!DC->getTypeAsWritten()->isReferenceType()) return Expr::CT_Cannot; + if (DC->getSubExpr()->isTypeDependent()) + return Expr::CT_Dependent; + return DC->getCastKind() == clang::CK_Dynamic? Expr::CT_Can : Expr::CT_Cannot; } @@ -1747,7 +1761,14 @@ Expr::CanThrowResult Expr::CanThrow(ASTContext &C) const { case CallExprClass: case CXXOperatorCallExprClass: case CXXMemberCallExprClass: { - CanThrowResult CT = CanCalleeThrow(C,cast<CallExpr>(this)->getCalleeDecl()); + const CallExpr *CE = cast<CallExpr>(this); + CanThrowResult CT; + if (isTypeDependent()) + CT = CT_Dependent; + else if (isa<CXXPseudoDestructorExpr>(CE->getCallee()->IgnoreParens())) + CT = CT_Cannot; + else + CT = CanCalleeThrow(C, this, CE->getCalleeDecl()); if (CT == CT_Can) return CT; return MergeCanThrow(CT, CanSubExprsThrow(C, this)); @@ -1755,7 +1776,7 @@ Expr::CanThrowResult Expr::CanThrow(ASTContext &C) const { case CXXConstructExprClass: case CXXTemporaryObjectExprClass: { - CanThrowResult CT = CanCalleeThrow(C, + CanThrowResult CT = CanCalleeThrow(C, this, cast<CXXConstructExpr>(this)->getConstructor()); if (CT == CT_Can) return CT; @@ -1763,9 +1784,13 @@ Expr::CanThrowResult Expr::CanThrow(ASTContext &C) const { } case CXXNewExprClass: { - CanThrowResult CT = MergeCanThrow( - CanCalleeThrow(C, cast<CXXNewExpr>(this)->getOperatorNew()), - CanCalleeThrow(C, cast<CXXNewExpr>(this)->getConstructor(), + CanThrowResult CT; + if (isTypeDependent()) + CT = CT_Dependent; + else + CT = MergeCanThrow( + CanCalleeThrow(C, this, cast<CXXNewExpr>(this)->getOperatorNew()), + CanCalleeThrow(C, this, cast<CXXNewExpr>(this)->getConstructor(), /*NullThrows*/false)); if (CT == CT_Can) return CT; @@ -1773,29 +1798,26 @@ Expr::CanThrowResult Expr::CanThrow(ASTContext &C) const { } case CXXDeleteExprClass: { - CanThrowResult CT = CanCalleeThrow(C, - cast<CXXDeleteExpr>(this)->getOperatorDelete()); - if (CT == CT_Can) - return CT; - const Expr *Arg = cast<CXXDeleteExpr>(this)->getArgument(); - // Unwrap exactly one implicit cast, which converts all pointers to void*. - if (const ImplicitCastExpr *Cast = dyn_cast<ImplicitCastExpr>(Arg)) - Arg = Cast->getSubExpr(); - if (const PointerType *PT = Arg->getType()->getAs<PointerType>()) { - if (const RecordType *RT = PT->getPointeeType()->getAs<RecordType>()) { - CanThrowResult CT2 = CanCalleeThrow(C, - cast<CXXRecordDecl>(RT->getDecl())->getDestructor()); - if (CT2 == CT_Can) - return CT2; - CT = MergeCanThrow(CT, CT2); + CanThrowResult CT; + QualType DTy = cast<CXXDeleteExpr>(this)->getDestroyedType(); + if (DTy.isNull() || DTy->isDependentType()) { + CT = CT_Dependent; + } else { + CT = CanCalleeThrow(C, this, + cast<CXXDeleteExpr>(this)->getOperatorDelete()); + if (const RecordType *RT = DTy->getAs<RecordType>()) { + const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); + CT = MergeCanThrow(CT, CanCalleeThrow(C, this, RD->getDestructor())); } + if (CT == CT_Can) + return CT; } return MergeCanThrow(CT, CanSubExprsThrow(C, this)); } case CXXBindTemporaryExprClass: { // The bound temporary has to be destroyed again, which might throw. - CanThrowResult CT = CanCalleeThrow(C, + CanThrowResult CT = CanCalleeThrow(C, this, cast<CXXBindTemporaryExpr>(this)->getTemporary()->getDestructor()); if (CT == CT_Can) return CT; @@ -1978,6 +2000,14 @@ Expr *Expr::IgnoreParenImpCasts() { } } +Expr *Expr::IgnoreConversionOperator() { + if (CXXMemberCallExpr *MCE = dyn_cast<CXXMemberCallExpr>(this)) { + if (isa<CXXConversionDecl>(MCE->getMethodDecl())) + return MCE->getImplicitObjectArgument(); + } + return this; +} + /// IgnoreParenNoopCasts - Ignore parentheses and casts that do not change the /// value (including ptr->int casts of the same size). Strip off any /// ParenExpr or CastExprs, returning their operand. @@ -3013,4 +3043,3 @@ BlockDeclRefExpr::BlockDeclRefExpr(VarDecl *d, QualType t, ExprValueKind VK, ExprBits.TypeDependent = TypeDependent; ExprBits.ValueDependent = ValueDependent; } - diff --git a/contrib/llvm/tools/clang/lib/AST/ExprClassification.cpp b/contrib/llvm/tools/clang/lib/AST/ExprClassification.cpp index 888a93c..d177cb5 100644 --- a/contrib/llvm/tools/clang/lib/AST/ExprClassification.cpp +++ b/contrib/llvm/tools/clang/lib/AST/ExprClassification.cpp @@ -161,6 +161,7 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) { case Expr::InitListExprClass: case Expr::SizeOfPackExprClass: case Expr::SubstNonTypeTemplateParmPackExprClass: + case Expr::AsTypeExprClass: return Cl::CL_PRValue; // Next come the complicated cases. @@ -465,14 +466,16 @@ static Cl::Kinds ClassifyBinaryOp(ASTContext &Ctx, const BinaryOperator *E) { // is a pointer to a data member is of the same value category as its first // operand. if (E->getOpcode() == BO_PtrMemD) - return E->getType()->isFunctionType() ? Cl::CL_MemberFunction : - ClassifyInternal(Ctx, E->getLHS()); + return (E->getType()->isFunctionType() || E->getType() == Ctx.BoundMemberTy) + ? Cl::CL_MemberFunction + : ClassifyInternal(Ctx, E->getLHS()); // C++ [expr.mptr.oper]p6: The result of an ->* expression is an lvalue if its // second operand is a pointer to data member and a prvalue otherwise. if (E->getOpcode() == BO_PtrMemI) - return E->getType()->isFunctionType() ? - Cl::CL_MemberFunction : Cl::CL_LValue; + return (E->getType()->isFunctionType() || E->getType() == Ctx.BoundMemberTy) + ? Cl::CL_MemberFunction + : Cl::CL_LValue; // All other binary operations are prvalues. return Cl::CL_PRValue; diff --git a/contrib/llvm/tools/clang/lib/AST/ExprConstant.cpp b/contrib/llvm/tools/clang/lib/AST/ExprConstant.cpp index c2caf8d4..06c5645 100644 --- a/contrib/llvm/tools/clang/lib/AST/ExprConstant.cpp +++ b/contrib/llvm/tools/clang/lib/AST/ExprConstant.cpp @@ -102,10 +102,10 @@ namespace { }; struct LValue { - Expr *Base; + const Expr *Base; CharUnits Offset; - Expr *getLValueBase() { return Base; } + const Expr *getLValueBase() { return Base; } CharUnits getLValueOffset() { return Offset; } void moveInto(APValue &v) const { @@ -221,7 +221,7 @@ static APSInt HandleFloatToIntCast(QualType DestType, QualType SrcType, APFloat &Value, const ASTContext &Ctx) { unsigned DestWidth = Ctx.getIntWidth(DestType); // Determine whether we are converting to unsigned or signed. - bool DestSigned = DestType->isSignedIntegerType(); + bool DestSigned = DestType->isSignedIntegerOrEnumerationType(); // FIXME: Warning for overflow. uint64_t Space[4]; @@ -247,7 +247,7 @@ static APSInt HandleIntToIntCast(QualType DestType, QualType SrcType, // Figure out if this is a truncate, extend or noop cast. // If the input is signed, do a sign extend, noop, or truncate. Result = Result.extOrTrunc(DestWidth); - Result.setIsUnsigned(DestType->isUnsignedIntegerType()); + Result.setIsUnsigned(DestType->isUnsignedIntegerOrEnumerationType()); return Result; } @@ -262,69 +262,69 @@ static APFloat HandleIntToFloatCast(QualType DestType, QualType SrcType, namespace { class HasSideEffect - : public StmtVisitor<HasSideEffect, bool> { + : public ConstStmtVisitor<HasSideEffect, bool> { EvalInfo &Info; public: HasSideEffect(EvalInfo &info) : Info(info) {} // Unhandled nodes conservatively default to having side effects. - bool VisitStmt(Stmt *S) { + bool VisitStmt(const Stmt *S) { return true; } - bool VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); } - bool VisitGenericSelectionExpr(GenericSelectionExpr *E) { + bool VisitParenExpr(const ParenExpr *E) { return Visit(E->getSubExpr()); } + bool VisitGenericSelectionExpr(const GenericSelectionExpr *E) { return Visit(E->getResultExpr()); } - bool VisitDeclRefExpr(DeclRefExpr *E) { + bool VisitDeclRefExpr(const DeclRefExpr *E) { if (Info.Ctx.getCanonicalType(E->getType()).isVolatileQualified()) return true; return false; } // We don't want to evaluate BlockExprs multiple times, as they generate // a ton of code. - bool VisitBlockExpr(BlockExpr *E) { return true; } - bool VisitPredefinedExpr(PredefinedExpr *E) { return false; } - bool VisitCompoundLiteralExpr(CompoundLiteralExpr *E) + bool VisitBlockExpr(const BlockExpr *E) { return true; } + bool VisitPredefinedExpr(const PredefinedExpr *E) { return false; } + bool VisitCompoundLiteralExpr(const CompoundLiteralExpr *E) { return Visit(E->getInitializer()); } - bool VisitMemberExpr(MemberExpr *E) { return Visit(E->getBase()); } - bool VisitIntegerLiteral(IntegerLiteral *E) { return false; } - bool VisitFloatingLiteral(FloatingLiteral *E) { return false; } - bool VisitStringLiteral(StringLiteral *E) { return false; } - bool VisitCharacterLiteral(CharacterLiteral *E) { return false; } - bool VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E) + bool VisitMemberExpr(const MemberExpr *E) { return Visit(E->getBase()); } + bool VisitIntegerLiteral(const IntegerLiteral *E) { return false; } + bool VisitFloatingLiteral(const FloatingLiteral *E) { return false; } + bool VisitStringLiteral(const StringLiteral *E) { return false; } + bool VisitCharacterLiteral(const CharacterLiteral *E) { return false; } + bool VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *E) { return false; } - bool VisitArraySubscriptExpr(ArraySubscriptExpr *E) + bool VisitArraySubscriptExpr(const ArraySubscriptExpr *E) { return Visit(E->getLHS()) || Visit(E->getRHS()); } - bool VisitChooseExpr(ChooseExpr *E) + bool VisitChooseExpr(const ChooseExpr *E) { return Visit(E->getChosenSubExpr(Info.Ctx)); } - bool VisitCastExpr(CastExpr *E) { return Visit(E->getSubExpr()); } - bool VisitBinAssign(BinaryOperator *E) { return true; } - bool VisitCompoundAssignOperator(BinaryOperator *E) { return true; } - bool VisitBinaryOperator(BinaryOperator *E) + bool VisitCastExpr(const CastExpr *E) { return Visit(E->getSubExpr()); } + bool VisitBinAssign(const BinaryOperator *E) { return true; } + bool VisitCompoundAssignOperator(const BinaryOperator *E) { return true; } + bool VisitBinaryOperator(const BinaryOperator *E) { return Visit(E->getLHS()) || Visit(E->getRHS()); } - bool VisitUnaryPreInc(UnaryOperator *E) { return true; } - bool VisitUnaryPostInc(UnaryOperator *E) { return true; } - bool VisitUnaryPreDec(UnaryOperator *E) { return true; } - bool VisitUnaryPostDec(UnaryOperator *E) { return true; } - bool VisitUnaryDeref(UnaryOperator *E) { + bool VisitUnaryPreInc(const UnaryOperator *E) { return true; } + bool VisitUnaryPostInc(const UnaryOperator *E) { return true; } + bool VisitUnaryPreDec(const UnaryOperator *E) { return true; } + bool VisitUnaryPostDec(const UnaryOperator *E) { return true; } + bool VisitUnaryDeref(const UnaryOperator *E) { if (Info.Ctx.getCanonicalType(E->getType()).isVolatileQualified()) return true; return Visit(E->getSubExpr()); } - bool VisitUnaryOperator(UnaryOperator *E) { return Visit(E->getSubExpr()); } + bool VisitUnaryOperator(const UnaryOperator *E) { return Visit(E->getSubExpr()); } // Has side effects if any element does. - bool VisitInitListExpr(InitListExpr *E) { + bool VisitInitListExpr(const InitListExpr *E) { for (unsigned i = 0, e = E->getNumInits(); i != e; ++i) if (Visit(E->getInit(i))) return true; - if (Expr *filler = E->getArrayFiller()) + if (const Expr *filler = E->getArrayFiller()) return Visit(filler); return false; } - bool VisitSizeOfPackExpr(SizeOfPackExpr *) { return false; } + bool VisitSizeOfPackExpr(const SizeOfPackExpr *) { return false; } }; class OpaqueValueEvaluation { @@ -354,15 +354,89 @@ public: } // end anonymous namespace //===----------------------------------------------------------------------===// +// Generic Evaluation +//===----------------------------------------------------------------------===// +namespace { + +template <class Derived, typename RetTy=void> +class ExprEvaluatorBase + : public ConstStmtVisitor<Derived, RetTy> { +private: + RetTy DerivedSuccess(const APValue &V, const Expr *E) { + return static_cast<Derived*>(this)->Success(V, E); + } + RetTy DerivedError(const Expr *E) { + return static_cast<Derived*>(this)->Error(E); + } + +protected: + EvalInfo &Info; + typedef ConstStmtVisitor<Derived, RetTy> StmtVisitorTy; + typedef ExprEvaluatorBase ExprEvaluatorBaseTy; + +public: + ExprEvaluatorBase(EvalInfo &Info) : Info(Info) {} + + RetTy VisitStmt(const Stmt *) { + assert(0 && "Expression evaluator should not be called on stmts"); + return DerivedError(0); + } + RetTy VisitExpr(const Expr *E) { + return DerivedError(E); + } + + RetTy VisitParenExpr(const ParenExpr *E) + { return StmtVisitorTy::Visit(E->getSubExpr()); } + RetTy VisitUnaryExtension(const UnaryOperator *E) + { return StmtVisitorTy::Visit(E->getSubExpr()); } + RetTy VisitUnaryPlus(const UnaryOperator *E) + { return StmtVisitorTy::Visit(E->getSubExpr()); } + RetTy VisitChooseExpr(const ChooseExpr *E) + { return StmtVisitorTy::Visit(E->getChosenSubExpr(Info.Ctx)); } + RetTy VisitGenericSelectionExpr(const GenericSelectionExpr *E) + { return StmtVisitorTy::Visit(E->getResultExpr()); } + + RetTy VisitBinaryConditionalOperator(const BinaryConditionalOperator *E) { + OpaqueValueEvaluation opaque(Info, E->getOpaqueValue(), E->getCommon()); + if (opaque.hasError()) + return DerivedError(E); + + bool cond; + if (!HandleConversionToBool(E->getCond(), cond, Info)) + return DerivedError(E); + + return StmtVisitorTy::Visit(cond ? E->getTrueExpr() : E->getFalseExpr()); + } + + RetTy VisitConditionalOperator(const ConditionalOperator *E) { + bool BoolResult; + if (!HandleConversionToBool(E->getCond(), BoolResult, Info)) + return DerivedError(E); + + Expr* EvalExpr = BoolResult ? E->getTrueExpr() : E->getFalseExpr(); + return StmtVisitorTy::Visit(EvalExpr); + } + + RetTy VisitOpaqueValueExpr(const OpaqueValueExpr *E) { + const APValue *value = Info.getOpaqueValue(E); + if (!value) + return (E->getSourceExpr() ? StmtVisitorTy::Visit(E->getSourceExpr()) + : DerivedError(E)); + return DerivedSuccess(*value, E); + } +}; + +} + +//===----------------------------------------------------------------------===// // LValue Evaluation //===----------------------------------------------------------------------===// namespace { class LValueExprEvaluator - : public StmtVisitor<LValueExprEvaluator, bool> { - EvalInfo &Info; + : public ExprEvaluatorBase<LValueExprEvaluator, bool> { LValue &Result; - bool Success(Expr *E) { + bool Success(const Expr *E) { Result.Base = E; Result.Offset = CharUnits::Zero(); return true; @@ -370,30 +444,26 @@ class LValueExprEvaluator public: LValueExprEvaluator(EvalInfo &info, LValue &Result) : - Info(info), Result(Result) {} + ExprEvaluatorBaseTy(info), Result(Result) {} - bool VisitStmt(Stmt *S) { + bool Success(const APValue &V, const Expr *E) { + Result.setFrom(V); + return true; + } + bool Error(const Expr *E) { return false; } - bool VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); } - bool VisitGenericSelectionExpr(GenericSelectionExpr *E) { - return Visit(E->getResultExpr()); - } - bool VisitDeclRefExpr(DeclRefExpr *E); - bool VisitPredefinedExpr(PredefinedExpr *E) { return Success(E); } - bool VisitCompoundLiteralExpr(CompoundLiteralExpr *E); - bool VisitMemberExpr(MemberExpr *E); - bool VisitStringLiteral(StringLiteral *E) { return Success(E); } - bool VisitObjCEncodeExpr(ObjCEncodeExpr *E) { return Success(E); } - bool VisitArraySubscriptExpr(ArraySubscriptExpr *E); - bool VisitUnaryDeref(UnaryOperator *E); - bool VisitUnaryExtension(const UnaryOperator *E) - { return Visit(E->getSubExpr()); } - bool VisitChooseExpr(const ChooseExpr *E) - { return Visit(E->getChosenSubExpr(Info.Ctx)); } - - bool VisitCastExpr(CastExpr *E) { + bool VisitDeclRefExpr(const DeclRefExpr *E); + bool VisitPredefinedExpr(const PredefinedExpr *E) { return Success(E); } + bool VisitCompoundLiteralExpr(const CompoundLiteralExpr *E); + bool VisitMemberExpr(const MemberExpr *E); + bool VisitStringLiteral(const StringLiteral *E) { return Success(E); } + bool VisitObjCEncodeExpr(const ObjCEncodeExpr *E) { return Success(E); } + bool VisitArraySubscriptExpr(const ArraySubscriptExpr *E); + bool VisitUnaryDeref(const UnaryOperator *E); + + bool VisitCastExpr(const CastExpr *E) { switch (E->getCastKind()) { default: return false; @@ -403,36 +473,37 @@ public: } } // FIXME: Missing: __real__, __imag__ + }; } // end anonymous namespace static bool EvaluateLValue(const Expr* E, LValue& Result, EvalInfo &Info) { - return LValueExprEvaluator(Info, Result).Visit(const_cast<Expr*>(E)); + return LValueExprEvaluator(Info, Result).Visit(E); } -bool LValueExprEvaluator::VisitDeclRefExpr(DeclRefExpr *E) { +bool LValueExprEvaluator::VisitDeclRefExpr(const DeclRefExpr *E) { if (isa<FunctionDecl>(E->getDecl())) { return Success(E); - } else if (VarDecl* VD = dyn_cast<VarDecl>(E->getDecl())) { + } else if (const VarDecl* VD = dyn_cast<VarDecl>(E->getDecl())) { if (!VD->getType()->isReferenceType()) return Success(E); // Reference parameters can refer to anything even if they have an // "initializer" in the form of a default argument. - if (isa<ParmVarDecl>(VD)) - return false; - // FIXME: Check whether VD might be overridden! - if (const Expr *Init = VD->getAnyInitializer()) - return Visit(const_cast<Expr *>(Init)); + if (!isa<ParmVarDecl>(VD)) + // FIXME: Check whether VD might be overridden! + if (const Expr *Init = VD->getAnyInitializer()) + return Visit(Init); } - return false; + return ExprEvaluatorBaseTy::VisitDeclRefExpr(E); } -bool LValueExprEvaluator::VisitCompoundLiteralExpr(CompoundLiteralExpr *E) { +bool +LValueExprEvaluator::VisitCompoundLiteralExpr(const CompoundLiteralExpr *E) { return Success(E); } -bool LValueExprEvaluator::VisitMemberExpr(MemberExpr *E) { +bool LValueExprEvaluator::VisitMemberExpr(const MemberExpr *E) { QualType Ty; if (E->isArrow()) { if (!EvaluatePointer(E->getBase(), Result, Info)) @@ -444,10 +515,10 @@ bool LValueExprEvaluator::VisitMemberExpr(MemberExpr *E) { Ty = E->getBase()->getType(); } - RecordDecl *RD = Ty->getAs<RecordType>()->getDecl(); + const RecordDecl *RD = Ty->getAs<RecordType>()->getDecl(); const ASTRecordLayout &RL = Info.Ctx.getASTRecordLayout(RD); - FieldDecl *FD = dyn_cast<FieldDecl>(E->getMemberDecl()); + const FieldDecl *FD = dyn_cast<FieldDecl>(E->getMemberDecl()); if (!FD) // FIXME: deal with other kinds of member expressions return false; @@ -467,7 +538,7 @@ bool LValueExprEvaluator::VisitMemberExpr(MemberExpr *E) { return true; } -bool LValueExprEvaluator::VisitArraySubscriptExpr(ArraySubscriptExpr *E) { +bool LValueExprEvaluator::VisitArraySubscriptExpr(const ArraySubscriptExpr *E) { if (!EvaluatePointer(E->getBase(), Result, Info)) return false; @@ -480,7 +551,7 @@ bool LValueExprEvaluator::VisitArraySubscriptExpr(ArraySubscriptExpr *E) { return true; } -bool LValueExprEvaluator::VisitUnaryDeref(UnaryOperator *E) { +bool LValueExprEvaluator::VisitUnaryDeref(const UnaryOperator *E) { return EvaluatePointer(E->getSubExpr(), Result, Info); } @@ -490,11 +561,10 @@ bool LValueExprEvaluator::VisitUnaryDeref(UnaryOperator *E) { namespace { class PointerExprEvaluator - : public StmtVisitor<PointerExprEvaluator, bool> { - EvalInfo &Info; + : public ExprEvaluatorBase<PointerExprEvaluator, bool> { LValue &Result; - bool Success(Expr *E) { + bool Success(const Expr *E) { Result.Base = E; Result.Offset = CharUnits::Zero(); return true; @@ -502,49 +572,41 @@ class PointerExprEvaluator public: PointerExprEvaluator(EvalInfo &info, LValue &Result) - : Info(info), Result(Result) {} + : ExprEvaluatorBaseTy(info), Result(Result) {} - bool VisitStmt(Stmt *S) { - return false; + bool Success(const APValue &V, const Expr *E) { + Result.setFrom(V); + return true; } - - bool VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); } - bool VisitGenericSelectionExpr(GenericSelectionExpr *E) { - return Visit(E->getResultExpr()); + bool Error(const Stmt *S) { + return false; } bool VisitBinaryOperator(const BinaryOperator *E); - bool VisitCastExpr(CastExpr* E); - bool VisitUnaryExtension(const UnaryOperator *E) - { return Visit(E->getSubExpr()); } + bool VisitCastExpr(const CastExpr* E); bool VisitUnaryAddrOf(const UnaryOperator *E); - bool VisitObjCStringLiteral(ObjCStringLiteral *E) + bool VisitObjCStringLiteral(const ObjCStringLiteral *E) { return Success(E); } - bool VisitAddrLabelExpr(AddrLabelExpr *E) + bool VisitAddrLabelExpr(const AddrLabelExpr *E) { return Success(E); } - bool VisitCallExpr(CallExpr *E); - bool VisitBlockExpr(BlockExpr *E) { + bool VisitCallExpr(const CallExpr *E); + bool VisitBlockExpr(const BlockExpr *E) { if (!E->getBlockDecl()->hasCaptures()) return Success(E); return false; } - bool VisitImplicitValueInitExpr(ImplicitValueInitExpr *E) + bool VisitImplicitValueInitExpr(const ImplicitValueInitExpr *E) { return Success((Expr*)0); } - bool VisitBinaryConditionalOperator(BinaryConditionalOperator *E); - bool VisitConditionalOperator(ConditionalOperator *E); - bool VisitChooseExpr(ChooseExpr *E) - { return Visit(E->getChosenSubExpr(Info.Ctx)); } - bool VisitCXXNullPtrLiteralExpr(CXXNullPtrLiteralExpr *E) + bool VisitCXXNullPtrLiteralExpr(const CXXNullPtrLiteralExpr *E) { return Success((Expr*)0); } - bool VisitOpaqueValueExpr(OpaqueValueExpr *E); // FIXME: Missing: @protocol, @selector }; } // end anonymous namespace static bool EvaluatePointer(const Expr* E, LValue& Result, EvalInfo &Info) { assert(E->getType()->hasPointerRepresentation()); - return PointerExprEvaluator(Info, Result).Visit(const_cast<Expr*>(E)); + return PointerExprEvaluator(Info, Result).Visit(E); } bool PointerExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { @@ -592,8 +654,8 @@ bool PointerExprEvaluator::VisitUnaryAddrOf(const UnaryOperator *E) { } -bool PointerExprEvaluator::VisitCastExpr(CastExpr* E) { - Expr* SubExpr = E->getSubExpr(); +bool PointerExprEvaluator::VisitCastExpr(const CastExpr* E) { + const Expr* SubExpr = E->getSubExpr(); switch (E->getCastKind()) { default: @@ -671,42 +733,14 @@ bool PointerExprEvaluator::VisitCastExpr(CastExpr* E) { return false; } -bool PointerExprEvaluator::VisitCallExpr(CallExpr *E) { +bool PointerExprEvaluator::VisitCallExpr(const CallExpr *E) { if (E->isBuiltinCall(Info.Ctx) == Builtin::BI__builtin___CFStringMakeConstantString || E->isBuiltinCall(Info.Ctx) == Builtin::BI__builtin___NSStringMakeConstantString) return Success(E); - return false; -} - -bool PointerExprEvaluator::VisitOpaqueValueExpr(OpaqueValueExpr *e) { - const APValue *value = Info.getOpaqueValue(e); - if (!value) - return (e->getSourceExpr() ? Visit(e->getSourceExpr()) : false); - Result.setFrom(*value); - return true; -} - -bool PointerExprEvaluator:: -VisitBinaryConditionalOperator(BinaryConditionalOperator *e) { - OpaqueValueEvaluation opaque(Info, e->getOpaqueValue(), e->getCommon()); - if (opaque.hasError()) return false; - bool cond; - if (!HandleConversionToBool(e->getCond(), cond, Info)) - return false; - - return Visit(cond ? e->getTrueExpr() : e->getFalseExpr()); -} - -bool PointerExprEvaluator::VisitConditionalOperator(ConditionalOperator *E) { - bool BoolResult; - if (!HandleConversionToBool(E->getCond(), BoolResult, Info)) - return false; - - Expr* EvalExpr = BoolResult ? E->getTrueExpr() : E->getFalseExpr(); - return Visit(EvalExpr); + return ExprEvaluatorBaseTy::VisitCallExpr(E); } //===----------------------------------------------------------------------===// @@ -715,25 +749,15 @@ bool PointerExprEvaluator::VisitConditionalOperator(ConditionalOperator *E) { namespace { class VectorExprEvaluator - : public StmtVisitor<VectorExprEvaluator, APValue> { - EvalInfo &Info; + : public ExprEvaluatorBase<VectorExprEvaluator, APValue> { APValue GetZeroVector(QualType VecType); public: - VectorExprEvaluator(EvalInfo &info) : Info(info) {} + VectorExprEvaluator(EvalInfo &info) : ExprEvaluatorBaseTy(info) {} - APValue VisitStmt(Stmt *S) { - return APValue(); - } + APValue Success(const APValue &V, const Expr *E) { return V; } + APValue Error(const Expr *E) { return APValue(); } - APValue VisitParenExpr(ParenExpr *E) - { return Visit(E->getSubExpr()); } - APValue VisitGenericSelectionExpr(GenericSelectionExpr *E) - { return Visit(E->getResultExpr()); } - APValue VisitUnaryExtension(const UnaryOperator *E) - { return Visit(E->getSubExpr()); } - APValue VisitUnaryPlus(const UnaryOperator *E) - { return Visit(E->getSubExpr()); } APValue VisitUnaryReal(const UnaryOperator *E) { return Visit(E->getSubExpr()); } APValue VisitImplicitValueInitExpr(const ImplicitValueInitExpr *E) @@ -741,9 +765,6 @@ namespace { APValue VisitCastExpr(const CastExpr* E); APValue VisitCompoundLiteralExpr(const CompoundLiteralExpr *E); APValue VisitInitListExpr(const InitListExpr *E); - APValue VisitConditionalOperator(const ConditionalOperator *E); - APValue VisitChooseExpr(const ChooseExpr *E) - { return Visit(E->getChosenSubExpr(Info.Ctx)); } APValue VisitUnaryImag(const UnaryOperator *E); // FIXME: Missing: unary -, unary ~, binary add/sub/mul/div, // binary comparisons, binary and/or/xor, @@ -756,7 +777,7 @@ namespace { static bool EvaluateVector(const Expr* E, APValue& Result, EvalInfo &Info) { if (!E->getType()->isVectorType()) return false; - Result = VectorExprEvaluator(Info).Visit(const_cast<Expr*>(E)); + Result = VectorExprEvaluator(Info).Visit(E); return !Result.isUninit(); } @@ -792,7 +813,7 @@ APValue VectorExprEvaluator::VisitCastExpr(const CastExpr* E) { } case CK_BitCast: { if (SETy->isVectorType()) - return Visit(const_cast<Expr*>(SE)); + return Visit(SE); if (!SETy->isIntegerType()) return APValue(); @@ -819,7 +840,7 @@ APValue VectorExprEvaluator::VisitCastExpr(const CastExpr* E) { } case CK_LValueToRValue: case CK_NoOp: - return Visit(const_cast<Expr*>(SE)); + return Visit(SE); default: return APValue(); } @@ -827,7 +848,7 @@ APValue VectorExprEvaluator::VisitCastExpr(const CastExpr* E) { APValue VectorExprEvaluator::VisitCompoundLiteralExpr(const CompoundLiteralExpr *E) { - return this->Visit(const_cast<Expr*>(E->getInitializer())); + return this->Visit(E->getInitializer()); } APValue @@ -905,19 +926,6 @@ VectorExprEvaluator::GetZeroVector(QualType T) { return APValue(&Elements[0], Elements.size()); } -APValue VectorExprEvaluator::VisitConditionalOperator(const ConditionalOperator *E) { - bool BoolResult; - if (!HandleConversionToBool(E->getCond(), BoolResult, Info)) - return APValue(); - - Expr* EvalExpr = BoolResult ? E->getTrueExpr() : E->getFalseExpr(); - - APValue Result; - if (EvaluateVector(EvalExpr, Result, Info)) - return Result; - return APValue(); -} - APValue VectorExprEvaluator::VisitUnaryImag(const UnaryOperator *E) { if (!E->getSubExpr()->isEvaluatable(Info.Ctx)) Info.EvalResult.HasSideEffects = true; @@ -930,17 +938,16 @@ APValue VectorExprEvaluator::VisitUnaryImag(const UnaryOperator *E) { namespace { class IntExprEvaluator - : public StmtVisitor<IntExprEvaluator, bool> { - EvalInfo &Info; + : public ExprEvaluatorBase<IntExprEvaluator, bool> { APValue &Result; public: IntExprEvaluator(EvalInfo &info, APValue &result) - : Info(info), Result(result) {} + : ExprEvaluatorBaseTy(info), Result(result) {} bool Success(const llvm::APSInt &SI, const Expr *E) { assert(E->getType()->isIntegralOrEnumerationType() && "Invalid evaluation result."); - assert(SI.isSigned() == E->getType()->isSignedIntegerType() && + assert(SI.isSigned() == E->getType()->isSignedIntegerOrEnumerationType() && "Invalid evaluation result."); assert(SI.getBitWidth() == Info.Ctx.getIntWidth(E->getType()) && "Invalid evaluation result."); @@ -954,7 +961,8 @@ public: assert(I.getBitWidth() == Info.Ctx.getIntWidth(E->getType()) && "Invalid evaluation result."); Result = APValue(APSInt(I)); - Result.getInt().setIsUnsigned(E->getType()->isUnsignedIntegerType()); + Result.getInt().setIsUnsigned( + E->getType()->isUnsignedIntegerOrEnumerationType()); return true; } @@ -980,23 +988,16 @@ public: return false; } - //===--------------------------------------------------------------------===// - // Visitor Methods - //===--------------------------------------------------------------------===// - - bool VisitStmt(Stmt *) { - assert(0 && "This should be called on integers, stmts are not integers"); - return false; + bool Success(const APValue &V, const Expr *E) { + return Success(V.getInt(), E); } - - bool VisitExpr(Expr *E) { + bool Error(const Expr *E) { return Error(E->getLocStart(), diag::note_invalid_subexpr_in_ice, E); } - bool VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); } - bool VisitGenericSelectionExpr(GenericSelectionExpr *E) { - return Visit(E->getResultExpr()); - } + //===--------------------------------------------------------------------===// + // Visitor Methods + //===--------------------------------------------------------------------===// bool VisitIntegerLiteral(const IntegerLiteral *E) { return Success(E->getValue(), E); @@ -1005,18 +1006,12 @@ public: return Success(E->getValue(), E); } - bool VisitOpaqueValueExpr(OpaqueValueExpr *e) { - const APValue *value = Info.getOpaqueValue(e); - if (!value) { - if (e->getSourceExpr()) return Visit(e->getSourceExpr()); - return Error(e->getExprLoc(), diag::note_invalid_subexpr_in_ice, e); - } - return Success(value->getInt(), e); - } - bool CheckReferencedDecl(const Expr *E, const Decl *D); bool VisitDeclRefExpr(const DeclRefExpr *E) { - return CheckReferencedDecl(E, E->getDecl()); + if (CheckReferencedDecl(E, E->getDecl())) + return true; + + return ExprEvaluatorBaseTy::VisitDeclRefExpr(E); } bool VisitMemberExpr(const MemberExpr *E) { if (CheckReferencedDecl(E, E->getMemberDecl())) { @@ -1024,17 +1019,16 @@ public: Info.EvalResult.HasSideEffects = true; return true; } - return false; + + return ExprEvaluatorBaseTy::VisitMemberExpr(E); } - bool VisitCallExpr(CallExpr *E); + bool VisitCallExpr(const CallExpr *E); bool VisitBinaryOperator(const BinaryOperator *E); bool VisitOffsetOfExpr(const OffsetOfExpr *E); bool VisitUnaryOperator(const UnaryOperator *E); - bool VisitConditionalOperator(const ConditionalOperator *E); - bool VisitBinaryConditionalOperator(const BinaryConditionalOperator *E); - bool VisitCastExpr(CastExpr* E); + bool VisitCastExpr(const CastExpr* E); bool VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *E); bool VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *E) { @@ -1069,10 +1063,6 @@ public: return Success(E->getValue(), E); } - bool VisitChooseExpr(const ChooseExpr *E) { - return Visit(E->getChosenSubExpr(Info.Ctx)); - } - bool VisitUnaryReal(const UnaryOperator *E); bool VisitUnaryImag(const UnaryOperator *E); @@ -1083,14 +1073,14 @@ private: CharUnits GetAlignOfExpr(const Expr *E); CharUnits GetAlignOfType(QualType T); static QualType GetObjectType(const Expr *E); - bool TryEvaluateBuiltinObjectSize(CallExpr *E); + bool TryEvaluateBuiltinObjectSize(const CallExpr *E); // FIXME: Missing: array subscript of vector, member of vector }; } // end anonymous namespace static bool EvaluateIntegerOrLValue(const Expr* E, APValue &Result, EvalInfo &Info) { assert(E->getType()->isIntegralOrEnumerationType()); - return IntExprEvaluator(Info, Result).Visit(const_cast<Expr*>(E)); + return IntExprEvaluator(Info, Result).Visit(E); } static bool EvaluateInteger(const Expr* E, APSInt &Result, EvalInfo &Info) { @@ -1114,18 +1104,18 @@ bool IntExprEvaluator::CheckReferencedDecl(const Expr* E, const Decl* D) { == Qualifiers::Const) { if (isa<ParmVarDecl>(D)) - return Error(E->getLocStart(), diag::note_invalid_subexpr_in_ice, E); + return false; if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { if (const Expr *Init = VD->getAnyInitializer()) { if (APValue *V = VD->getEvaluatedValue()) { if (V->isInt()) return Success(V->getInt(), E); - return Error(E->getLocStart(), diag::note_invalid_subexpr_in_ice, E); + return false; } if (VD->isEvaluatingValue()) - return Error(E->getLocStart(), diag::note_invalid_subexpr_in_ice, E); + return false; VD->setEvaluatingValue(); @@ -1144,7 +1134,7 @@ bool IntExprEvaluator::CheckReferencedDecl(const Expr* E, const Decl* D) { } // Otherwise, random variable references are not constants. - return Error(E->getLocStart(), diag::note_invalid_subexpr_in_ice, E); + return false; } /// EvaluateBuiltinClassifyType - Evaluate __builtin_classify_type the same way @@ -1216,7 +1206,7 @@ QualType IntExprEvaluator::GetObjectType(const Expr *E) { return QualType(); } -bool IntExprEvaluator::TryEvaluateBuiltinObjectSize(CallExpr *E) { +bool IntExprEvaluator::TryEvaluateBuiltinObjectSize(const CallExpr *E) { // TODO: Perhaps we should let LLVM lower this? LValue Base; if (!EvaluatePointer(E->getArg(0), Base, Info)) @@ -1244,10 +1234,10 @@ bool IntExprEvaluator::TryEvaluateBuiltinObjectSize(CallExpr *E) { return Success(Size, E); } -bool IntExprEvaluator::VisitCallExpr(CallExpr *E) { +bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) { switch (E->isBuiltinCall(Info.Ctx)) { default: - return Error(E->getLocStart(), diag::note_invalid_subexpr_in_ice, E); + return ExprEvaluatorBaseTy::VisitCallExpr(E); case Builtin::BI__builtin_object_size: { if (TryEvaluateBuiltinObjectSize(E)) @@ -1285,7 +1275,7 @@ bool IntExprEvaluator::VisitCallExpr(CallExpr *E) { case Builtin::BI__builtin_strlen: // As an extension, we support strlen() and __builtin_strlen() as constant // expressions when the argument is a string literal. - if (StringLiteral *S + if (const StringLiteral *S = dyn_cast<StringLiteral>(E->getArg(0)->IgnoreParenImpCasts())) { // The string literal may have embedded null characters. Find the first // one and truncate there. @@ -1574,26 +1564,6 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { } } -bool IntExprEvaluator:: -VisitBinaryConditionalOperator(const BinaryConditionalOperator *e) { - OpaqueValueEvaluation opaque(Info, e->getOpaqueValue(), e->getCommon()); - if (opaque.hasError()) return false; - - bool cond; - if (!HandleConversionToBool(e->getCond(), cond, Info)) - return false; - - return Visit(cond ? e->getTrueExpr() : e->getFalseExpr()); -} - -bool IntExprEvaluator::VisitConditionalOperator(const ConditionalOperator *E) { - bool Cond; - if (!HandleConversionToBool(E->getCond(), Cond, Info)) - return false; - - return Visit(Cond ? E->getTrueExpr() : E->getFalseExpr()); -} - CharUnits IntExprEvaluator::GetAlignOfType(QualType T) { // C++ [expr.sizeof]p2: "When applied to a reference or a reference type, // the result is the size of the referenced type." @@ -1679,18 +1649,17 @@ bool IntExprEvaluator::VisitUnaryExprOrTypeTraitExpr( return false; } -bool IntExprEvaluator::VisitOffsetOfExpr(const OffsetOfExpr *E) { +bool IntExprEvaluator::VisitOffsetOfExpr(const OffsetOfExpr *OOE) { CharUnits Result; - unsigned n = E->getNumComponents(); - OffsetOfExpr* OOE = const_cast<OffsetOfExpr*>(E); + unsigned n = OOE->getNumComponents(); if (n == 0) return false; - QualType CurrentType = E->getTypeSourceInfo()->getType(); + QualType CurrentType = OOE->getTypeSourceInfo()->getType(); for (unsigned i = 0; i != n; ++i) { OffsetOfExpr::OffsetOfNode ON = OOE->getComponent(i); switch (ON.getKind()) { case OffsetOfExpr::OffsetOfNode::Array: { - Expr *Idx = OOE->getIndexExpr(ON.getArrayExprIndex()); + const Expr *Idx = OOE->getIndexExpr(ON.getArrayExprIndex()); APSInt IdxResult; if (!EvaluateInteger(Idx, IdxResult, Info)) return false; @@ -1745,7 +1714,7 @@ bool IntExprEvaluator::VisitOffsetOfExpr(const OffsetOfExpr *E) { } } } - return Success(Result, E); + return Success(Result, OOE); } bool IntExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) { @@ -1788,8 +1757,8 @@ bool IntExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) { /// HandleCast - This is used to evaluate implicit or explicit casts where the /// result type is integer. -bool IntExprEvaluator::VisitCastExpr(CastExpr *E) { - Expr *SubExpr = E->getSubExpr(); +bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) { + const Expr *SubExpr = E->getSubExpr(); QualType DestType = E->getType(); QualType SrcType = SubExpr->getType(); @@ -1936,48 +1905,33 @@ bool IntExprEvaluator::VisitCXXNoexceptExpr(const CXXNoexceptExpr *E) { namespace { class FloatExprEvaluator - : public StmtVisitor<FloatExprEvaluator, bool> { - EvalInfo &Info; + : public ExprEvaluatorBase<FloatExprEvaluator, bool> { APFloat &Result; public: FloatExprEvaluator(EvalInfo &info, APFloat &result) - : Info(info), Result(result) {} + : ExprEvaluatorBaseTy(info), Result(result) {} - bool VisitStmt(Stmt *S) { + bool Success(const APValue &V, const Expr *e) { + Result = V.getFloat(); + return true; + } + bool Error(const Stmt *S) { return false; } - bool VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); } - bool VisitGenericSelectionExpr(GenericSelectionExpr *E) { - return Visit(E->getResultExpr()); - } bool VisitCallExpr(const CallExpr *E); bool VisitUnaryOperator(const UnaryOperator *E); bool VisitBinaryOperator(const BinaryOperator *E); bool VisitFloatingLiteral(const FloatingLiteral *E); - bool VisitCastExpr(CastExpr *E); - bool VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *E); - bool VisitConditionalOperator(ConditionalOperator *E); - bool VisitBinaryConditionalOperator(BinaryConditionalOperator *E); + bool VisitCastExpr(const CastExpr *E); + bool VisitCXXScalarValueInitExpr(const CXXScalarValueInitExpr *E); - bool VisitChooseExpr(const ChooseExpr *E) - { return Visit(E->getChosenSubExpr(Info.Ctx)); } - bool VisitUnaryExtension(const UnaryOperator *E) - { return Visit(E->getSubExpr()); } bool VisitUnaryReal(const UnaryOperator *E); bool VisitUnaryImag(const UnaryOperator *E); bool VisitDeclRefExpr(const DeclRefExpr *E); - bool VisitOpaqueValueExpr(const OpaqueValueExpr *e) { - const APValue *value = Info.getOpaqueValue(e); - if (!value) - return (e->getSourceExpr() ? Visit(e->getSourceExpr()) : false); - Result = value->getFloat(); - return true; - } - // FIXME: Missing: array subscript of vector, member of vector, // ImplicitValueInitExpr }; @@ -1985,7 +1939,7 @@ public: static bool EvaluateFloat(const Expr* E, APFloat& Result, EvalInfo &Info) { assert(E->getType()->isRealFloatingType()); - return FloatExprEvaluator(Info, Result).Visit(const_cast<Expr*>(E)); + return FloatExprEvaluator(Info, Result).Visit(E); } static bool TryEvaluateBuiltinNaN(const ASTContext &Context, @@ -2015,7 +1969,9 @@ static bool TryEvaluateBuiltinNaN(const ASTContext &Context, bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) { switch (E->isBuiltinCall(Info.Ctx)) { - default: return false; + default: + return ExprEvaluatorBaseTy::VisitCallExpr(E); + case Builtin::BI__builtin_huge_val: case Builtin::BI__builtin_huge_valf: case Builtin::BI__builtin_huge_vall: @@ -2066,6 +2022,9 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) { } bool FloatExprEvaluator::VisitDeclRefExpr(const DeclRefExpr *E) { + if (ExprEvaluatorBaseTy::VisitDeclRefExpr(E)) + return true; + const Decl *D = E->getDecl(); if (!isa<VarDecl>(D) || isa<ParmVarDecl>(D)) return false; const VarDecl *VD = cast<VarDecl>(D); @@ -2196,8 +2155,8 @@ bool FloatExprEvaluator::VisitFloatingLiteral(const FloatingLiteral *E) { return true; } -bool FloatExprEvaluator::VisitCastExpr(CastExpr *E) { - Expr* SubExpr = E->getSubExpr(); +bool FloatExprEvaluator::VisitCastExpr(const CastExpr *E) { + const Expr* SubExpr = E->getSubExpr(); switch (E->getCastKind()) { default: @@ -2236,77 +2195,42 @@ bool FloatExprEvaluator::VisitCastExpr(CastExpr *E) { return false; } -bool FloatExprEvaluator::VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *E) { +bool FloatExprEvaluator::VisitCXXScalarValueInitExpr(const CXXScalarValueInitExpr *E) { Result = APFloat::getZero(Info.Ctx.getFloatTypeSemantics(E->getType())); return true; } -bool FloatExprEvaluator:: -VisitBinaryConditionalOperator(BinaryConditionalOperator *e) { - OpaqueValueEvaluation opaque(Info, e->getOpaqueValue(), e->getCommon()); - if (opaque.hasError()) return false; - - bool cond; - if (!HandleConversionToBool(e->getCond(), cond, Info)) - return false; - - return Visit(cond ? e->getTrueExpr() : e->getFalseExpr()); -} - -bool FloatExprEvaluator::VisitConditionalOperator(ConditionalOperator *E) { - bool Cond; - if (!HandleConversionToBool(E->getCond(), Cond, Info)) - return false; - - return Visit(Cond ? E->getTrueExpr() : E->getFalseExpr()); -} - //===----------------------------------------------------------------------===// // Complex Evaluation (for float and integer) //===----------------------------------------------------------------------===// namespace { class ComplexExprEvaluator - : public StmtVisitor<ComplexExprEvaluator, bool> { - EvalInfo &Info; + : public ExprEvaluatorBase<ComplexExprEvaluator, bool> { ComplexValue &Result; public: ComplexExprEvaluator(EvalInfo &info, ComplexValue &Result) - : Info(info), Result(Result) {} + : ExprEvaluatorBaseTy(info), Result(Result) {} - //===--------------------------------------------------------------------===// - // Visitor Methods - //===--------------------------------------------------------------------===// - - bool VisitStmt(Stmt *S) { + bool Success(const APValue &V, const Expr *e) { + Result.setFrom(V); + return true; + } + bool Error(const Expr *E) { return false; } - bool VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); } - bool VisitGenericSelectionExpr(GenericSelectionExpr *E) { - return Visit(E->getResultExpr()); - } + //===--------------------------------------------------------------------===// + // Visitor Methods + //===--------------------------------------------------------------------===// - bool VisitImaginaryLiteral(ImaginaryLiteral *E); + bool VisitImaginaryLiteral(const ImaginaryLiteral *E); - bool VisitCastExpr(CastExpr *E); + bool VisitCastExpr(const CastExpr *E); bool VisitBinaryOperator(const BinaryOperator *E); bool VisitUnaryOperator(const UnaryOperator *E); - bool VisitConditionalOperator(const ConditionalOperator *E); - bool VisitBinaryConditionalOperator(const BinaryConditionalOperator *E); - bool VisitChooseExpr(const ChooseExpr *E) - { return Visit(E->getChosenSubExpr(Info.Ctx)); } - bool VisitUnaryExtension(const UnaryOperator *E) - { return Visit(E->getSubExpr()); } - bool VisitOpaqueValueExpr(const OpaqueValueExpr *e) { - const APValue *value = Info.getOpaqueValue(e); - if (!value) - return (e->getSourceExpr() ? Visit(e->getSourceExpr()) : false); - Result.setFrom(*value); - return true; - } // FIXME Missing: ImplicitValueInitExpr }; } // end anonymous namespace @@ -2314,11 +2238,11 @@ public: static bool EvaluateComplex(const Expr *E, ComplexValue &Result, EvalInfo &Info) { assert(E->getType()->isAnyComplexType()); - return ComplexExprEvaluator(Info, Result).Visit(const_cast<Expr*>(E)); + return ComplexExprEvaluator(Info, Result).Visit(E); } -bool ComplexExprEvaluator::VisitImaginaryLiteral(ImaginaryLiteral *E) { - Expr* SubExpr = E->getSubExpr(); +bool ComplexExprEvaluator::VisitImaginaryLiteral(const ImaginaryLiteral *E) { + const Expr* SubExpr = E->getSubExpr(); if (SubExpr->getType()->isRealFloatingType()) { Result.makeComplexFloat(); @@ -2342,7 +2266,7 @@ bool ComplexExprEvaluator::VisitImaginaryLiteral(ImaginaryLiteral *E) { } } -bool ComplexExprEvaluator::VisitCastExpr(CastExpr *E) { +bool ComplexExprEvaluator::VisitCastExpr(const CastExpr *E) { switch (E->getCastKind()) { case CK_BitCast: @@ -2627,26 +2551,6 @@ bool ComplexExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) { } } -bool ComplexExprEvaluator:: -VisitBinaryConditionalOperator(const BinaryConditionalOperator *e) { - OpaqueValueEvaluation opaque(Info, e->getOpaqueValue(), e->getCommon()); - if (opaque.hasError()) return false; - - bool cond; - if (!HandleConversionToBool(e->getCond(), cond, Info)) - return false; - - return Visit(cond ? e->getTrueExpr() : e->getFalseExpr()); -} - -bool ComplexExprEvaluator::VisitConditionalOperator(const ConditionalOperator *E) { - bool Cond; - if (!HandleConversionToBool(E->getCond(), Cond, Info)) - return false; - - return Visit(Cond ? E->getTrueExpr() : E->getFalseExpr()); -} - //===----------------------------------------------------------------------===// // Top level Expr::Evaluate method. //===----------------------------------------------------------------------===// @@ -2655,8 +2559,8 @@ static bool Evaluate(EvalInfo &Info, const Expr *E) { if (E->getType()->isVectorType()) { if (!EvaluateVector(E, Info.EvalResult.Val, Info)) return false; - } else if (E->getType()->isIntegerType()) { - if (!IntExprEvaluator(Info, Info.EvalResult.Val).Visit(const_cast<Expr*>(E))) + } else if (E->getType()->isIntegralOrEnumerationType()) { + if (!IntExprEvaluator(Info, Info.EvalResult.Val).Visit(E)) return false; if (Info.EvalResult.Val.isLValue() && !IsGlobalLValue(Info.EvalResult.Val.getLValueBase())) @@ -2737,7 +2641,7 @@ bool Expr::isEvaluatable(const ASTContext &Ctx) const { bool Expr::HasSideEffects(const ASTContext &Ctx) const { Expr::EvalResult Result; EvalInfo Info(Ctx, Result); - return HasSideEffect(Info).Visit(const_cast<Expr*>(this)); + return HasSideEffect(Info).Visit(this); } APSInt Expr::EvaluateAsInt(const ASTContext &Ctx) const { @@ -2866,6 +2770,7 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { case Expr::OpaqueValueExprClass: case Expr::PackExpansionExprClass: case Expr::SubstNonTypeTemplateParmPackExprClass: + case Expr::AsTypeExprClass: return ICEDiag(2, E->getLocStart()); case Expr::SizeOfPackExprClass: @@ -3053,6 +2958,21 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { case BO_LAnd: case BO_LOr: { ICEDiag LHSResult = CheckICE(Exp->getLHS(), Ctx); + + // C++0x [expr.const]p2: + // [...] subexpressions of logical AND (5.14), logical OR + // (5.15), and condi- tional (5.16) operations that are not + // evaluated are not considered. + if (Ctx.getLangOptions().CPlusPlus0x && LHSResult.Val == 0) { + if (Exp->getOpcode() == BO_LAnd && + Exp->getLHS()->EvaluateAsInt(Ctx) == 0) + return LHSResult; + + if (Exp->getOpcode() == BO_LOr && + Exp->getLHS()->EvaluateAsInt(Ctx) != 0) + return LHSResult; + } + ICEDiag RHSResult = CheckICE(Exp->getRHS(), Ctx); if (LHSResult.Val == 0 && RHSResult.Val == 1) { // Rare case where the RHS has a comma "side-effect"; we need @@ -3111,10 +3031,22 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { return NoDiag(); } ICEDiag CondResult = CheckICE(Exp->getCond(), Ctx); - ICEDiag TrueResult = CheckICE(Exp->getTrueExpr(), Ctx); - ICEDiag FalseResult = CheckICE(Exp->getFalseExpr(), Ctx); if (CondResult.Val == 2) return CondResult; + + // C++0x [expr.const]p2: + // subexpressions of [...] conditional (5.16) operations that + // are not evaluated are not considered + bool TrueBranch = Ctx.getLangOptions().CPlusPlus0x + ? Exp->getCond()->EvaluateAsInt(Ctx) != 0 + : false; + ICEDiag TrueResult = NoDiag(); + if (!Ctx.getLangOptions().CPlusPlus0x || TrueBranch) + TrueResult = CheckICE(Exp->getTrueExpr(), Ctx); + ICEDiag FalseResult = NoDiag(); + if (!Ctx.getLangOptions().CPlusPlus0x || !TrueBranch) + FalseResult = CheckICE(Exp->getFalseExpr(), Ctx); + if (TrueResult.Val == 2) return TrueResult; if (FalseResult.Val == 2) diff --git a/contrib/llvm/tools/clang/lib/AST/ExternalASTSource.cpp b/contrib/llvm/tools/clang/lib/AST/ExternalASTSource.cpp index 89bf56d..f428318 100644 --- a/contrib/llvm/tools/clang/lib/AST/ExternalASTSource.cpp +++ b/contrib/llvm/tools/clang/lib/AST/ExternalASTSource.cpp @@ -57,3 +57,5 @@ ExternalASTSource::FindExternalLexicalDecls(const DeclContext *DC, llvm::SmallVectorImpl<Decl*> &Result) { return true; } + +void ExternalASTSource::getMemoryBufferSizes(MemoryBufferSizes &sizes) const { } diff --git a/contrib/llvm/tools/clang/lib/AST/ItaniumMangle.cpp b/contrib/llvm/tools/clang/lib/AST/ItaniumMangle.cpp index c460929..e81ec7e 100644 --- a/contrib/llvm/tools/clang/lib/AST/ItaniumMangle.cpp +++ b/contrib/llvm/tools/clang/lib/AST/ItaniumMangle.cpp @@ -255,7 +255,8 @@ private: DeclarationName name, unsigned KnownArity = UnknownArity); - void mangleUnresolvedType(QualType type); + static bool isUnresolvedType(const Type *type); + void mangleUnresolvedType(const Type *type); void mangleName(const TemplateDecl *TD, const TemplateArgument *TemplateArgs, @@ -277,6 +278,7 @@ private: unsigned NumTemplateArgs); void manglePrefix(NestedNameSpecifier *qualifier); void manglePrefix(const DeclContext *DC, bool NoFunction=false); + void manglePrefix(QualType type); void mangleTemplatePrefix(const TemplateDecl *ND); void mangleTemplatePrefix(TemplateName Template); void mangleOperatorName(OverloadedOperatorKind OO, unsigned Arity); @@ -317,6 +319,8 @@ private: void mangleTemplateArgs(const TemplateParameterList &PL, const TemplateArgumentList &AL); void mangleTemplateArg(const NamedDecl *P, const TemplateArgument &A); + void mangleUnresolvedTemplateArgs(const TemplateArgument *args, + unsigned numArgs); void mangleTemplateParameter(unsigned Index); @@ -667,7 +671,7 @@ void CXXNameMangler::mangleCallOffset(int64_t NonVirtual, int64_t Virtual) { Out << '_'; } -void CXXNameMangler::mangleUnresolvedType(QualType type) { +void CXXNameMangler::manglePrefix(QualType type) { if (const TemplateSpecializationType *TST = type->getAs<TemplateSpecializationType>()) { if (!mangleSubstitution(QualType(TST, 0))) { @@ -698,6 +702,31 @@ void CXXNameMangler::mangleUnresolvedType(QualType type) { } } +/// Returns true if the given type, appearing within an +/// unresolved-name, should be mangled as an unresolved-type. +bool CXXNameMangler::isUnresolvedType(const Type *type) { + // <unresolved-type> ::= <template-param> + // ::= <decltype> + // ::= <template-template-param> <template-args> + // (this last is not official yet) + + if (isa<TemplateTypeParmType>(type)) return true; + if (isa<DecltypeType>(type)) return true; + // typeof? + if (const TemplateSpecializationType *tst = + dyn_cast<TemplateSpecializationType>(type)) { + TemplateDecl *temp = tst->getTemplateName().getAsTemplateDecl(); + if (temp && isa<TemplateTemplateParmDecl>(temp)) + return true; + } + return false; +} + +void CXXNameMangler::mangleUnresolvedType(const Type *type) { + // This seems to be do everything we want. + mangleType(QualType(type, 0)); +} + /// Mangle everything prior to the base-unresolved-name in an unresolved-name. /// /// \param firstQualifierLookup - the entity found by unqualified lookup @@ -752,17 +781,60 @@ void CXXNameMangler::mangleUnresolvedPrefix(NestedNameSpecifier *qualifier, case NestedNameSpecifier::TypeSpec: case NestedNameSpecifier::TypeSpecWithTemplate: { - // Both cases want this. - Out << "sr"; + const Type *type = qualifier->getAsType(); - // We only get here recursively if we're followed by identifiers. - if (recursive) Out << 'N'; + // We only want to use an unresolved-type encoding if this is one of: + // - a decltype + // - a template type parameter + // - a template template parameter with arguments + // In all of these cases, we should have no prefix. + if (qualifier->getPrefix()) { + mangleUnresolvedPrefix(qualifier->getPrefix(), firstQualifierLookup, + /*recursive*/ true); + } else { + // Otherwise, all the cases want this. + Out << "sr"; - mangleUnresolvedType(QualType(qualifier->getAsType(), 0)); + if (isUnresolvedType(type)) { + // We only get here recursively if we're followed by identifiers. + if (recursive) Out << 'N'; + mangleUnresolvedType(type); - // We never want to print 'E' directly after an unresolved-type, - // so we return directly. - return; + // We never want to print 'E' directly after an unresolved-type, + // so we return directly. + return; + } + } + + assert(!isUnresolvedType(type)); + + // Only certain other types are valid as prefixes; enumerate them. + // FIXME: can we get ElaboratedTypes here? + // FIXME: SubstTemplateTypeParmType? + if (const TagType *t = dyn_cast<TagType>(type)) { + mangleSourceName(t->getDecl()->getIdentifier()); + } else if (const TypedefType *t = dyn_cast<TypedefType>(type)) { + mangleSourceName(t->getDecl()->getIdentifier()); + } else if (const UnresolvedUsingType *t + = dyn_cast<UnresolvedUsingType>(type)) { + mangleSourceName(t->getDecl()->getIdentifier()); + } else if (const DependentNameType *t + = dyn_cast<DependentNameType>(type)) { + mangleSourceName(t->getIdentifier()); + } else if (const TemplateSpecializationType *tst + = dyn_cast<TemplateSpecializationType>(type)) { + TemplateDecl *temp = tst->getTemplateName().getAsTemplateDecl(); + assert(temp && "no template for template specialization type"); + mangleSourceName(temp->getIdentifier()); + mangleUnresolvedTemplateArgs(tst->getArgs(), tst->getNumArgs()); + } else if (const DependentTemplateSpecializationType *tst + = dyn_cast<DependentTemplateSpecializationType>(type)) { + mangleSourceName(tst->getIdentifier()); + mangleUnresolvedTemplateArgs(tst->getArgs(), tst->getNumArgs()); + } else { + llvm_unreachable("unexpected type in nested name specifier!"); + } + break; } case NestedNameSpecifier::Identifier: @@ -1050,6 +1122,12 @@ void CXXNameMangler::mangleLocalName(const NamedDecl *ND) { // := Z <function encoding> E s [<discriminator>] // <discriminator> := _ <non-negative number> const DeclContext *DC = ND->getDeclContext(); + if (isa<ObjCMethodDecl>(DC) && isa<FunctionDecl>(ND)) { + // Don't add objc method name mangling to locally declared function + mangleUnqualifiedName(ND); + return; + } + Out << 'Z'; if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(DC)) { @@ -1097,7 +1175,7 @@ void CXXNameMangler::manglePrefix(NestedNameSpecifier *qualifier) { case NestedNameSpecifier::TypeSpec: case NestedNameSpecifier::TypeSpecWithTemplate: - mangleUnresolvedType(QualType(qualifier->getAsType(), 0)); + manglePrefix(QualType(qualifier->getAsType(), 0)); return; case NestedNameSpecifier::Identifier: @@ -1867,6 +1945,22 @@ void CXXNameMangler::mangleType(const DecltypeType *T) { Out << 'E'; } +void CXXNameMangler::mangleType(const UnaryTransformType *T) { + // If this is dependent, we need to record that. If not, we simply + // mangle it as the underlying type since they are equivalent. + if (T->isDependentType()) { + Out << 'U'; + + switch (T->getUTTKind()) { + case UnaryTransformType::EnumUnderlyingType: + Out << "3eut"; + break; + } + } + + mangleType(T->getUnderlyingType()); +} + void CXXNameMangler::mangleType(const AutoType *T) { QualType D = T->getDeducedType(); // <builtin-type> ::= Da # dependent auto @@ -1951,6 +2045,7 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) { // ::= <function-param> // ::= sr <type> <unqualified-name> # dependent name // ::= sr <type> <unqualified-name> <template-args> # dependent template-id + // ::= ds <expression> <expression> # expr.*expr // ::= sZ <template-param> # size of a parameter pack // ::= sZ <function-param> # size of a function parameter pack // ::= <expr-primary> @@ -2005,7 +2100,9 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) { case Expr::VAArgExprClass: case Expr::CXXUuidofExprClass: case Expr::CXXNoexceptExprClass: - case Expr::CUDAKernelCallExprClass: { + case Expr::CUDAKernelCallExprClass: + case Expr::AsTypeExprClass: + { // As bad as this diagnostic is, it's better than crashing. Diagnostic &Diags = Context.getDiags(); unsigned DiagID = Diags.getCustomDiagID(Diagnostic::Error, @@ -2227,8 +2324,11 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) { case Expr::CompoundAssignOperatorClass: // fallthrough case Expr::BinaryOperatorClass: { const BinaryOperator *BO = cast<BinaryOperator>(E); - mangleOperatorName(BinaryOperator::getOverloadedOperator(BO->getOpcode()), - /*Arity=*/2); + if (BO->getOpcode() == BO_PtrMemD) + Out << "ds"; + else + mangleOperatorName(BinaryOperator::getOverloadedOperator(BO->getOpcode()), + /*Arity=*/2); mangleExpression(BO->getLHS()); mangleExpression(BO->getRHS()); break; @@ -2552,8 +2652,8 @@ void CXXNameMangler::mangleTemplateArgs( const ExplicitTemplateArgumentList &TemplateArgs) { // <template-args> ::= I <template-arg>+ E Out << 'I'; - for (unsigned I = 0, E = TemplateArgs.NumTemplateArgs; I != E; ++I) - mangleTemplateArg(0, TemplateArgs.getTemplateArgs()[I].getArgument()); + for (unsigned i = 0, e = TemplateArgs.NumTemplateArgs; i != e; ++i) + mangleTemplateArg(0, TemplateArgs.getTemplateArgs()[i].getArgument()); Out << 'E'; } @@ -2564,10 +2664,15 @@ void CXXNameMangler::mangleTemplateArgs(TemplateName Template, return mangleTemplateArgs(*TD->getTemplateParameters(), TemplateArgs, NumTemplateArgs); + mangleUnresolvedTemplateArgs(TemplateArgs, NumTemplateArgs); +} + +void CXXNameMangler::mangleUnresolvedTemplateArgs(const TemplateArgument *args, + unsigned numArgs) { // <template-args> ::= I <template-arg>+ E Out << 'I'; - for (unsigned i = 0; i != NumTemplateArgs; ++i) - mangleTemplateArg(0, TemplateArgs[i]); + for (unsigned i = 0; i != numArgs; ++i) + mangleTemplateArg(0, args[i]); Out << 'E'; } diff --git a/contrib/llvm/tools/clang/lib/AST/Mangle.cpp b/contrib/llvm/tools/clang/lib/AST/Mangle.cpp index 3a0b909..c3f3b11 100644 --- a/contrib/llvm/tools/clang/lib/AST/Mangle.cpp +++ b/contrib/llvm/tools/clang/lib/AST/Mangle.cpp @@ -48,6 +48,11 @@ static void checkMangleDC(const DeclContext *DC, const BlockDecl *BD) { const DeclContext *ExpectedDC = BD->getDeclContext(); while (isa<BlockDecl>(ExpectedDC) || isa<EnumDecl>(ExpectedDC)) ExpectedDC = ExpectedDC->getParent(); + // In-class initializers for non-static data members are lexically defined + // within the class, but are mangled as if they were specified as constructor + // member initializers. + if (isa<CXXRecordDecl>(ExpectedDC) && DC != ExpectedDC) + DC = DC->getParent(); assert(DC == ExpectedDC && "Given decl context did not match expected!"); #endif } diff --git a/contrib/llvm/tools/clang/lib/AST/MicrosoftMangle.cpp b/contrib/llvm/tools/clang/lib/AST/MicrosoftMangle.cpp index 5424beb..4f920f9 100644 --- a/contrib/llvm/tools/clang/lib/AST/MicrosoftMangle.cpp +++ b/contrib/llvm/tools/clang/lib/AST/MicrosoftMangle.cpp @@ -1113,6 +1113,10 @@ void MicrosoftCXXNameMangler::mangleType(const DecltypeType *T) { assert(false && "Don't know how to mangle DecltypeTypes yet!"); } +void MicrosoftCXXNameMangler::mangleType(const UnaryTransformType *T) { + assert(false && "Don't know how to mangle UnaryTransformationTypes yet!"); +} + void MicrosoftCXXNameMangler::mangleType(const AutoType *T) { assert(false && "Don't know how to mangle AutoTypes yet!"); } diff --git a/contrib/llvm/tools/clang/lib/AST/RecordLayoutBuilder.cpp b/contrib/llvm/tools/clang/lib/AST/RecordLayoutBuilder.cpp index 0770e1f..de0b1d0 100644 --- a/contrib/llvm/tools/clang/lib/AST/RecordLayoutBuilder.cpp +++ b/contrib/llvm/tools/clang/lib/AST/RecordLayoutBuilder.cpp @@ -582,7 +582,7 @@ protected: CharUnits NonVirtualSize; CharUnits NonVirtualAlignment; - CharUnits ZeroLengthBitfieldAlignment; + FieldDecl *ZeroLengthBitfield; /// PrimaryBase - the primary base class (if one exists) of the class /// we're laying out. @@ -621,7 +621,7 @@ protected: UnfilledBitsInLastByte(0), MaxFieldAlignment(CharUnits::Zero()), DataSize(0), NonVirtualSize(CharUnits::Zero()), NonVirtualAlignment(CharUnits::One()), - ZeroLengthBitfieldAlignment(CharUnits::Zero()), PrimaryBase(0), + ZeroLengthBitfield(0), PrimaryBase(0), PrimaryBaseIsVirtual(false), FirstNearlyEmptyVBase(0) { } void Layout(const RecordDecl *D); @@ -1258,27 +1258,112 @@ void RecordLayoutBuilder::LayoutFields(const RecordDecl *D) { // Layout each field, for now, just sequentially, respecting alignment. In // the future, this will need to be tweakable by targets. const FieldDecl *LastFD = 0; + ZeroLengthBitfield = 0; + unsigned RemainingInAlignment = 0; for (RecordDecl::field_iterator Field = D->field_begin(), FieldEnd = D->field_end(); Field != FieldEnd; ++Field) { if (IsMsStruct) { - const FieldDecl *FD = (*Field); - if (Context.ZeroBitfieldFollowsBitfield(FD, LastFD)) { - // FIXME. Multiple zero bitfields may follow a bitfield. - // set ZeroLengthBitfieldAlignment to max. of its - // currrent and alignment of 'FD'. - std::pair<CharUnits, CharUnits> FieldInfo = - Context.getTypeInfoInChars(FD->getType()); - ZeroLengthBitfieldAlignment = FieldInfo.second; - continue; - } + FieldDecl *FD = (*Field); + if (Context.ZeroBitfieldFollowsBitfield(FD, LastFD)) + ZeroLengthBitfield = FD; // Zero-length bitfields following non-bitfield members are // ignored: - if (Context.ZeroBitfieldFollowsNonBitfield(FD, LastFD)) + else if (Context.ZeroBitfieldFollowsNonBitfield(FD, LastFD)) continue; + // FIXME. streamline these conditions into a simple one. + else if (Context.BitfieldFollowsBitfield(FD, LastFD) || + Context.BitfieldFollowsNoneBitfield(FD, LastFD) || + Context.NoneBitfieldFollowsBitfield(FD, LastFD)) { + // 1) Adjacent bit fields are packed into the same 1-, 2-, or + // 4-byte allocation unit if the integral types are the same + // size and if the next bit field fits into the current + // allocation unit without crossing the boundary imposed by the + // common alignment requirements of the bit fields. + // 2) Establish a new alignment for a bitfield following + // a non-bitfield if size of their types differ. + // 3) Establish a new alignment for a non-bitfield following + // a bitfield if size of their types differ. + std::pair<uint64_t, unsigned> FieldInfo = + Context.getTypeInfo(FD->getType()); + uint64_t TypeSize = FieldInfo.first; + unsigned FieldAlign = FieldInfo.second; + // This check is needed for 'long long' in -m32 mode. + if (TypeSize > FieldAlign) + FieldAlign = TypeSize; + FieldInfo = Context.getTypeInfo(LastFD->getType()); + uint64_t TypeSizeLastFD = FieldInfo.first; + unsigned FieldAlignLastFD = FieldInfo.second; + // This check is needed for 'long long' in -m32 mode. + if (TypeSizeLastFD > FieldAlignLastFD) + FieldAlignLastFD = TypeSizeLastFD; + + if (TypeSizeLastFD != TypeSize) { + if (RemainingInAlignment && + LastFD && LastFD->isBitField() && + LastFD->getBitWidth()->EvaluateAsInt(Context).getZExtValue()) { + // If previous field was a bitfield with some remaining unfilled + // bits, pad the field so current field starts on its type boundary. + uint64_t FieldOffset = + getDataSizeInBits() - UnfilledBitsInLastByte; + uint64_t NewSizeInBits = RemainingInAlignment + FieldOffset; + setDataSize(llvm::RoundUpToAlignment(NewSizeInBits, + Context.Target.getCharAlign())); + setSize(std::max(getSizeInBits(), getDataSizeInBits())); + RemainingInAlignment = 0; + } + + uint64_t UnpaddedFieldOffset = + getDataSizeInBits() - UnfilledBitsInLastByte; + FieldAlign = std::max(FieldAlign, FieldAlignLastFD); + + // The maximum field alignment overrides the aligned attribute. + if (!MaxFieldAlignment.isZero()) { + unsigned MaxFieldAlignmentInBits = + Context.toBits(MaxFieldAlignment); + FieldAlign = std::min(FieldAlign, MaxFieldAlignmentInBits); + } + + uint64_t NewSizeInBits = + llvm::RoundUpToAlignment(UnpaddedFieldOffset, FieldAlign); + setDataSize(llvm::RoundUpToAlignment(NewSizeInBits, + Context.Target.getCharAlign())); + UnfilledBitsInLastByte = getDataSizeInBits() - NewSizeInBits; + setSize(std::max(getSizeInBits(), getDataSizeInBits())); + } + if (FD->isBitField()) { + uint64_t FieldSize = + FD->getBitWidth()->EvaluateAsInt(Context).getZExtValue(); + assert (FieldSize > 0 && "LayoutFields - ms_struct layout"); + if (RemainingInAlignment < FieldSize) + RemainingInAlignment = TypeSize - FieldSize; + else + RemainingInAlignment -= FieldSize; + } + } + else if (FD->isBitField()) { + uint64_t FieldSize = + FD->getBitWidth()->EvaluateAsInt(Context).getZExtValue(); + std::pair<uint64_t, unsigned> FieldInfo = + Context.getTypeInfo(FD->getType()); + uint64_t TypeSize = FieldInfo.first; + RemainingInAlignment = TypeSize - FieldSize; + } LastFD = FD; } LayoutField(*Field); } + if (IsMsStruct && RemainingInAlignment && + LastFD && LastFD->isBitField() && + LastFD->getBitWidth()->EvaluateAsInt(Context).getZExtValue()) { + // If we ended a bitfield before the full length of the type then + // pad the struct out to the full length of the last type. + uint64_t FieldOffset = + getDataSizeInBits() - UnfilledBitsInLastByte; + uint64_t NewSizeInBits = RemainingInAlignment + FieldOffset; + setDataSize(llvm::RoundUpToAlignment(NewSizeInBits, + Context.Target.getCharAlign())); + setSize(std::max(getSizeInBits(), getDataSizeInBits())); + } } void RecordLayoutBuilder::LayoutWideBitField(uint64_t FieldSize, @@ -1355,6 +1440,27 @@ void RecordLayoutBuilder::LayoutBitField(const FieldDecl *D) { std::pair<uint64_t, unsigned> FieldInfo = Context.getTypeInfo(D->getType()); uint64_t TypeSize = FieldInfo.first; unsigned FieldAlign = FieldInfo.second; + + // This check is needed for 'long long' in -m32 mode. + if (IsMsStruct && (TypeSize > FieldAlign)) + FieldAlign = TypeSize; + + if (ZeroLengthBitfield) { + // If a zero-length bitfield is inserted after a bitfield, + // and the alignment of the zero-length bitfield is + // greater than the member that follows it, `bar', `bar' + // will be aligned as the type of the zero-length bitfield. + if (ZeroLengthBitfield != D) { + std::pair<uint64_t, unsigned> FieldInfo = + Context.getTypeInfo(ZeroLengthBitfield->getType()); + unsigned ZeroLengthBitfieldAlignment = FieldInfo.second; + // Ignore alignment of subsequent zero-length bitfields. + if ((ZeroLengthBitfieldAlignment > FieldAlign) || (FieldSize == 0)) + FieldAlign = ZeroLengthBitfieldAlignment; + if (FieldSize) + ZeroLengthBitfield = 0; + } + } if (FieldSize > TypeSize) { LayoutWideBitField(FieldSize, TypeSize, FieldPacked, D); @@ -1455,11 +1561,21 @@ void RecordLayoutBuilder::LayoutField(const FieldDecl *D) { Context.getTypeInfoInChars(D->getType()); FieldSize = FieldInfo.first; FieldAlign = FieldInfo.second; - if (ZeroLengthBitfieldAlignment > FieldAlign) - FieldAlign = ZeroLengthBitfieldAlignment; - ZeroLengthBitfieldAlignment = CharUnits::Zero(); + + if (ZeroLengthBitfield) { + // If a zero-length bitfield is inserted after a bitfield, + // and the alignment of the zero-length bitfield is + // greater than the member that follows it, `bar', `bar' + // will be aligned as the type of the zero-length bitfield. + std::pair<CharUnits, CharUnits> FieldInfo = + Context.getTypeInfoInChars(ZeroLengthBitfield->getType()); + CharUnits ZeroLengthBitfieldAlignment = FieldInfo.second; + if (ZeroLengthBitfieldAlignment > FieldAlign) + FieldAlign = ZeroLengthBitfieldAlignment; + ZeroLengthBitfield = 0; + } - if (Context.getLangOptions().MSBitfields) { + if (Context.getLangOptions().MSBitfields || IsMsStruct) { // If MS bitfield layout is required, figure out what type is being // laid out and align the field to the width of that type. @@ -1641,10 +1757,10 @@ RecordLayoutBuilder::ComputeKeyFunction(const CXXRecordDecl *RD) { if (!RD->isPolymorphic()) return 0; - // A class inside an anonymous namespace doesn't have a key function. (Or + // A class that is not externally visible doesn't have a key function. (Or // at least, there's no point to assigning a key function to such a class; // this doesn't affect the ABI.) - if (RD->isInAnonymousNamespace()) + if (RD->getLinkage() != ExternalLinkage) return 0; // Template instantiations don't have key functions,see Itanium C++ ABI 5.2.6. diff --git a/contrib/llvm/tools/clang/lib/AST/StmtPrinter.cpp b/contrib/llvm/tools/clang/lib/AST/StmtPrinter.cpp index 0d13502..87588e4 100644 --- a/contrib/llvm/tools/clang/lib/AST/StmtPrinter.cpp +++ b/contrib/llvm/tools/clang/lib/AST/StmtPrinter.cpp @@ -1297,7 +1297,7 @@ static const char *getTypeTraitName(UnaryTypeTrait UTT) { case UTT_HasNothrowConstructor: return "__has_nothrow_constructor"; case UTT_HasNothrowCopy: return "__has_nothrow_copy"; case UTT_HasTrivialAssign: return "__has_trivial_assign"; - case UTT_HasTrivialConstructor: return "__has_trivial_constructor"; + case UTT_HasTrivialDefaultConstructor: return "__has_trivial_constructor"; case UTT_HasTrivialCopy: return "__has_trivial_copy"; case UTT_HasTrivialDestructor: return "__has_trivial_destructor"; case UTT_HasVirtualDestructor: return "__has_virtual_destructor"; @@ -1329,6 +1329,7 @@ static const char *getTypeTraitName(UnaryTypeTrait UTT) { case UTT_IsSigned: return "__is_signed"; case UTT_IsStandardLayout: return "__is_standard_layout"; case UTT_IsTrivial: return "__is_trivial"; + case UTT_IsTriviallyCopyable: return "__is_trivially_copyable"; case UTT_IsUnion: return "__is_union"; case UTT_IsUnsigned: return "__is_unsigned"; case UTT_IsVoid: return "__is_void"; @@ -1498,6 +1499,13 @@ void StmtPrinter::VisitBlockDeclRefExpr(BlockDeclRefExpr *Node) { void StmtPrinter::VisitOpaqueValueExpr(OpaqueValueExpr *Node) {} +void StmtPrinter::VisitAsTypeExpr(AsTypeExpr *Node) { + OS << "__builtin_astype("; + PrintExpr(Node->getSrcExpr()); + OS << ", " << Node->getType().getAsString(); + OS << ")"; +} + //===----------------------------------------------------------------------===// // Stmt method implementations //===----------------------------------------------------------------------===// diff --git a/contrib/llvm/tools/clang/lib/AST/StmtProfile.cpp b/contrib/llvm/tools/clang/lib/AST/StmtProfile.cpp index 44818e8..b117cd9 100644 --- a/contrib/llvm/tools/clang/lib/AST/StmtProfile.cpp +++ b/contrib/llvm/tools/clang/lib/AST/StmtProfile.cpp @@ -679,6 +679,10 @@ void StmtProfiler::VisitCUDAKernelCallExpr(CUDAKernelCallExpr *S) { VisitCallExpr(S); } +void StmtProfiler::VisitAsTypeExpr(AsTypeExpr *S) { + VisitExpr(S); +} + void StmtProfiler::VisitCXXNamedCastExpr(CXXNamedCastExpr *S) { VisitExplicitCastExpr(S); } diff --git a/contrib/llvm/tools/clang/lib/AST/Type.cpp b/contrib/llvm/tools/clang/lib/AST/Type.cpp index 9eb497b..d2875528 100644 --- a/contrib/llvm/tools/clang/lib/AST/Type.cpp +++ b/contrib/llvm/tools/clang/lib/AST/Type.cpp @@ -517,7 +517,7 @@ bool Type::isIntegerType() const { if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType)) // Incomplete enum types are not treated as integer types. // FIXME: In C++, enum types are never integer types. - return ET->getDecl()->isComplete(); + return ET->getDecl()->isComplete() && !ET->getDecl()->isScoped(); return false; } @@ -641,13 +641,27 @@ bool Type::isSignedIntegerType() const { if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType)) { // Incomplete enum types are not treated as integer types. // FIXME: In C++, enum types are never integer types. - if (ET->getDecl()->isComplete()) + if (ET->getDecl()->isComplete() && !ET->getDecl()->isScoped()) return ET->getDecl()->getIntegerType()->isSignedIntegerType(); } return false; } +bool Type::isSignedIntegerOrEnumerationType() const { + if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) { + return BT->getKind() >= BuiltinType::Char_S && + BT->getKind() <= BuiltinType::Int128; + } + + if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType)) { + if (ET->getDecl()->isComplete()) + return ET->getDecl()->getIntegerType()->isSignedIntegerType(); + } + + return false; +} + bool Type::hasSignedIntegerRepresentation() const { if (const VectorType *VT = dyn_cast<VectorType>(CanonicalType)) return VT->getElementType()->isSignedIntegerType(); @@ -667,13 +681,27 @@ bool Type::isUnsignedIntegerType() const { if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType)) { // Incomplete enum types are not treated as integer types. // FIXME: In C++, enum types are never integer types. - if (ET->getDecl()->isComplete()) + if (ET->getDecl()->isComplete() && !ET->getDecl()->isScoped()) return ET->getDecl()->getIntegerType()->isUnsignedIntegerType(); } return false; } +bool Type::isUnsignedIntegerOrEnumerationType() const { + if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) { + return BT->getKind() >= BuiltinType::Bool && + BT->getKind() <= BuiltinType::UInt128; + } + + if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType)) { + if (ET->getDecl()->isComplete()) + return ET->getDecl()->getIntegerType()->isUnsignedIntegerType(); + } + + return false; +} + bool Type::hasUnsignedIntegerRepresentation() const { if (const VectorType *VT = dyn_cast<VectorType>(CanonicalType)) return VT->getElementType()->isUnsignedIntegerType(); @@ -954,10 +982,37 @@ bool Type::isTrivialType() const { if (const RecordType *RT = BaseTy->getAs<RecordType>()) { if (const CXXRecordDecl *ClassDecl = dyn_cast<CXXRecordDecl>(RT->getDecl())) { - // C++0x [class]p5: - // A trivial class is a class that has a trivial default constructor - if (!ClassDecl->hasTrivialConstructor()) return false; - // and is trivially copyable. + if (!ClassDecl->isTrivial()) return false; + } + + return true; + } + + // No other types can match. + return false; +} + +bool Type::isTriviallyCopyableType() const { + if (isDependentType()) + return false; + + // C++0x [basic.types]p9 + // Scalar types, trivially copyable class types, arrays of such types, and + // cv-qualified versions of these types are collectively called trivial + // types. + const Type *BaseTy = getBaseElementTypeUnsafe(); + assert(BaseTy && "NULL element type"); + + // Return false for incomplete types after skipping any incomplete array types + // which are expressly allowed by the standard and thus our API. + if (BaseTy->isIncompleteType()) + return false; + + // As an extension, Clang treats vector types as Scalar types. + if (BaseTy->isScalarType() || BaseTy->isVectorType()) return true; + if (const RecordType *RT = BaseTy->getAs<RecordType>()) { + if (const CXXRecordDecl *ClassDecl = + dyn_cast<CXXRecordDecl>(RT->getDecl())) { if (!ClassDecl->isTriviallyCopyable()) return false; } @@ -1027,11 +1082,7 @@ bool Type::isCXX11PODType() const { dyn_cast<CXXRecordDecl>(RT->getDecl())) { // C++11 [class]p10: // A POD struct is a non-union class that is both a trivial class [...] - // C++11 [class]p5: - // A trivial class is a class that has a trivial default constructor - if (!ClassDecl->hasTrivialConstructor()) return false; - // and is trivially copyable. - if (!ClassDecl->isTriviallyCopyable()) return false; + if (!ClassDecl->isTrivial()) return false; // C++11 [class]p10: // A POD struct is a non-union class that is both a trivial class and @@ -1484,6 +1535,16 @@ static TagDecl *getInterestingTagDecl(TagDecl *decl) { return decl; } +UnaryTransformType::UnaryTransformType(QualType BaseType, + QualType UnderlyingType, + UTTKind UKind, + QualType CanonicalType) + : Type(UnaryTransform, CanonicalType, UnderlyingType->isDependentType(), + UnderlyingType->isVariablyModifiedType(), + BaseType->containsUnexpandedParameterPack()) + , BaseType(BaseType), UnderlyingType(UnderlyingType), UKind(UKind) +{} + TagDecl *TagType::getDecl() const { return getInterestingTagDecl(decl); } @@ -1559,13 +1620,13 @@ anyDependentTemplateArguments(const TemplateArgument *Args, unsigned N) { TemplateSpecializationType:: TemplateSpecializationType(TemplateName T, - const TemplateArgument *Args, - unsigned NumArgs, QualType Canon) + const TemplateArgument *Args, unsigned NumArgs, + QualType Canon, QualType AliasedType) : Type(TemplateSpecialization, Canon.isNull()? QualType(this, 0) : Canon, - T.isDependent(), false, T.containsUnexpandedParameterPack()), - Template(T), NumArgs(NumArgs) -{ + Canon.isNull()? T.isDependent() : Canon->isDependentType(), + false, T.containsUnexpandedParameterPack()), + Template(T), NumArgs(NumArgs) { assert(!T.getAsDependentTemplateName() && "Use DependentTemplateSpecializationType for dependent template-name"); assert((!Canon.isNull() || @@ -1576,7 +1637,12 @@ TemplateSpecializationType(TemplateName T, = reinterpret_cast<TemplateArgument *>(this + 1); for (unsigned Arg = 0; Arg < NumArgs; ++Arg) { // Update dependent and variably-modified bits. - if (Args[Arg].isDependent()) + // If the canonical type exists and is non-dependent, the template + // specialization type can be non-dependent even if one of the type + // arguments is. Given: + // template<typename T> using U = int; + // U<T> is always non-dependent, irrespective of the type T. + if (Canon.isNull() && Args[Arg].isDependent()) setDependent(); if (Args[Arg].getKind() == TemplateArgument::Type && Args[Arg].getAsType()->isVariablyModifiedType()) @@ -1586,6 +1652,15 @@ TemplateSpecializationType(TemplateName T, new (&TemplateArgs[Arg]) TemplateArgument(Args[Arg]); } + + // Store the aliased type if this is a type alias template specialization. + bool IsTypeAlias = !AliasedType.isNull(); + assert(IsTypeAlias == isTypeAlias() && + "allocated wrong size for type alias"); + if (IsTypeAlias) { + TemplateArgument *Begin = reinterpret_cast<TemplateArgument *>(this + 1); + *reinterpret_cast<QualType*>(Begin + getNumArgs()) = AliasedType; + } } void @@ -1599,6 +1674,11 @@ TemplateSpecializationType::Profile(llvm::FoldingSetNodeID &ID, Args[Idx].Profile(ID, Context); } +bool TemplateSpecializationType::isTypeAlias() const { + TemplateDecl *D = Template.getAsTemplateDecl(); + return D && isa<TypeAliasTemplateDecl>(D); +} + QualType QualifierCollector::apply(const ASTContext &Context, QualType QT) const { if (!hasNonFastQualifiers()) diff --git a/contrib/llvm/tools/clang/lib/AST/TypePrinter.cpp b/contrib/llvm/tools/clang/lib/AST/TypePrinter.cpp index 0c5df7f..4519606 100644 --- a/contrib/llvm/tools/clang/lib/AST/TypePrinter.cpp +++ b/contrib/llvm/tools/clang/lib/AST/TypePrinter.cpp @@ -94,6 +94,7 @@ void TypePrinter::print(const Type *T, Qualifiers Quals, std::string &buffer) { case Type::TypeOfExpr: case Type::TypeOf: case Type::Decltype: + case Type::UnaryTransform: case Type::Record: case Type::Enum: case Type::Elaborated: @@ -512,6 +513,20 @@ void TypePrinter::printDecltype(const DecltypeType *T, std::string &S) { S = "decltype(" + s.str() + ")" + S; } +void TypePrinter::printUnaryTransform(const UnaryTransformType *T, + std::string &S) { + if (!S.empty()) + S = ' ' + S; + std::string Str; + print(T->getBaseType(), Str); + + switch (T->getUTTKind()) { + case UnaryTransformType::EnumUnderlyingType: + S = "__underlying_type(" + Str + ")" + S; + break; + } +} + void TypePrinter::printAuto(const AutoType *T, std::string &S) { // If the type has been deduced, do not print 'auto'. if (T->isDeduced()) { @@ -963,7 +978,7 @@ TemplateSpecializationType::PrintTemplateArgumentList( SpecString += '<'; for (unsigned Arg = 0; Arg < NumArgs; ++Arg) { - if (SpecString.size() > !SkipBrackets) + if (SpecString.size() > unsigned(!SkipBrackets)) SpecString += ", "; // Print the argument into a string. diff --git a/contrib/llvm/tools/clang/lib/Analysis/AnalysisContext.cpp b/contrib/llvm/tools/clang/lib/Analysis/AnalysisContext.cpp index ddc5e88..678f02f 100644 --- a/contrib/llvm/tools/clang/lib/Analysis/AnalysisContext.cpp +++ b/contrib/llvm/tools/clang/lib/Analysis/AnalysisContext.cpp @@ -78,16 +78,16 @@ void AnalysisContext::registerForcedBlockExpression(const Stmt *stmt) { if (!forcedBlkExprs) forcedBlkExprs = new CFG::BuildOptions::ForcedBlkExprs(); // Default construct an entry for 'stmt'. - if (const ParenExpr *pe = dyn_cast<ParenExpr>(stmt)) - stmt = pe->IgnoreParens(); + if (const Expr *e = dyn_cast<Expr>(stmt)) + stmt = e->IgnoreParens(); (void) (*forcedBlkExprs)[stmt]; } const CFGBlock * AnalysisContext::getBlockForRegisteredExpression(const Stmt *stmt) { assert(forcedBlkExprs); - if (const ParenExpr *pe = dyn_cast<ParenExpr>(stmt)) - stmt = pe->IgnoreParens(); + if (const Expr *e = dyn_cast<Expr>(stmt)) + stmt = e->IgnoreParens(); CFG::BuildOptions::ForcedBlkExprs::const_iterator itr = forcedBlkExprs->find(stmt); assert(itr != forcedBlkExprs->end()); diff --git a/contrib/llvm/tools/clang/lib/Analysis/CFG.cpp b/contrib/llvm/tools/clang/lib/Analysis/CFG.cpp index de16334..3e54020 100644 --- a/contrib/llvm/tools/clang/lib/Analysis/CFG.cpp +++ b/contrib/llvm/tools/clang/lib/Analysis/CFG.cpp @@ -320,7 +320,6 @@ private: AddStmtChoice asc); CFGBlock *VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *C, AddStmtChoice asc); - CFGBlock *VisitCXXMemberCallExpr(CXXMemberCallExpr *C, AddStmtChoice asc); CFGBlock *VisitCallExpr(CallExpr *C, AddStmtChoice asc); CFGBlock *VisitCaseStmt(CaseStmt *C); CFGBlock *VisitChooseExpr(ChooseExpr *C, AddStmtChoice asc); @@ -398,6 +397,8 @@ private: if (alwaysAdd(S)) cachedEntry->second = B; + // All block-level expressions should have already been IgnoreParens()ed. + assert(!isa<Expr>(S) || cast<Expr>(S)->IgnoreParens() == S); B->appendStmt(const_cast<Stmt*>(S), cfg->getBumpVectorContext()); } void appendInitializer(CFGBlock *B, CXXCtorInitializer *I) { @@ -444,7 +445,7 @@ private: return Result.Val.getInt().getBoolValue(); if (Result.Val.isLValue()) { - Expr *e = Result.Val.getLValueBase(); + const Expr *e = Result.Val.getLValueBase(); const CharUnits &c = Result.Val.getLValueOffset(); if (!e && c.isZero()) return false; @@ -842,11 +843,14 @@ void CFGBuilder::prependAutomaticObjDtorsWithTerminator(CFGBlock* Blk, /// blocks for ternary operators, &&, and ||. We also process "," and /// DeclStmts (which may contain nested control-flow). CFGBlock* CFGBuilder::Visit(Stmt * S, AddStmtChoice asc) { -tryAgain: if (!S) { badCFG = true; return 0; } + + if (Expr *E = dyn_cast<Expr>(S)) + S = E->IgnoreParens(); + switch (S->getStmtClass()) { default: return VisitStmt(S, asc); @@ -868,6 +872,7 @@ tryAgain: case Stmt::CallExprClass: case Stmt::CXXOperatorCallExprClass: + case Stmt::CXXMemberCallExprClass: return VisitCallExpr(cast<CallExpr>(S), asc); case Stmt::CaseStmtClass: @@ -903,9 +908,6 @@ tryAgain: case Stmt::CXXTemporaryObjectExprClass: return VisitCXXTemporaryObjectExpr(cast<CXXTemporaryObjectExpr>(S), asc); - case Stmt::CXXMemberCallExprClass: - return VisitCXXMemberCallExpr(cast<CXXMemberCallExpr>(S), asc); - case Stmt::CXXThrowExprClass: return VisitCXXThrowExpr(cast<CXXThrowExpr>(S)); @@ -960,10 +962,6 @@ tryAgain: case Stmt::ObjCForCollectionStmtClass: return VisitObjCForCollectionStmt(cast<ObjCForCollectionStmt>(S)); - case Stmt::ParenExprClass: - S = cast<ParenExpr>(S)->getSubExpr(); - goto tryAgain; - case Stmt::NullStmtClass: return Block; @@ -1153,12 +1151,19 @@ static bool CanThrow(Expr *E, ASTContext &Ctx) { } CFGBlock *CFGBuilder::VisitCallExpr(CallExpr *C, AddStmtChoice asc) { - // If this is a call to a no-return function, this stops the block here. - bool NoReturn = false; - if (getFunctionExtInfo(*C->getCallee()->getType()).getNoReturn()) { - NoReturn = true; + // Compute the callee type. + QualType calleeType = C->getCallee()->getType(); + if (calleeType == Context->BoundMemberTy) { + QualType boundType = Expr::findBoundMemberType(C->getCallee()); + + // We should only get a null bound type if processing a dependent + // CFG. Recover by assuming nothing. + if (!boundType.isNull()) calleeType = boundType; } + // If this is a call to a no-return function, this stops the block here. + bool NoReturn = getFunctionExtInfo(*calleeType).getNoReturn(); + bool AddEHEdge = false; // Languages without exceptions are assumed to not throw. @@ -1314,6 +1319,12 @@ CFGBlock *CFGBuilder::VisitConditionalOperator(AbstractConditionalOperator *C, } CFGBlock *CFGBuilder::VisitDeclStmt(DeclStmt *DS) { + // Check if the Decl is for an __label__. If so, elide it from the + // CFG entirely. + if (isa<LabelDecl>(*DS->decl_begin())) + return Block; + + // This case also handles static_asserts. if (DS->isSingleDecl()) return VisitDeclSubExpr(DS); @@ -1346,7 +1357,14 @@ CFGBlock *CFGBuilder::VisitDeclStmt(DeclStmt *DS) { /// DeclStmts and initializers in them. CFGBlock *CFGBuilder::VisitDeclSubExpr(DeclStmt* DS) { assert(DS->isSingleDecl() && "Can handle single declarations only."); - + Decl *D = DS->getSingleDecl(); + + if (isa<StaticAssertDecl>(D)) { + // static_asserts aren't added to the CFG because they do not impact + // runtime semantics. + return Block; + } + VarDecl *VD = dyn_cast<VarDecl>(DS->getSingleDecl()); if (!VD) { @@ -2686,13 +2704,6 @@ CFGBlock *CFGBuilder::VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *C, return VisitChildren(C); } -CFGBlock *CFGBuilder::VisitCXXMemberCallExpr(CXXMemberCallExpr *C, - AddStmtChoice asc) { - autoCreateBlock(); - appendStmt(Block, C); - return VisitChildren(C); -} - CFGBlock *CFGBuilder::VisitImplicitCastExpr(ImplicitCastExpr *E, AddStmtChoice asc) { if (asc.alwaysAdd(*this, E)) { @@ -3039,6 +3050,7 @@ static BlkExprMapTy* PopulateBlkExprMap(CFG& cfg) { if (!CS) continue; if (Expr* Exp = dyn_cast<Expr>(CS->getStmt())) { + assert((Exp->IgnoreParens() == Exp) && "No parens on block-level exps"); if (BinaryOperator* B = dyn_cast<BinaryOperator>(Exp)) { // Assignment expressions that are not nested within another @@ -3046,13 +3058,16 @@ static BlkExprMapTy* PopulateBlkExprMap(CFG& cfg) { // another expression. if (B->isAssignmentOp() && !SubExprAssignments.count(Exp)) continue; - } else if (const StmtExpr* Terminator = dyn_cast<StmtExpr>(Exp)) { + } else if (const StmtExpr* SE = dyn_cast<StmtExpr>(Exp)) { // Special handling for statement expressions. The last statement in // the statement expression is also a block-level expr. - const CompoundStmt* C = Terminator->getSubStmt(); + const CompoundStmt* C = SE->getSubStmt(); if (!C->body_empty()) { + const Stmt *Last = C->body_back(); + if (const Expr *LastEx = dyn_cast<Expr>(Last)) + Last = LastEx->IgnoreParens(); unsigned x = M->size(); - (*M)[C->body_back()] = x; + (*M)[Last] = x; } } @@ -3066,8 +3081,8 @@ static BlkExprMapTy* PopulateBlkExprMap(CFG& cfg) { Stmt* S = (*I)->getTerminatorCondition(); if (S && M->find(S) == M->end()) { - unsigned x = M->size(); - (*M)[S] = x; + unsigned x = M->size(); + (*M)[S] = x; } } diff --git a/contrib/llvm/tools/clang/lib/Analysis/CocoaConventions.cpp b/contrib/llvm/tools/clang/lib/Analysis/CocoaConventions.cpp index 4c62f36..946c38c 100644 --- a/contrib/llvm/tools/clang/lib/Analysis/CocoaConventions.cpp +++ b/contrib/llvm/tools/clang/lib/Analysis/CocoaConventions.cpp @@ -44,6 +44,7 @@ cocoa::NamingConvention cocoa::deriveNamingConvention(Selector S) { case OMF_release: case OMF_retain: case OMF_retainCount: + case OMF_self: return NoConvention; case OMF_init: diff --git a/contrib/llvm/tools/clang/lib/Analysis/LiveVariables.cpp b/contrib/llvm/tools/clang/lib/Analysis/LiveVariables.cpp index 303dc0f..7b36f85 100644 --- a/contrib/llvm/tools/clang/lib/Analysis/LiveVariables.cpp +++ b/contrib/llvm/tools/clang/lib/Analysis/LiveVariables.cpp @@ -157,7 +157,7 @@ void TransferFuncs::Visit(Stmt *S) { } else { // For block-level expressions, mark that they are live. - LiveState(S,AD) = Alive; + LiveState(S, AD) = Alive; } } diff --git a/contrib/llvm/tools/clang/lib/Analysis/UninitializedValues.cpp b/contrib/llvm/tools/clang/lib/Analysis/UninitializedValues.cpp index 88a2db7..e80e282 100644 --- a/contrib/llvm/tools/clang/lib/Analysis/UninitializedValues.cpp +++ b/contrib/llvm/tools/clang/lib/Analysis/UninitializedValues.cpp @@ -14,7 +14,7 @@ #include <utility> #include "llvm/ADT/Optional.h" #include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/BitVector.h" +#include "llvm/ADT/PackedVector.h" #include "llvm/ADT/DenseMap.h" #include "clang/AST/Decl.h" #include "clang/Analysis/CFG.h" @@ -93,39 +93,8 @@ static bool isAlwaysUninit(const Value v) { } namespace { -class ValueVector { - llvm::BitVector vec; -public: - ValueVector() {} - ValueVector(unsigned size) : vec(size << 1) {} - void resize(unsigned n) { vec.resize(n << 1); } - void merge(const ValueVector &rhs) { vec |= rhs.vec; } - bool operator!=(const ValueVector &rhs) const { return vec != rhs.vec; } - void reset() { vec.reset(); } - - class reference { - ValueVector &vv; - const unsigned idx; - - reference(); // Undefined - public: - reference(ValueVector &vv, unsigned idx) : vv(vv), idx(idx) {} - ~reference() {} - - reference &operator=(Value v) { - vv.vec[idx << 1] = (((unsigned) v) & 0x1) ? true : false; - vv.vec[(idx << 1) | 1] = (((unsigned) v) & 0x2) ? true : false; - return *this; - } - operator Value() { - unsigned x = (vv.vec[idx << 1] ? 1 : 0) | (vv.vec[(idx << 1) | 1] ? 2 :0); - return (Value) x; - } - }; - - reference operator[](unsigned idx) { return reference(*this, idx); } -}; +typedef llvm::PackedVector<Value, 2> ValueVector; typedef std::pair<ValueVector *, ValueVector *> BVPair; class CFGBlockValues { @@ -214,11 +183,15 @@ static BinaryOperator *getLogicalOperatorInChain(const CFGBlock *block) { if (!b || !b->isLogicalOp()) return 0; - if (block->pred_size() == 2 && - ((block->succ_size() == 2 && block->getTerminatorCondition() == b) || - block->size() == 1)) - return b; - + if (block->pred_size() == 2) { + if (block->getTerminatorCondition() == b) { + if (block->succ_size() == 2) + return b; + } + else if (block->size() == 1) + return b; + } + return 0; } @@ -255,7 +228,7 @@ void CFGBlockValues::mergeIntoScratch(ValueVector const &source, if (isFirst) scratch = source; else - scratch.merge(source); + scratch |= source; } #if 0 static void printVector(const CFGBlock *block, ValueVector &bv, diff --git a/contrib/llvm/tools/clang/lib/Basic/Diagnostic.cpp b/contrib/llvm/tools/clang/lib/Basic/Diagnostic.cpp index e8cd218..11887ab 100644 --- a/contrib/llvm/tools/clang/lib/Basic/Diagnostic.cpp +++ b/contrib/llvm/tools/clang/lib/Basic/Diagnostic.cpp @@ -212,6 +212,42 @@ void Diagnostic::setDiagnosticMapping(diag::kind Diag, diag::Mapping Map, FullSourceLoc(Loc, *SourceMgr))); } +void Diagnostic::Report(const StoredDiagnostic &storedDiag) { + assert(CurDiagID == ~0U && "Multiple diagnostics in flight at once!"); + + CurDiagLoc = storedDiag.getLocation(); + CurDiagID = storedDiag.getID(); + NumDiagArgs = 0; + + NumDiagRanges = storedDiag.range_size(); + assert(NumDiagRanges < sizeof(DiagRanges)/sizeof(DiagRanges[0]) && + "Too many arguments to diagnostic!"); + unsigned i = 0; + for (StoredDiagnostic::range_iterator + RI = storedDiag.range_begin(), + RE = storedDiag.range_end(); RI != RE; ++RI) + DiagRanges[i++] = *RI; + + NumFixItHints = storedDiag.fixit_size(); + assert(NumFixItHints < Diagnostic::MaxFixItHints && "Too many fix-it hints!"); + i = 0; + for (StoredDiagnostic::fixit_iterator + FI = storedDiag.fixit_begin(), + FE = storedDiag.fixit_end(); FI != FE; ++FI) + FixItHints[i++] = *FI; + + assert(Client && "DiagnosticClient not set!"); + Level DiagLevel = storedDiag.getLevel(); + DiagnosticInfo Info(this, storedDiag.getMessage()); + Client->HandleDiagnostic(DiagLevel, Info); + if (Client->IncludeInDiagnosticCounts()) { + if (DiagLevel == Diagnostic::Warning) + ++NumWarnings; + } + + CurDiagID = ~0U; +} + void DiagnosticBuilder::FlushCounts() { DiagObj->NumDiagArgs = NumArgs; DiagObj->NumDiagRanges = NumRanges; @@ -486,10 +522,15 @@ static void HandlePluralModifier(const DiagnosticInfo &DInfo, unsigned ValNo, /// array. void DiagnosticInfo:: FormatDiagnostic(llvm::SmallVectorImpl<char> &OutStr) const { - const char *DiagStr = getDiags()->getDiagnosticIDs()->getDescription(getID()); - const char *DiagEnd = DiagStr+strlen(DiagStr); + if (!StoredDiagMessage.empty()) { + OutStr.append(StoredDiagMessage.begin(), StoredDiagMessage.end()); + return; + } + + llvm::StringRef Diag = + getDiags()->getDiagnosticIDs()->getDescription(getID()); - FormatDiagnostic(DiagStr, DiagEnd, OutStr); + FormatDiagnostic(Diag.begin(), Diag.end(), OutStr); } void DiagnosticInfo:: diff --git a/contrib/llvm/tools/clang/lib/Basic/DiagnosticIDs.cpp b/contrib/llvm/tools/clang/lib/Basic/DiagnosticIDs.cpp index b4dd575..6d7e320 100644 --- a/contrib/llvm/tools/clang/lib/Basic/DiagnosticIDs.cpp +++ b/contrib/llvm/tools/clang/lib/Basic/DiagnosticIDs.cpp @@ -45,14 +45,37 @@ struct StaticDiagInfoRec { unsigned SFINAE : 1; unsigned AccessControl : 1; unsigned Category : 5; - - const char *Name; - - const char *Description; - const char *OptionGroup; - const char *BriefExplanation; - const char *FullExplanation; + uint8_t NameLen; + uint8_t OptionGroupLen; + + uint16_t DescriptionLen; + uint16_t BriefExplanationLen; + uint16_t FullExplanationLen; + + const char *NameStr; + const char *OptionGroupStr; + + const char *DescriptionStr; + const char *BriefExplanationStr; + const char *FullExplanationStr; + + llvm::StringRef getName() const { + return llvm::StringRef(NameStr, NameLen); + } + llvm::StringRef getOptionGroup() const { + return llvm::StringRef(OptionGroupStr, OptionGroupLen); + } + + llvm::StringRef getDescription() const { + return llvm::StringRef(DescriptionStr, DescriptionLen); + } + llvm::StringRef getBriefExplanation() const { + return llvm::StringRef(BriefExplanationStr, BriefExplanationLen); + } + llvm::StringRef getFullExplanation() const { + return llvm::StringRef(FullExplanationStr, FullExplanationLen); + } bool operator<(const StaticDiagInfoRec &RHS) const { return DiagID < RHS.DiagID; @@ -60,27 +83,42 @@ struct StaticDiagInfoRec { }; struct StaticDiagNameIndexRec { - const char *Name; + const char *NameStr; unsigned short DiagID; - + uint8_t NameLen; + + llvm::StringRef getName() const { + return llvm::StringRef(NameStr, NameLen); + } + bool operator<(const StaticDiagNameIndexRec &RHS) const { - assert(Name && RHS.Name && "Null Diagnostic Name"); - return strcmp(Name, RHS.Name) == -1; + return getName() < RHS.getName(); } bool operator==(const StaticDiagNameIndexRec &RHS) const { - assert(Name && RHS.Name && "Null Diagnostic Name"); - return strcmp(Name, RHS.Name) == 0; + return getName() == RHS.getName(); } }; -} +template <size_t SizeOfStr, typename FieldType> +class StringSizerHelper { + char FIELD_TOO_SMALL[SizeOfStr <= FieldType(~0U) ? 1 : -1]; +public: + enum { Size = SizeOfStr }; +}; + +} // namespace anonymous + +#define STR_SIZE(str, fieldTy) StringSizerHelper<sizeof(str)-1, fieldTy>::Size static const StaticDiagInfoRec StaticDiagInfo[] = { -#define DIAG(ENUM,CLASS,DEFAULT_MAPPING,DESC,GROUP, \ - SFINAE,ACCESS,CATEGORY,BRIEF,FULL) \ - { diag::ENUM, DEFAULT_MAPPING, CLASS, SFINAE, \ - ACCESS, CATEGORY, #ENUM, DESC, GROUP, BRIEF, FULL }, +#define DIAG(ENUM,CLASS,DEFAULT_MAPPING,DESC,GROUP, \ + SFINAE,ACCESS,CATEGORY,BRIEF,FULL) \ + { diag::ENUM, DEFAULT_MAPPING, CLASS, SFINAE, ACCESS, CATEGORY, \ + STR_SIZE(#ENUM, uint8_t), STR_SIZE(GROUP, uint8_t), \ + STR_SIZE(DESC, uint16_t), STR_SIZE(BRIEF, uint16_t), \ + STR_SIZE(FULL, uint16_t), \ + #ENUM, GROUP, DESC, BRIEF, FULL }, #include "clang/Basic/DiagnosticCommonKinds.inc" #include "clang/Basic/DiagnosticDriverKinds.inc" #include "clang/Basic/DiagnosticFrontendKinds.inc" @@ -90,7 +128,7 @@ static const StaticDiagInfoRec StaticDiagInfo[] = { #include "clang/Basic/DiagnosticSemaKinds.inc" #include "clang/Basic/DiagnosticAnalysisKinds.inc" #undef DIAG - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }; static const unsigned StaticDiagInfoSize = @@ -98,10 +136,10 @@ static const unsigned StaticDiagInfoSize = /// To be sorted before first use (since it's splitted among multiple files) static StaticDiagNameIndexRec StaticDiagNameIndex[] = { -#define DIAG_NAME_INDEX(ENUM) { #ENUM, diag::ENUM }, +#define DIAG_NAME_INDEX(ENUM) { #ENUM, diag::ENUM, STR_SIZE(#ENUM, uint8_t) }, #include "clang/Basic/DiagnosticIndexName.inc" #undef DIAG_NAME_INDEX - { 0, 0 } + { 0, 0, 0 } }; static const unsigned StaticDiagNameIndexSize = @@ -127,7 +165,7 @@ static const StaticDiagInfoRec *GetDiagInfo(unsigned DiagID) { #endif // Search the diagnostic table with a binary search. - StaticDiagInfoRec Find = { DiagID, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + StaticDiagInfoRec Find = { DiagID, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0 }; const StaticDiagInfoRec *Found = std::lower_bound(StaticDiagInfo, StaticDiagInfo + StaticDiagInfoSize, Find); @@ -147,10 +185,10 @@ static unsigned GetDefaultDiagMapping(unsigned DiagID) { /// getWarningOptionForDiag - Return the lowest-level warning option that /// enables the specified diagnostic. If there is no -Wfoo flag that controls /// the diagnostic, this returns null. -const char *DiagnosticIDs::getWarningOptionForDiag(unsigned DiagID) { +llvm::StringRef DiagnosticIDs::getWarningOptionForDiag(unsigned DiagID) { if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID)) - return Info->OptionGroup; - return 0; + return Info->getOptionGroup(); + return llvm::StringRef(); } /// getCategoryNumberForDiag - Return the category number that a specified @@ -161,23 +199,36 @@ unsigned DiagnosticIDs::getCategoryNumberForDiag(unsigned DiagID) { return 0; } -/// getCategoryNameFromID - Given a category ID, return the name of the -/// category, an empty string if CategoryID is zero, or null if CategoryID is -/// invalid. -const char *DiagnosticIDs::getCategoryNameFromID(unsigned CategoryID) { - // Second the table of options, sorted by name for fast binary lookup. - static const char *CategoryNameTable[] = { +// The diagnostic category names. +struct StaticDiagCategoryRec { + const char *NameStr; + uint8_t NameLen; + + llvm::StringRef getName() const { + return llvm::StringRef(NameStr, NameLen); + } +}; + +static StaticDiagCategoryRec CategoryNameTable[] = { #define GET_CATEGORY_TABLE -#define CATEGORY(X) X, +#define CATEGORY(X) { X, STR_SIZE(X, uint8_t) }, #include "clang/Basic/DiagnosticGroups.inc" #undef GET_CATEGORY_TABLE - "<<END>>" - }; - static const size_t CategoryNameTableSize = - sizeof(CategoryNameTable) / sizeof(CategoryNameTable[0])-1; - - if (CategoryID >= CategoryNameTableSize) return 0; - return CategoryNameTable[CategoryID]; + { 0, 0 } +}; + +/// getNumberOfCategories - Return the number of categories +unsigned DiagnosticIDs::getNumberOfCategories() { + return sizeof(CategoryNameTable) / sizeof(CategoryNameTable[0])-1; +} + +/// getCategoryNameFromID - Given a category ID, return the name of the +/// category, an empty string if CategoryID is zero, or null if CategoryID is +/// invalid. +llvm::StringRef DiagnosticIDs::getCategoryNameFromID(unsigned CategoryID) { + if (CategoryID >= getNumberOfCategories()) + return llvm::StringRef(); + return CategoryNameTable[CategoryID].getName(); } @@ -202,25 +253,25 @@ DiagnosticIDs::getDiagnosticSFINAEResponse(unsigned DiagID) { } /// getName - Given a diagnostic ID, return its name -const char *DiagnosticIDs::getName(unsigned DiagID) { +llvm::StringRef DiagnosticIDs::getName(unsigned DiagID) { if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID)) - return Info->Name; - return 0; + return Info->getName(); + return llvm::StringRef(); } /// getIdFromName - Given a diagnostic name, return its ID, or 0 -unsigned DiagnosticIDs::getIdFromName(char const *Name) { +unsigned DiagnosticIDs::getIdFromName(llvm::StringRef Name) { StaticDiagNameIndexRec *StaticDiagNameIndexEnd = StaticDiagNameIndex + StaticDiagNameIndexSize; - if (Name == 0) { return diag::DIAG_UPPER_LIMIT; } + if (Name.empty()) { return diag::DIAG_UPPER_LIMIT; } - StaticDiagNameIndexRec Find = { Name, 0 }; + StaticDiagNameIndexRec Find = { Name.data(), 0, Name.size() }; const StaticDiagNameIndexRec *Found = std::lower_bound( StaticDiagNameIndex, StaticDiagNameIndexEnd, Find); if (Found == StaticDiagNameIndexEnd || - strcmp(Found->Name, Name) != 0) + Found->getName() != Name) return diag::DIAG_UPPER_LIMIT; return Found->DiagID; @@ -228,18 +279,18 @@ unsigned DiagnosticIDs::getIdFromName(char const *Name) { /// getBriefExplanation - Given a diagnostic ID, return a brief explanation /// of the issue -const char *DiagnosticIDs::getBriefExplanation(unsigned DiagID) { +llvm::StringRef DiagnosticIDs::getBriefExplanation(unsigned DiagID) { if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID)) - return Info->BriefExplanation; - return 0; + return Info->getBriefExplanation(); + return llvm::StringRef(); } /// getFullExplanation - Given a diagnostic ID, return a full explanation /// of the issue -const char *DiagnosticIDs::getFullExplanation(unsigned DiagID) { +llvm::StringRef DiagnosticIDs::getFullExplanation(unsigned DiagID) { if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID)) - return Info->FullExplanation; - return 0; + return Info->getFullExplanation(); + return llvm::StringRef(); } /// getBuiltinDiagClass - Return the class field of the diagnostic. @@ -264,10 +315,10 @@ namespace clang { /// getDescription - Return the description of the specified custom /// diagnostic. - const char *getDescription(unsigned DiagID) const { + llvm::StringRef getDescription(unsigned DiagID) const { assert(this && DiagID-DIAG_UPPER_LIMIT < DiagInfo.size() && "Invalid diagnosic ID"); - return DiagInfo[DiagID-DIAG_UPPER_LIMIT].second.c_str(); + return DiagInfo[DiagID-DIAG_UPPER_LIMIT].second; } /// getLevel - Return the level of the specified custom diagnostic. @@ -352,9 +403,9 @@ bool DiagnosticIDs::isBuiltinExtensionDiag(unsigned DiagID, /// getDescription - Given a diagnostic ID, return a description of the /// issue. -const char *DiagnosticIDs::getDescription(unsigned DiagID) const { +llvm::StringRef DiagnosticIDs::getDescription(unsigned DiagID) const { if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID)) - return Info->Description; + return Info->getDescription(); return CustomDiagInfo->getDescription(DiagID); } @@ -493,9 +544,15 @@ DiagnosticIDs::getDiagnosticLevel(unsigned DiagID, unsigned DiagClass, } struct WarningOption { - const char *Name; + // Be safe with the size of 'NameLen' because we don't statically check if the + // size will fit in the field; the struct size won't decrease with a shorter + // type anyway. + size_t NameLen; + const char *NameStr; const short *Members; const short *SubGroups; + + llvm::StringRef getName() const { return llvm::StringRef(NameStr, NameLen); } }; #define GET_DIAG_ARRAYS @@ -513,7 +570,7 @@ sizeof(OptionTable) / sizeof(OptionTable[0]); static bool WarningOptionCompare(const WarningOption &LHS, const WarningOption &RHS) { - return strcmp(LHS.Name, RHS.Name) < 0; + return LHS.getName() < RHS.getName(); } static void MapGroupMembers(const WarningOption *Group, diag::Mapping Mapping, @@ -534,10 +591,10 @@ static void MapGroupMembers(const WarningOption *Group, diag::Mapping Mapping, /// setDiagnosticGroupMapping - Change an entire diagnostic group (e.g. /// "unknown-pragmas" to have the specified mapping. This returns true and /// ignores the request if "Group" was unknown, false otherwise. -bool DiagnosticIDs::setDiagnosticGroupMapping(const char *Group, - diag::Mapping Map, - SourceLocation Loc, - Diagnostic &Diag) const { +bool DiagnosticIDs::setDiagnosticGroupMapping(llvm::StringRef Group, + diag::Mapping Map, + SourceLocation Loc, + Diagnostic &Diag) const { assert((Loc.isValid() || Diag.DiagStatePoints.empty() || Diag.DiagStatePoints.back().Loc.isInvalid()) && @@ -548,12 +605,12 @@ bool DiagnosticIDs::setDiagnosticGroupMapping(const char *Group, Diag.DiagStatePoints.back().Loc)) && "Source location of new mapping is before the previous one!"); - WarningOption Key = { Group, 0, 0 }; + WarningOption Key = { Group.size(), Group.data(), 0, 0 }; const WarningOption *Found = std::lower_bound(OptionTable, OptionTable + OptionTableSize, Key, WarningOptionCompare); if (Found == OptionTable + OptionTableSize || - strcmp(Found->Name, Group) != 0) + Found->getName() != Group) return true; // Option not found. MapGroupMembers(Found, Map, Loc, Diag); diff --git a/contrib/llvm/tools/clang/lib/Basic/FileManager.cpp b/contrib/llvm/tools/clang/lib/Basic/FileManager.cpp index 4e5a129..f747c53 100644 --- a/contrib/llvm/tools/clang/lib/Basic/FileManager.cpp +++ b/contrib/llvm/tools/clang/lib/Basic/FileManager.cpp @@ -264,10 +264,6 @@ void FileManager::addAncestorsAsVirtualDirs(llvm::StringRef Path) { /// exist. /// const DirectoryEntry *FileManager::getDirectory(llvm::StringRef DirName) { - // stat doesn't like trailing separators (at least on Windows). - if (DirName.size() > 1 && llvm::sys::path::is_separator(DirName.back())) - DirName = DirName.substr(0, DirName.size()-1); - ++NumDirLookups; llvm::StringMapEntry<DirectoryEntry *> &NamedDirEnt = SeenDirEntries.GetOrCreateValue(DirName); diff --git a/contrib/llvm/tools/clang/lib/Basic/IdentifierTable.cpp b/contrib/llvm/tools/clang/lib/Basic/IdentifierTable.cpp index cb1f55b..4711faa 100644 --- a/contrib/llvm/tools/clang/lib/Basic/IdentifierTable.cpp +++ b/contrib/llvm/tools/clang/lib/Basic/IdentifierTable.cpp @@ -392,6 +392,7 @@ ObjCMethodFamily Selector::getMethodFamilyImpl(Selector sel) { if (name == "release") return OMF_release; if (name == "retain") return OMF_retain; if (name == "retainCount") return OMF_retainCount; + if (name == "self") return OMF_self; } // The other method families may begin with a prefix of underscores. diff --git a/contrib/llvm/tools/clang/lib/Basic/SourceManager.cpp b/contrib/llvm/tools/clang/lib/Basic/SourceManager.cpp index c3e0393..2de8ab7 100644 --- a/contrib/llvm/tools/clang/lib/Basic/SourceManager.cpp +++ b/contrib/llvm/tools/clang/lib/Basic/SourceManager.cpp @@ -961,6 +961,12 @@ static void ComputeLineNumbers(Diagnostic &Diag, ContentCache *FI, /// about to emit a diagnostic. unsigned SourceManager::getLineNumber(FileID FID, unsigned FilePos, bool *Invalid) const { + if (FID.isInvalid()) { + if (Invalid) + *Invalid = true; + return 1; + } + ContentCache *Content; if (LastLineNoFileIDQuery == FID) Content = LastLineNoContentCache; @@ -1207,6 +1213,73 @@ PresumedLoc SourceManager::getPresumedLoc(SourceLocation Loc) const { return PresumedLoc(Filename, LineNo, ColNo, IncludeLoc); } +/// \brief Returns true if the given MacroID location points at the first +/// token of the macro instantiation. +bool SourceManager::isAtStartOfMacroInstantiation(SourceLocation loc) const { + assert(loc.isValid() && loc.isMacroID() && "Expected a valid macro loc"); + + unsigned FID = getFileID(loc).ID; + assert(FID > 1); + std::pair<SourceLocation, SourceLocation> + instRange = getImmediateInstantiationRange(loc); + + bool invalid = false; + const SrcMgr::SLocEntry &Entry = getSLocEntry(FID-1, &invalid); + if (invalid) + return false; + + // If the FileID immediately before it is a file then this is the first token + // in the macro. + if (Entry.isFile()) + return true; + + // If the FileID immediately before it (which is a macro token) is the + // immediate instantiated macro, check this macro token's location. + if (getFileID(instRange.second).ID == FID-1) + return isAtStartOfMacroInstantiation(instRange.first); + + // If the FileID immediately before it (which is a macro token) came from a + // different instantiation, then this is the first token in the macro. + if (getInstantiationLoc(Entry.getInstantiation().getInstantiationLocStart()) + != getInstantiationLoc(loc)) + return true; + + // It is inside the macro or the last token in the macro. + return false; +} + +/// \brief Returns true if the given MacroID location points at the last +/// token of the macro instantiation. +bool SourceManager::isAtEndOfMacroInstantiation(SourceLocation loc) const { + assert(loc.isValid() && loc.isMacroID() && "Expected a valid macro loc"); + + unsigned FID = getFileID(loc).ID; + assert(FID > 1); + std::pair<SourceLocation, SourceLocation> + instRange = getInstantiationRange(loc); + + // If there's no FileID after it, it is the last token in the macro. + if (FID+1 == sloc_entry_size()) + return true; + + bool invalid = false; + const SrcMgr::SLocEntry &Entry = getSLocEntry(FID+1, &invalid); + if (invalid) + return false; + + // If the FileID immediately after it is a file or a macro token which + // came from a different instantiation, then this is the last token in the + // macro. + if (Entry.isFile()) + return true; + if (getInstantiationLoc(Entry.getInstantiation().getInstantiationLocStart()) + != instRange.first) + return true; + + // It is inside the macro or the first token in the macro. + return false; +} + //===----------------------------------------------------------------------===// // Other miscellaneous methods. //===----------------------------------------------------------------------===// diff --git a/contrib/llvm/tools/clang/lib/Basic/Targets.cpp b/contrib/llvm/tools/clang/lib/Basic/Targets.cpp index 97109ca..dd167dc 100644 --- a/contrib/llvm/tools/clang/lib/Basic/Targets.cpp +++ b/contrib/llvm/tools/clang/lib/Basic/Targets.cpp @@ -1121,7 +1121,7 @@ public: } virtual bool validateAsmConstraint(const char *&Name, TargetInfo::ConstraintInfo &info) const; - virtual std::string convertConstraint(const char Constraint) const; + virtual std::string convertConstraint(const char *&Constraint) const; virtual const char *getClobbers() const { return "~{dirflag},~{fpsr},~{flags}"; } @@ -1180,7 +1180,7 @@ void X86TargetInfo::getDefaultFeatures(const std::string &CPU, else if (CPU == "corei7") { setFeatureEnabled(Features, "sse4", true); setFeatureEnabled(Features, "aes", true); - } else if (CPU == "sandybridge") { + } else if (CPU == "corei7-avx") { setFeatureEnabled(Features, "sse4", true); setFeatureEnabled(Features, "aes", true); // setFeatureEnabled(Features, "avx", true); @@ -1449,8 +1449,8 @@ X86TargetInfo::validateAsmConstraint(const char *&Name, std::string -X86TargetInfo::convertConstraint(const char Constraint) const { - switch (Constraint) { +X86TargetInfo::convertConstraint(const char *&Constraint) const { + switch (*Constraint) { case 'a': return std::string("{ax}"); case 'b': return std::string("{bx}"); case 'c': return std::string("{cx}"); @@ -1464,7 +1464,7 @@ X86TargetInfo::convertConstraint(const char Constraint) const { case 'u': // second from top of floating point stack. return std::string("{st(1)}"); // second from top of floating point stack. default: - return std::string(1, Constraint); + return std::string(1, *Constraint); } } } // end anonymous namespace @@ -1993,11 +1993,11 @@ public: if (CPU == "xscale") Builder.defineMacro("__XSCALE__"); - bool IsThumb2 = IsThumb && (CPUArch == "6T2" || CPUArch.startswith("7")); + bool IsARMv7 = CPUArch.startswith("7"); if (IsThumb) { Builder.defineMacro("__THUMBEL__"); Builder.defineMacro("__thumb__"); - if (IsThumb2) + if (CPUArch == "6T2" || IsARMv7) Builder.defineMacro("__thumb2__"); } @@ -2011,7 +2011,7 @@ public: // the VFP define, hence the soft float and arch check. This is subtly // different from gcc, we follow the intent which was that it should be set // when Neon instructions are actually available. - if (FPU == NeonFPU && !SoftFloat && IsThumb2) + if (FPU == NeonFPU && !SoftFloat && IsARMv7) Builder.defineMacro("__ARM_NEON__"); } virtual void getTargetBuiltins(const Builtin::Info *&Records, @@ -2020,7 +2020,7 @@ public: NumRecords = clang::ARM::LastTSBuiltin-Builtin::FirstTSBuiltin; } virtual const char *getVAListDeclaration() const { - return "typedef char* __builtin_va_list;"; + return "typedef void* __builtin_va_list;"; } virtual void getGCCRegNames(const char * const *&Names, unsigned &NumNames) const; @@ -2037,9 +2037,31 @@ public: case 'P': // VFP Floating point register double precision Info.setAllowsRegister(); return true; + case 'U': // a memory reference... + switch (Name[1]) { + case 'q': // ...ARMV4 ldrsb + case 'v': // ...VFP load/store (reg+constant offset) + case 'y': // ...iWMMXt load/store + Info.setAllowsMemory(); + Name++; + return true; + } } return false; } + std::string + virtual convertConstraint(const char *&Constraint) const { + std::string R; + switch (*Constraint) { + case 'U': // Two-character constraint; add "^" hint for later parsing. + R = std::string("^") + std::string(Constraint, 2); + Constraint++; + break; + default: + return std::string(1, *Constraint); + } + return R; + } virtual const char *getClobbers() const { // FIXME: Is this really right? return ""; @@ -2531,7 +2553,9 @@ class MipsTargetInfo : public TargetInfo { public: MipsTargetInfo(const std::string& triple) : TargetInfo(triple), ABI("o32") { DescriptionString = "E-p:32:32:32-i1:8:8-i8:8:32-i16:16:32-i32:32:32-" - "i64:32:64-f32:32:32-f64:64:64-v64:64:64-n32"; + "i64:64:64-f32:32:32-f64:64:64-v64:64:64-n32"; + SizeType = UnsignedInt; + PtrDiffType = SignedInt; } virtual const char *getABI() const { return ABI.c_str(); } virtual bool setABI(const std::string &Name) { @@ -2663,7 +2687,7 @@ class MipselTargetInfo : public MipsTargetInfo { public: MipselTargetInfo(const std::string& triple) : MipsTargetInfo(triple) { DescriptionString = "e-p:32:32:32-i1:8:8-i8:8:32-i16:16:32-i32:32:32-" - "i64:32:64-f32:32:32-f64:64:64-v64:64:64-n32"; + "i64:64:64-f32:32:32-f64:64:64-v64:64:64-n32"; } virtual void getTargetDefines(const LangOptions &Opts, diff --git a/contrib/llvm/tools/clang/lib/CodeGen/BackendUtil.cpp b/contrib/llvm/tools/clang/lib/CodeGen/BackendUtil.cpp index 1264473..01d15ff 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/BackendUtil.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/BackendUtil.cpp @@ -21,12 +21,11 @@ #include "llvm/Support/CommandLine.h" #include "llvm/Support/FormattedStream.h" #include "llvm/Support/PrettyStackTrace.h" -#include "llvm/Support/StandardPasses.h" +#include "llvm/Support/PassManagerBuilder.h" #include "llvm/Support/Timer.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Target/SubtargetFeature.h" #include "llvm/Target/TargetData.h" -#include "llvm/Target/TargetLibraryInfo.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetOptions.h" #include "llvm/Target/TargetRegistry.h" @@ -109,67 +108,62 @@ void EmitAssemblyHelper::CreatePasses() { OptLevel = 0; Inlining = CodeGenOpts.NoInlining; } - - FunctionPassManager *FPM = getPerFunctionPasses(); - - TargetLibraryInfo *TLI = - new TargetLibraryInfo(Triple(TheModule->getTargetTriple())); + + PassManagerBuilder PMBuilder; + PMBuilder.OptLevel = OptLevel; + PMBuilder.SizeLevel = CodeGenOpts.OptimizeSize; + + PMBuilder.DisableSimplifyLibCalls = !CodeGenOpts.SimplifyLibCalls; + PMBuilder.DisableUnitAtATime = !CodeGenOpts.UnitAtATime; + PMBuilder.DisableUnrollLoops = !CodeGenOpts.UnrollLoops; + + // Figure out TargetLibraryInfo. + Triple TargetTriple(TheModule->getTargetTriple()); + PMBuilder.LibraryInfo = new TargetLibraryInfo(TargetTriple); if (!CodeGenOpts.SimplifyLibCalls) - TLI->disableAllFunctions(); - FPM->add(TLI); - - // In -O0 if checking is disabled, we don't even have per-function passes. - if (CodeGenOpts.VerifyModule) - FPM->add(createVerifierPass()); - - // Assume that standard function passes aren't run for -O0. - if (OptLevel > 0) - llvm::createStandardFunctionPasses(FPM, OptLevel); - - llvm::Pass *InliningPass = 0; + PMBuilder.LibraryInfo->disableAllFunctions(); + switch (Inlining) { case CodeGenOptions::NoInlining: break; case CodeGenOptions::NormalInlining: { - // Set the inline threshold following llvm-gcc. - // // FIXME: Derive these constants in a principled fashion. unsigned Threshold = 225; - if (CodeGenOpts.OptimizeSize == 1) //-Os + if (CodeGenOpts.OptimizeSize == 1) // -Os Threshold = 75; - else if (CodeGenOpts.OptimizeSize == 2) //-Oz + else if (CodeGenOpts.OptimizeSize == 2) // -Oz Threshold = 25; else if (OptLevel > 2) Threshold = 275; - InliningPass = createFunctionInliningPass(Threshold); + PMBuilder.Inliner = createFunctionInliningPass(Threshold); break; } case CodeGenOptions::OnlyAlwaysInlining: - InliningPass = createAlwaysInlinerPass(); // Respect always_inline + // Respect always_inline. + PMBuilder.Inliner = createAlwaysInlinerPass(); break; } - PassManager *MPM = getPerModulePasses(); + + // Set up the per-function pass manager. + FunctionPassManager *FPM = getPerFunctionPasses(); + if (CodeGenOpts.VerifyModule) + FPM->add(createVerifierPass()); + PMBuilder.populateFunctionPassManager(*FPM); - TLI = new TargetLibraryInfo(Triple(TheModule->getTargetTriple())); - if (!CodeGenOpts.SimplifyLibCalls) - TLI->disableAllFunctions(); - MPM->add(TLI); + // Set up the per-module pass manager. + PassManager *MPM = getPerModulePasses(); if (CodeGenOpts.EmitGcovArcs || CodeGenOpts.EmitGcovNotes) { MPM->add(createGCOVProfilerPass(CodeGenOpts.EmitGcovNotes, - CodeGenOpts.EmitGcovArcs)); + CodeGenOpts.EmitGcovArcs, + TargetTriple.isMacOSX())); + if (!CodeGenOpts.DebugInfo) MPM->add(createStripSymbolsPass(true)); } - - // For now we always create per module passes. - llvm::createStandardModulePasses(MPM, OptLevel, - CodeGenOpts.OptimizeSize, - CodeGenOpts.UnitAtATime, - CodeGenOpts.UnrollLoops, - CodeGenOpts.SimplifyLibCalls, - /*HaveExceptions=*/true, - InliningPass); + + + PMBuilder.populateModulePassManager(*MPM); } bool EmitAssemblyHelper::AddEmitPasses(BackendAction Action, @@ -215,7 +209,6 @@ bool EmitAssemblyHelper::AddEmitPasses(BackendAction Action, NoZerosInBSS = CodeGenOpts.NoZeroInitializedInBSS; llvm::UnsafeFPMath = CodeGenOpts.UnsafeFPMath; llvm::UseSoftFloat = CodeGenOpts.SoftFloat; - UnwindTablesMandatory = CodeGenOpts.UnwindTables; TargetMachine::setAsmVerbosityDefault(CodeGenOpts.AsmVerbose); diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGBlocks.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGBlocks.cpp index 99a69a4..e5da703 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGBlocks.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGBlocks.cpp @@ -189,23 +189,6 @@ namespace { } } -/// Determines if the given record type has a mutable field. -static bool hasMutableField(const CXXRecordDecl *record) { - for (CXXRecordDecl::field_iterator - i = record->field_begin(), e = record->field_end(); i != e; ++i) - if ((*i)->isMutable()) - return true; - - for (CXXRecordDecl::base_class_const_iterator - i = record->bases_begin(), e = record->bases_end(); i != e; ++i) { - const RecordType *record = i->getType()->castAs<RecordType>(); - if (hasMutableField(cast<CXXRecordDecl>(record->getDecl()))) - return true; - } - - return false; -} - /// Determines if the given type is safe for constant capture in C++. static bool isSafeForCXXConstantCapture(QualType type) { const RecordType *recordType = @@ -222,7 +205,7 @@ static bool isSafeForCXXConstantCapture(QualType type) { // Otherwise, we just have to make sure there aren't any mutable // fields that might have changed since initialization. - return !hasMutableField(record); + return !record->hasMutableFields(); } /// It is illegal to modify a const object after initialization. @@ -262,7 +245,7 @@ static CharUnits getLowBit(CharUnits v) { } static void initializeForBlockHeader(CodeGenModule &CGM, CGBlockInfo &info, - std::vector<const llvm::Type*> &elementTypes) { + llvm::SmallVectorImpl<const llvm::Type*> &elementTypes) { ASTContext &C = CGM.getContext(); // The header is basically a 'struct { void *; int; int; void *; void *; }'. @@ -299,7 +282,7 @@ static void computeBlockInfo(CodeGenModule &CGM, CGBlockInfo &info) { ASTContext &C = CGM.getContext(); const BlockDecl *block = info.getBlockDecl(); - std::vector<const llvm::Type*> elementTypes; + llvm::SmallVector<const llvm::Type*, 8> elementTypes; initializeForBlockHeader(CGM, info, elementTypes); if (!block->hasCaptures()) { @@ -321,7 +304,11 @@ static void computeBlockInfo(CodeGenModule &CGM, CGBlockInfo &info) { const DeclContext *DC = block->getDeclContext(); for (; isa<BlockDecl>(DC); DC = cast<BlockDecl>(DC)->getDeclContext()) ; - QualType thisType = cast<CXXMethodDecl>(DC)->getThisType(C); + QualType thisType; + if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(DC)) + thisType = C.getPointerType(C.getRecordType(RD)); + else + thisType = cast<CXXMethodDecl>(DC)->getThisType(C); const llvm::Type *llvmType = CGM.getTypes().ConvertType(thisType); std::pair<CharUnits,CharUnits> tinfo @@ -720,9 +707,8 @@ RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr* E, BlockLiteral = Builder.CreateBitCast(BlockLiteral, VoidPtrTy, "tmp"); // Add the block literal. - QualType VoidPtrTy = getContext().getPointerType(getContext().VoidTy); CallArgList Args; - Args.add(RValue::get(BlockLiteral), VoidPtrTy); + Args.add(RValue::get(BlockLiteral), getContext().VoidPtrTy); QualType FnType = BPT->getPointeeType(); @@ -1063,6 +1049,10 @@ CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) { IdentifierInfo *II = &CGM.getContext().Idents.get("__copy_helper_block_"); + // Check if we should generate debug info for this block helper function. + if (CGM.getModuleDebugInfo()) + DebugInfo = CGM.getModuleDebugInfo(); + FunctionDecl *FD = FunctionDecl::Create(C, C.getTranslationUnitDecl(), SourceLocation(), @@ -1150,6 +1140,10 @@ CodeGenFunction::GenerateDestroyHelperFunction(const CGBlockInfo &blockInfo) { llvm::Function::Create(LTy, llvm::GlobalValue::InternalLinkage, "__destroy_helper_block_", &CGM.getModule()); + // Check if we should generate debug info for this block destroy function. + if (CGM.getModuleDebugInfo()) + DebugInfo = CGM.getModuleDebugInfo(); + IdentifierInfo *II = &CGM.getContext().Idents.get("__destroy_helper_block_"); @@ -1508,29 +1502,29 @@ const llvm::Type *CodeGenFunction::BuildByRefType(const VarDecl *D) { QualType Ty = D->getType(); - std::vector<const llvm::Type *> Types; + llvm::SmallVector<const llvm::Type *, 8> types; llvm::PATypeHolder ByRefTypeHolder = llvm::OpaqueType::get(getLLVMContext()); // void *__isa; - Types.push_back(Int8PtrTy); + types.push_back(Int8PtrTy); // void *__forwarding; - Types.push_back(llvm::PointerType::getUnqual(ByRefTypeHolder)); + types.push_back(llvm::PointerType::getUnqual(ByRefTypeHolder)); // int32_t __flags; - Types.push_back(Int32Ty); + types.push_back(Int32Ty); // int32_t __size; - Types.push_back(Int32Ty); + types.push_back(Int32Ty); bool HasCopyAndDispose = getContext().BlockRequiresCopying(Ty); if (HasCopyAndDispose) { /// void *__copy_helper; - Types.push_back(Int8PtrTy); + types.push_back(Int8PtrTy); /// void *__destroy_helper; - Types.push_back(Int8PtrTy); + types.push_back(Int8PtrTy); } bool Packed = false; @@ -1553,11 +1547,11 @@ const llvm::Type *CodeGenFunction::BuildByRefType(const VarDecl *D) { if (NumPaddingBytes > 0) { const llvm::Type *Ty = llvm::Type::getInt8Ty(getLLVMContext()); // FIXME: We need a sema error for alignment larger than the minimum of - // the maximal stack alignmint and the alignment of malloc on the system. + // the maximal stack alignment and the alignment of malloc on the system. if (NumPaddingBytes > 1) Ty = llvm::ArrayType::get(Ty, NumPaddingBytes); - Types.push_back(Ty); + types.push_back(Ty); // We want a packed struct. Packed = true; @@ -1565,9 +1559,9 @@ const llvm::Type *CodeGenFunction::BuildByRefType(const VarDecl *D) { } // T x; - Types.push_back(ConvertTypeForMem(Ty)); + types.push_back(ConvertTypeForMem(Ty)); - const llvm::Type *T = llvm::StructType::get(getLLVMContext(), Types, Packed); + const llvm::Type *T = llvm::StructType::get(getLLVMContext(), types, Packed); cast<llvm::OpaqueType>(ByRefTypeHolder.get())->refineAbstractTypeTo(T); CGM.getModule().addTypeName("struct.__block_byref_" + D->getNameAsString(), @@ -1575,7 +1569,7 @@ const llvm::Type *CodeGenFunction::BuildByRefType(const VarDecl *D) { Info.first = ByRefTypeHolder.get(); - Info.second = Types.size() - 1; + Info.second = types.size() - 1; return Info.first; } diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGBuiltin.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGBuiltin.cpp index 7a0c8da..14bebaf 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGBuiltin.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGBuiltin.cpp @@ -164,9 +164,8 @@ static Value *EmitFAbs(CodeGenFunction &CGF, Value *V, QualType ValTy) { } // The prototype is something that takes and returns whatever V's type is. - std::vector<const llvm::Type*> Args; - Args.push_back(V->getType()); - llvm::FunctionType *FT = llvm::FunctionType::get(V->getType(), Args, false); + llvm::FunctionType *FT = llvm::FunctionType::get(V->getType(), V->getType(), + false); llvm::Value *Fn = CGF.CGM.CreateRuntimeFunction(FT, FnName); return CGF.Builder.CreateCall(Fn, V, "abs"); @@ -1186,6 +1185,41 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID, Ops.begin(), Ops.end()); } + if (BuiltinID == ARM::BI__builtin_arm_ldrexd) { + Function *F = CGM.getIntrinsic(Intrinsic::arm_ldrexd); + + Value *LdPtr = EmitScalarExpr(E->getArg(0)); + Value *Val = Builder.CreateCall(F, LdPtr, "ldrexd"); + + Value *Val0 = Builder.CreateExtractValue(Val, 1); + Value *Val1 = Builder.CreateExtractValue(Val, 0); + Val0 = Builder.CreateZExt(Val0, Int64Ty); + Val1 = Builder.CreateZExt(Val1, Int64Ty); + + Value *ShiftCst = llvm::ConstantInt::get(Int64Ty, 32); + Val = Builder.CreateShl(Val0, ShiftCst, "shl", true /* nuw */); + return Builder.CreateOr(Val, Val1); + } + + if (BuiltinID == ARM::BI__builtin_arm_strexd) { + Function *F = CGM.getIntrinsic(Intrinsic::arm_strexd); + llvm::Type *STy = llvm::StructType::get(getLLVMContext(), Int32Ty, Int32Ty, + NULL); + + Value *One = llvm::ConstantInt::get(Int32Ty, 1); + Value *Tmp = Builder.CreateAlloca(Int64Ty, One, "tmp"); + Value *Val = EmitScalarExpr(E->getArg(0)); + Builder.CreateStore(Val, Tmp); + + Value *LdPtr = Builder.CreateBitCast(Tmp,llvm::PointerType::getUnqual(STy)); + Val = Builder.CreateLoad(LdPtr); + + Value *Arg0 = Builder.CreateExtractValue(Val, 0); + Value *Arg1 = Builder.CreateExtractValue(Val, 1); + Value *StPtr = EmitScalarExpr(E->getArg(1)); + return Builder.CreateCall3(F, Arg0, Arg1, StPtr, "strexd"); + } + llvm::SmallVector<Value*, 4> Ops; for (unsigned i = 0, e = E->getNumArgs() - 1; i != e; i++) Ops.push_back(EmitScalarExpr(E->getArg(i))); @@ -2143,16 +2177,21 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID, // If palignr is shifting the pair of vectors more than 32 bytes, emit zero. return llvm::Constant::getNullValue(ConvertType(E->getType())); } - case X86::BI__builtin_ia32_loaddqu: { - const llvm::Type *VecTy = ConvertType(E->getType()); - const llvm::Type *IntTy = llvm::IntegerType::get(getLLVMContext(), 128); + case X86::BI__builtin_ia32_movntps: + case X86::BI__builtin_ia32_movntpd: + case X86::BI__builtin_ia32_movntdq: + case X86::BI__builtin_ia32_movnti: { + llvm::MDNode *Node = llvm::MDNode::get(getLLVMContext(), + Builder.getInt32(1)); + // Convert the type of the pointer to a pointer to the stored type. Value *BC = Builder.CreateBitCast(Ops[0], - llvm::PointerType::getUnqual(IntTy), + llvm::PointerType::getUnqual(Ops[1]->getType()), "cast"); - LoadInst *LI = Builder.CreateLoad(BC); - LI->setAlignment(1); // Unaligned load. - return Builder.CreateBitCast(LI, VecTy, "loadu.cast"); + StoreInst *SI = Builder.CreateStore(Ops[1], BC); + SI->setMetadata(CGM.getModule().getMDKindID("nontemporal"), Node); + SI->setAlignment(16); + return SI; } // 3DNow! case X86::BI__builtin_ia32_pavgusb: diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGCXX.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGCXX.cpp index 184147c..f6fc202 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGCXX.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGCXX.cpp @@ -28,17 +28,6 @@ using namespace clang; using namespace CodeGen; -/// Determines whether the given function has a trivial body that does -/// not require any specific codegen. -static bool HasTrivialBody(const FunctionDecl *FD) { - Stmt *S = FD->getBody(); - if (!S) - return true; - if (isa<CompoundStmt>(S) && cast<CompoundStmt>(S)->body_empty()) - return true; - return false; -} - /// Try to emit a base destructor as an alias to its primary /// base-class destructor. bool CodeGenModule::TryEmitBaseDestructorAsAlias(const CXXDestructorDecl *D) { @@ -47,7 +36,7 @@ bool CodeGenModule::TryEmitBaseDestructorAsAlias(const CXXDestructorDecl *D) { // If the destructor doesn't have a trivial body, we have to emit it // separately. - if (!HasTrivialBody(D)) + if (!D->hasTrivialBody()) return true; const CXXRecordDecl *Class = D->getParent(); @@ -187,7 +176,10 @@ bool CodeGenModule::TryEmitDefinitionAsAlias(GlobalDecl AliasDecl, void CodeGenModule::EmitCXXConstructors(const CXXConstructorDecl *D) { // The constructor used for constructing this as a complete class; // constucts the virtual bases, then calls the base constructor. - EmitGlobal(GlobalDecl(D, Ctor_Complete)); + if (!D->getParent()->isAbstract()) { + // We don't need to emit the complete ctor if the class is abstract. + EmitGlobal(GlobalDecl(D, Ctor_Complete)); + } // The constructor used for constructing this as a base class; // ignores virtual bases. @@ -244,7 +236,11 @@ void CodeGenModule::EmitCXXDestructors(const CXXDestructorDecl *D) { // The destructor used for destructing this as a most-derived class; // call the base destructor and then destructs any virtual bases. - EmitGlobal(GlobalDecl(D, Dtor_Complete)); + if (!D->getParent()->isAbstract() || D->isVirtual()) { + // We don't need to emit the complete ctor if the class is abstract, + // unless the destructor is virtual and needs to be in the vtable. + EmitGlobal(GlobalDecl(D, Dtor_Complete)); + } // The destructor used for destructing this as a base class; ignores // virtual bases. diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGCall.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGCall.cpp index a765f0f..712ae89 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGCall.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGCall.cpp @@ -309,10 +309,10 @@ CGFunctionInfo::CGFunctionInfo(unsigned _CallingConvention, /***/ -void CodeGenTypes::GetExpandedTypes(QualType Ty, - std::vector<const llvm::Type*> &ArgTys, - bool IsRecursive) { - const RecordType *RT = Ty->getAsStructureType(); +void CodeGenTypes::GetExpandedTypes(QualType type, + llvm::SmallVectorImpl<const llvm::Type*> &expandedTypes, + bool isRecursive) { + const RecordType *RT = type->getAsStructureType(); assert(RT && "Can only expand structure types."); const RecordDecl *RD = RT->getDecl(); assert(!RD->hasFlexibleArrayMember() && @@ -324,11 +324,11 @@ void CodeGenTypes::GetExpandedTypes(QualType Ty, assert(!FD->isBitField() && "Cannot expand structure with bit-field members."); - QualType FT = FD->getType(); - if (CodeGenFunction::hasAggregateLLVMType(FT)) - GetExpandedTypes(FT, ArgTys, IsRecursive); + QualType fieldType = FD->getType(); + if (fieldType->isRecordType()) + GetExpandedTypes(fieldType, expandedTypes, isRecursive); else - ArgTys.push_back(ConvertType(FT, IsRecursive)); + expandedTypes.push_back(ConvertType(fieldType, isRecursive)); } } @@ -513,6 +513,29 @@ static llvm::Value *CreateCoercedLoad(llvm::Value *SrcPtr, return CGF.Builder.CreateLoad(Tmp); } +// Function to store a first-class aggregate into memory. We prefer to +// store the elements rather than the aggregate to be more friendly to +// fast-isel. +// FIXME: Do we need to recurse here? +static void BuildAggStore(CodeGenFunction &CGF, llvm::Value *Val, + llvm::Value *DestPtr, bool DestIsVolatile, + bool LowAlignment) { + // Prefer scalar stores to first-class aggregate stores. + if (const llvm::StructType *STy = + dyn_cast<llvm::StructType>(Val->getType())) { + for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i) { + llvm::Value *EltPtr = CGF.Builder.CreateConstGEP2_32(DestPtr, 0, i); + llvm::Value *Elt = CGF.Builder.CreateExtractValue(Val, i); + llvm::StoreInst *SI = CGF.Builder.CreateStore(Elt, EltPtr, + DestIsVolatile); + if (LowAlignment) + SI->setAlignment(1); + } + } else { + CGF.Builder.CreateStore(Val, DestPtr, DestIsVolatile); + } +} + /// CreateCoercedStore - Create a store to \arg DstPtr from \arg Src, /// where the source and destination may have different types. /// @@ -553,7 +576,7 @@ static void CreateCoercedStore(llvm::Value *Src, llvm::Value *Casted = CGF.Builder.CreateBitCast(DstPtr, llvm::PointerType::getUnqual(SrcTy)); // FIXME: Use better alignment / avoid requiring aligned store. - CGF.Builder.CreateStore(Src, Casted, DstIsVolatile)->setAlignment(1); + BuildAggStore(CGF, Src, Casted, DstIsVolatile, true); } else { // Otherwise do coercion through memory. This is stupid, but // simple. @@ -612,49 +635,49 @@ const llvm::FunctionType *CodeGenTypes::GetFunctionType(GlobalDecl GD) { } const llvm::FunctionType * -CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI, bool IsVariadic, - bool IsRecursive) { - std::vector<const llvm::Type*> ArgTys; +CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI, bool isVariadic, + bool isRecursive) { + llvm::SmallVector<const llvm::Type*, 8> argTypes; + const llvm::Type *resultType = 0; - const llvm::Type *ResultType = 0; - - QualType RetTy = FI.getReturnType(); - const ABIArgInfo &RetAI = FI.getReturnInfo(); - switch (RetAI.getKind()) { + const ABIArgInfo &retAI = FI.getReturnInfo(); + switch (retAI.getKind()) { case ABIArgInfo::Expand: - assert(0 && "Invalid ABI kind for return argument"); + llvm_unreachable("Invalid ABI kind for return argument"); case ABIArgInfo::Extend: case ABIArgInfo::Direct: - ResultType = RetAI.getCoerceToType(); + resultType = retAI.getCoerceToType(); break; case ABIArgInfo::Indirect: { - assert(!RetAI.getIndirectAlign() && "Align unused on indirect return."); - ResultType = llvm::Type::getVoidTy(getLLVMContext()); - const llvm::Type *STy = ConvertType(RetTy, IsRecursive); - unsigned AS = Context.getTargetAddressSpace(RetTy); - ArgTys.push_back(llvm::PointerType::get(STy, AS)); + assert(!retAI.getIndirectAlign() && "Align unused on indirect return."); + resultType = llvm::Type::getVoidTy(getLLVMContext()); + + QualType ret = FI.getReturnType(); + const llvm::Type *ty = ConvertType(ret, isRecursive); + unsigned addressSpace = Context.getTargetAddressSpace(ret); + argTypes.push_back(llvm::PointerType::get(ty, addressSpace)); break; } case ABIArgInfo::Ignore: - ResultType = llvm::Type::getVoidTy(getLLVMContext()); + resultType = llvm::Type::getVoidTy(getLLVMContext()); break; } for (CGFunctionInfo::const_arg_iterator it = FI.arg_begin(), ie = FI.arg_end(); it != ie; ++it) { - const ABIArgInfo &AI = it->info; + const ABIArgInfo &argAI = it->info; - switch (AI.getKind()) { + switch (argAI.getKind()) { case ABIArgInfo::Ignore: break; case ABIArgInfo::Indirect: { // indirect arguments are always on the stack, which is addr space #0. - const llvm::Type *LTy = ConvertTypeForMem(it->type, IsRecursive); - ArgTys.push_back(llvm::PointerType::getUnqual(LTy)); + const llvm::Type *LTy = ConvertTypeForMem(it->type, isRecursive); + argTypes.push_back(LTy->getPointerTo()); break; } @@ -663,23 +686,23 @@ CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI, bool IsVariadic, // If the coerce-to type is a first class aggregate, flatten it. Either // way is semantically identical, but fast-isel and the optimizer // generally likes scalar values better than FCAs. - const llvm::Type *ArgTy = AI.getCoerceToType(); - if (const llvm::StructType *STy = dyn_cast<llvm::StructType>(ArgTy)) { - for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i) - ArgTys.push_back(STy->getElementType(i)); + const llvm::Type *argType = argAI.getCoerceToType(); + if (const llvm::StructType *st = dyn_cast<llvm::StructType>(argType)) { + for (unsigned i = 0, e = st->getNumElements(); i != e; ++i) + argTypes.push_back(st->getElementType(i)); } else { - ArgTys.push_back(ArgTy); + argTypes.push_back(argType); } break; } case ABIArgInfo::Expand: - GetExpandedTypes(it->type, ArgTys, IsRecursive); + GetExpandedTypes(it->type, argTypes, isRecursive); break; } } - return llvm::FunctionType::get(ResultType, ArgTys, IsVariadic); + return llvm::FunctionType::get(resultType, argTypes, isVariadic); } const llvm::Type *CodeGenTypes::GetFunctionTypeForVTable(GlobalDecl GD) { @@ -786,9 +809,9 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI, // sense to do it here because parameters are so messed up. switch (AI.getKind()) { case ABIArgInfo::Extend: - if (ParamType->isSignedIntegerType()) + if (ParamType->isSignedIntegerOrEnumerationType()) Attributes |= llvm::Attribute::SExt; - else if (ParamType->isUnsignedIntegerType()) + else if (ParamType->isUnsignedIntegerOrEnumerationType()) Attributes |= llvm::Attribute::ZExt; // FALL THROUGH case ABIArgInfo::Direct: @@ -822,12 +845,12 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI, continue; case ABIArgInfo::Expand: { - std::vector<const llvm::Type*> Tys; + llvm::SmallVector<const llvm::Type*, 8> types; // FIXME: This is rather inefficient. Do we ever actually need to do // anything here? The result should be just reconstructed on the other // side, so extension should be a non-issue. - getTypes().GetExpandedTypes(ParamType, Tys, false); - Index += Tys.size(); + getTypes().GetExpandedTypes(ParamType, types, false); + Index += types.size(); continue; } } @@ -1166,6 +1189,15 @@ void CodeGenFunction::EmitCallArg(CallArgList &args, const Expr *E, return args.add(EmitReferenceBindingToExpr(E, /*InitializedDecl=*/0), type); + if (hasAggregateLLVMType(type) && isa<ImplicitCastExpr>(E) && + cast<CastExpr>(E)->getCastKind() == CK_LValueToRValue) { + LValue L = EmitLValue(cast<CastExpr>(E)->getSubExpr()); + assert(L.isSimple()); + args.add(RValue::getAggregate(L.getAddress(), L.isVolatileQualified()), + type, /*NeedsCopy*/true); + return; + } + args.add(EmitAnyExprToTemp(E), type); } @@ -1231,6 +1263,10 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, Alignment, I->Ty); else StoreComplexToAddr(RV.getComplexVal(), Args.back(), false); + } else if (I->NeedsCopy && !ArgInfo.getIndirectByVal()) { + Args.push_back(CreateMemTemp(I->Ty)); + EmitAggregateCopy(Args.back(), RV.getAggregateAddr(), I->Ty, + RV.isVolatileQualified()); } else { Args.push_back(RV.getAggregateAddr()); } @@ -1409,7 +1445,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, DestPtr = CreateMemTemp(RetTy, "agg.tmp"); DestIsVolatile = false; } - Builder.CreateStore(CI, DestPtr, DestIsVolatile); + BuildAggStore(*this, CI, DestPtr, DestIsVolatile, false); return RValue::getAggregate(DestPtr); } return RValue::get(CI); diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGCall.h b/contrib/llvm/tools/clang/lib/CodeGen/CGCall.h index 3f600c0..160a62e 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGCall.h +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGCall.h @@ -47,8 +47,9 @@ namespace CodeGen { struct CallArg { RValue RV; QualType Ty; - CallArg(RValue rv, QualType ty) - : RV(rv), Ty(ty) + bool NeedsCopy; + CallArg(RValue rv, QualType ty, bool needscopy) + : RV(rv), Ty(ty), NeedsCopy(needscopy) { } }; @@ -57,8 +58,8 @@ namespace CodeGen { class CallArgList : public llvm::SmallVector<CallArg, 16> { public: - void add(RValue rvalue, QualType type) { - push_back(CallArg(rvalue, type)); + void add(RValue rvalue, QualType type, bool needscopy = false) { + push_back(CallArg(rvalue, type, needscopy)); } }; diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGClass.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGClass.cpp index ca8b657..5725d80 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGClass.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGClass.cpp @@ -520,6 +520,7 @@ static void EmitMemberInitializer(CodeGenFunction &CGF, FunctionArgList &Args) { assert(MemberInit->isAnyMemberInitializer() && "Must have member initializer!"); + assert(MemberInit->getInit() && "Must have initializer!"); // non-static data member initializers. FieldDecl *Field = MemberInit->getAnyMember(); @@ -726,12 +727,13 @@ void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD, B != E; ++B) { CXXCtorInitializer *Member = (*B); - if (Member->isBaseInitializer()) + if (Member->isBaseInitializer()) { EmitBaseInitializer(*this, ClassDecl, Member, CtorType); - else if (Member->isAnyMemberInitializer()) + } else { + assert(Member->isAnyMemberInitializer() && + "Delegating initializer on non-delegating constructor"); MemberInitializers.push_back(Member); - else - llvm_unreachable("Delegating initializer on non-delegating constructor"); + } } InitializeVTablePointers(ClassDecl); @@ -740,6 +742,94 @@ void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD, EmitMemberInitializer(*this, ClassDecl, MemberInitializers[I], CD, Args); } +static bool +FieldHasTrivialDestructorBody(ASTContext &Context, const FieldDecl *Field); + +static bool +HasTrivialDestructorBody(ASTContext &Context, + const CXXRecordDecl *BaseClassDecl, + const CXXRecordDecl *MostDerivedClassDecl) +{ + // If the destructor is trivial we don't have to check anything else. + if (BaseClassDecl->hasTrivialDestructor()) + return true; + + if (!BaseClassDecl->getDestructor()->hasTrivialBody()) + return false; + + // Check fields. + for (CXXRecordDecl::field_iterator I = BaseClassDecl->field_begin(), + E = BaseClassDecl->field_end(); I != E; ++I) { + const FieldDecl *Field = *I; + + if (!FieldHasTrivialDestructorBody(Context, Field)) + return false; + } + + // Check non-virtual bases. + for (CXXRecordDecl::base_class_const_iterator I = + BaseClassDecl->bases_begin(), E = BaseClassDecl->bases_end(); + I != E; ++I) { + if (I->isVirtual()) + continue; + + const CXXRecordDecl *NonVirtualBase = + cast<CXXRecordDecl>(I->getType()->castAs<RecordType>()->getDecl()); + if (!HasTrivialDestructorBody(Context, NonVirtualBase, + MostDerivedClassDecl)) + return false; + } + + if (BaseClassDecl == MostDerivedClassDecl) { + // Check virtual bases. + for (CXXRecordDecl::base_class_const_iterator I = + BaseClassDecl->vbases_begin(), E = BaseClassDecl->vbases_end(); + I != E; ++I) { + const CXXRecordDecl *VirtualBase = + cast<CXXRecordDecl>(I->getType()->castAs<RecordType>()->getDecl()); + if (!HasTrivialDestructorBody(Context, VirtualBase, + MostDerivedClassDecl)) + return false; + } + } + + return true; +} + +static bool +FieldHasTrivialDestructorBody(ASTContext &Context, + const FieldDecl *Field) +{ + QualType FieldBaseElementType = Context.getBaseElementType(Field->getType()); + + const RecordType *RT = FieldBaseElementType->getAs<RecordType>(); + if (!RT) + return true; + + CXXRecordDecl *FieldClassDecl = cast<CXXRecordDecl>(RT->getDecl()); + return HasTrivialDestructorBody(Context, FieldClassDecl, FieldClassDecl); +} + +/// CanSkipVTablePointerInitialization - Check whether we need to initialize +/// any vtable pointers before calling this destructor. +static bool CanSkipVTablePointerInitialization(ASTContext &Context, + const CXXDestructorDecl *Dtor) { + if (!Dtor->hasTrivialBody()) + return false; + + // Check the fields. + const CXXRecordDecl *ClassDecl = Dtor->getParent(); + for (CXXRecordDecl::field_iterator I = ClassDecl->field_begin(), + E = ClassDecl->field_end(); I != E; ++I) { + const FieldDecl *Field = *I; + + if (!FieldHasTrivialDestructorBody(Context, Field)) + return false; + } + + return true; +} + /// EmitDestructorBody - Emits the body of the current destructor. void CodeGenFunction::EmitDestructorBody(FunctionArgList &Args) { const CXXDestructorDecl *Dtor = cast<CXXDestructorDecl>(CurGD.getDecl()); @@ -791,7 +881,8 @@ void CodeGenFunction::EmitDestructorBody(FunctionArgList &Args) { EnterDtorCleanups(Dtor, Dtor_Base); // Initialize the vtable pointers before entering the body. - InitializeVTablePointers(Dtor->getParent()); + if (!CanSkipVTablePointerInitialization(getContext(), Dtor)) + InitializeVTablePointers(Dtor->getParent()); if (isTryBody) EmitStmt(cast<CXXTryStmt>(Body)->getTryBlock()); @@ -1269,6 +1360,23 @@ CodeGenFunction::EmitDelegateCXXConstructorCall(const CXXConstructorDecl *Ctor, ReturnValueSlot(), DelegateArgs, Ctor); } +namespace { + struct CallDelegatingCtorDtor : EHScopeStack::Cleanup { + const CXXDestructorDecl *Dtor; + llvm::Value *Addr; + CXXDtorType Type; + + CallDelegatingCtorDtor(const CXXDestructorDecl *D, llvm::Value *Addr, + CXXDtorType Type) + : Dtor(D), Addr(Addr), Type(Type) {} + + void Emit(CodeGenFunction &CGF, bool IsForEH) { + CGF.EmitCXXDestructorCall(Dtor, Type, /*ForVirtualBase=*/false, + Addr); + } + }; +} + void CodeGenFunction::EmitDelegatingCXXConstructorCall(const CXXConstructorDecl *Ctor, const FunctionArgList &Args) { @@ -1279,8 +1387,17 @@ CodeGenFunction::EmitDelegatingCXXConstructorCall(const CXXConstructorDecl *Ctor AggValueSlot AggSlot = AggValueSlot::forAddr(ThisPtr, false, /*Lifetime*/ true); EmitAggExpr(Ctor->init_begin()[0]->getInit(), AggSlot); -} + const CXXRecordDecl *ClassDecl = Ctor->getParent(); + if (CGM.getLangOptions().Exceptions && !ClassDecl->hasTrivialDestructor()) { + CXXDtorType Type = + CurGD.getCtorType() == Ctor_Complete ? Dtor_Complete : Dtor_Base; + + EHStack.pushCleanup<CallDelegatingCtorDtor>(EHCleanup, + ClassDecl->getDestructor(), + ThisPtr, Type); + } +} void CodeGenFunction::EmitCXXDestructorCall(const CXXDestructorDecl *DD, CXXDtorType Type, @@ -1494,3 +1611,136 @@ llvm::Value *CodeGenFunction::GetVTablePtr(llvm::Value *This, llvm::Value *VTablePtrSrc = Builder.CreateBitCast(This, Ty->getPointerTo()); return Builder.CreateLoad(VTablePtrSrc, "vtable"); } + +static const CXXRecordDecl *getMostDerivedClassDecl(const Expr *Base) { + const Expr *E = Base; + + while (true) { + E = E->IgnoreParens(); + if (const CastExpr *CE = dyn_cast<CastExpr>(E)) { + if (CE->getCastKind() == CK_DerivedToBase || + CE->getCastKind() == CK_UncheckedDerivedToBase || + CE->getCastKind() == CK_NoOp) { + E = CE->getSubExpr(); + continue; + } + } + + break; + } + + QualType DerivedType = E->getType(); + if (const PointerType *PTy = DerivedType->getAs<PointerType>()) + DerivedType = PTy->getPointeeType(); + + return cast<CXXRecordDecl>(DerivedType->castAs<RecordType>()->getDecl()); +} + +// FIXME: Ideally Expr::IgnoreParenNoopCasts should do this, but it doesn't do +// quite what we want. +static const Expr *skipNoOpCastsAndParens(const Expr *E) { + while (true) { + if (const ParenExpr *PE = dyn_cast<ParenExpr>(E)) { + E = PE->getSubExpr(); + continue; + } + + if (const CastExpr *CE = dyn_cast<CastExpr>(E)) { + if (CE->getCastKind() == CK_NoOp) { + E = CE->getSubExpr(); + continue; + } + } + if (const UnaryOperator *UO = dyn_cast<UnaryOperator>(E)) { + if (UO->getOpcode() == UO_Extension) { + E = UO->getSubExpr(); + continue; + } + } + return E; + } +} + +/// canDevirtualizeMemberFunctionCall - Checks whether the given virtual member +/// function call on the given expr can be devirtualized. +/// expr can be devirtualized. +static bool canDevirtualizeMemberFunctionCall(const Expr *Base, + const CXXMethodDecl *MD) { + // If the most derived class is marked final, we know that no subclass can + // override this member function and so we can devirtualize it. For example: + // + // struct A { virtual void f(); } + // struct B final : A { }; + // + // void f(B *b) { + // b->f(); + // } + // + const CXXRecordDecl *MostDerivedClassDecl = getMostDerivedClassDecl(Base); + if (MostDerivedClassDecl->hasAttr<FinalAttr>()) + return true; + + // If the member function is marked 'final', we know that it can't be + // overridden and can therefore devirtualize it. + if (MD->hasAttr<FinalAttr>()) + return true; + + // Similarly, if the class itself is marked 'final' it can't be overridden + // and we can therefore devirtualize the member function call. + if (MD->getParent()->hasAttr<FinalAttr>()) + return true; + + Base = skipNoOpCastsAndParens(Base); + if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Base)) { + if (const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl())) { + // This is a record decl. We know the type and can devirtualize it. + return VD->getType()->isRecordType(); + } + + return false; + } + + // We can always devirtualize calls on temporary object expressions. + if (isa<CXXConstructExpr>(Base)) + return true; + + // And calls on bound temporaries. + if (isa<CXXBindTemporaryExpr>(Base)) + return true; + + // Check if this is a call expr that returns a record type. + if (const CallExpr *CE = dyn_cast<CallExpr>(Base)) + return CE->getCallReturnType()->isRecordType(); + + // We can't devirtualize the call. + return false; +} + +static bool UseVirtualCall(ASTContext &Context, + const CXXOperatorCallExpr *CE, + const CXXMethodDecl *MD) { + if (!MD->isVirtual()) + return false; + + // When building with -fapple-kext, all calls must go through the vtable since + // the kernel linker can do runtime patching of vtables. + if (Context.getLangOptions().AppleKext) + return true; + + return !canDevirtualizeMemberFunctionCall(CE->getArg(0), MD); +} + +llvm::Value * +CodeGenFunction::EmitCXXOperatorMemberCallee(const CXXOperatorCallExpr *E, + const CXXMethodDecl *MD, + llvm::Value *This) { + const FunctionProtoType *FPT = MD->getType()->castAs<FunctionProtoType>(); + const llvm::Type *Ty = + CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD), + FPT->isVariadic()); + + if (UseVirtualCall(getContext(), E, MD)) + return BuildVirtualCall(MD, This, Ty); + + return CGM.GetAddrOfFunction(MD, Ty); +} diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGDebugInfo.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGDebugInfo.cpp index f2e1c02..98d30db 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGDebugInfo.cpp @@ -335,10 +335,12 @@ llvm::DIType CGDebugInfo::CreateType(const BuiltinType *BT) { case BuiltinType::SChar: Encoding = llvm::dwarf::DW_ATE_signed_char; break; case BuiltinType::UShort: case BuiltinType::UInt: + case BuiltinType::UInt128: case BuiltinType::ULong: case BuiltinType::ULongLong: Encoding = llvm::dwarf::DW_ATE_unsigned; break; case BuiltinType::Short: case BuiltinType::Int: + case BuiltinType::Int128: case BuiltinType::Long: case BuiltinType::LongLong: Encoding = llvm::dwarf::DW_ATE_signed; break; case BuiltinType::Bool: Encoding = llvm::dwarf::DW_ATE_boolean; break; @@ -553,9 +555,12 @@ llvm::DIType CGDebugInfo::CreateType(const TypedefType *Ty, // We don't set size information, but do specify where the typedef was // declared. unsigned Line = getLineNumber(Ty->getDecl()->getLocation()); - llvm::DIType DbgTy = DBuilder.createTypedef(Src, Ty->getDecl()->getName(), - Unit, Line); - return DbgTy; + const TypedefNameDecl *TyDecl = Ty->getDecl(); + llvm::DIDescriptor TydefContext = + getContextDescriptor(cast<Decl>(Ty->getDecl()->getDeclContext())); + + return + DBuilder.createTypedef(Src, TyDecl->getName(), Unit, Line, TydefContext); } llvm::DIType CGDebugInfo::CreateType(const FunctionType *Ty, @@ -628,8 +633,7 @@ CollectRecordFields(const RecordDecl *record, llvm::DIFile tunit, FieldDecl *field = *I; if (IsMsStruct) { // Zero-length bitfields following non-bitfield members are ignored - if (CGM.getContext().ZeroBitfieldFollowsNonBitfield((field), LastFD) || - CGM.getContext().ZeroBitfieldFollowsBitfield((field), LastFD)) { + if (CGM.getContext().ZeroBitfieldFollowsNonBitfield((field), LastFD)) { --fieldNo; continue; } @@ -1240,9 +1244,13 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty, uint64_t Size = CGM.getContext().getTypeSize(Ty); uint64_t Align = CGM.getContext().getTypeAlign(Ty); + unsigned Flags = 0; + if (ID->getImplementation()) + Flags |= llvm::DIDescriptor::FlagObjcClassComplete; + llvm::DIType RealDecl = DBuilder.createStructType(Unit, ID->getName(), DefUnit, - Line, Size, Align, 0, + Line, Size, Align, Flags, Elements, RuntimeLang); // Now that we have a real decl for the struct, replace anything using the @@ -1439,6 +1447,9 @@ static QualType UnwrapTypeForDebugInfo(QualType T) { case Type::Decltype: T = cast<DecltypeType>(T)->getUnderlyingType(); break; + case Type::UnaryTransform: + T = cast<UnaryTransformType>(T)->getUnderlyingType(); + break; case Type::Attributed: T = cast<AttributedType>(T)->getEquivalentType(); break; @@ -1554,6 +1565,7 @@ llvm::DIType CGDebugInfo::CreateTypeNode(QualType Ty, case Type::TypeOfExpr: case Type::TypeOf: case Type::Decltype: + case Type::UnaryTransform: case Type::Auto: llvm_unreachable("type should have been unwrapped!"); return llvm::DIType(); @@ -1612,6 +1624,33 @@ llvm::DISubprogram CGDebugInfo::getFunctionDeclaration(const Decl *D) { return llvm::DISubprogram(); } +// getOrCreateFunctionType - Construct DIType. If it is a c++ method, include +// implicit parameter "this". +llvm::DIType CGDebugInfo::getOrCreateFunctionType(const Decl * D, QualType FnType, + llvm::DIFile F) { + if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) + return getOrCreateMethodType(Method, F); + else if (const ObjCMethodDecl *OMethod = dyn_cast<ObjCMethodDecl>(D)) { + // Add "self" and "_cmd" + llvm::SmallVector<llvm::Value *, 16> Elts; + + // First element is always return type. For 'void' functions it is NULL. + Elts.push_back(getOrCreateType(OMethod->getResultType(), F)); + // "self" pointer is always first argument. + Elts.push_back(getOrCreateType(OMethod->getSelfDecl()->getType(), F)); + // "cmd" pointer is always second argument. + Elts.push_back(getOrCreateType(OMethod->getCmdDecl()->getType(), F)); + // Get rest of the arguments. + for (ObjCMethodDecl::param_iterator PI = OMethod->param_begin(), + PE = OMethod->param_end(); PI != PE; ++PI) + Elts.push_back(getOrCreateType((*PI)->getType(), F)); + + llvm::DIArray EltTypeArray = DBuilder.getOrCreateArray(Elts); + return DBuilder.createSubroutineType(F, EltTypeArray); + } + return getOrCreateType(FnType, F); +} + /// EmitFunctionStart - Constructs the debug code for entering a function - /// "llvm.dbg.func.start.". void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType, @@ -1644,7 +1683,8 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType, } Name = getFunctionName(FD); // Use mangled name as linkage name for c/c++ functions. - LinkageName = CGM.getMangledName(GD); + if (!Fn->hasInternalLinkage()) + LinkageName = CGM.getMangledName(GD); if (LinkageName == Name) LinkageName = llvm::StringRef(); if (FD->hasPrototype()) @@ -1652,6 +1692,9 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType, if (const NamespaceDecl *NSDecl = dyn_cast_or_null<NamespaceDecl>(FD->getDeclContext())) FDContext = getOrCreateNameSpace(NSDecl); + else if (const RecordDecl *RDecl = + dyn_cast_or_null<RecordDecl>(FD->getDeclContext())) + FDContext = getContextDescriptor(cast<Decl>(RDecl->getDeclContext())); // Collect template parameters. TParamsArray = CollectFunctionTemplateParams(FD, Unit); @@ -1672,11 +1715,10 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType, unsigned LineNo = getLineNumber(CurLoc); if (D->isImplicit()) Flags |= llvm::DIDescriptor::FlagArtificial; - llvm::DIType SPTy = getOrCreateType(FnType, Unit); llvm::DISubprogram SPDecl = getFunctionDeclaration(D); llvm::DISubprogram SP = DBuilder.createFunction(FDContext, Name, LinkageName, Unit, - LineNo, SPTy, + LineNo, getOrCreateFunctionType(D, FnType, Unit), Fn->hasInternalLinkage(), true/*definition*/, Flags, CGM.getLangOptions().Optimize, Fn, TParamsArray, SPDecl); diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGDebugInfo.h b/contrib/llvm/tools/clang/lib/CodeGen/CGDebugInfo.h index 27d991b..6ec6b65 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGDebugInfo.h +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGDebugInfo.h @@ -98,6 +98,8 @@ class CGDebugInfo { llvm::DIType CreateEnumType(const EnumDecl *ED); llvm::DIType getOrCreateMethodType(const CXXMethodDecl *Method, llvm::DIFile F); + llvm::DIType getOrCreateFunctionType(const Decl *D, QualType FnType, + llvm::DIFile F); llvm::DIType getOrCreateVTablePtrType(llvm::DIFile F); llvm::DINameSpace getOrCreateNameSpace(const NamespaceDecl *N); llvm::DIType CreatePointeeType(QualType PointeeTy, llvm::DIFile F); diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGDecl.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGDecl.cpp index c027375..8a1a853 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGDecl.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGDecl.cpp @@ -51,6 +51,7 @@ void CodeGenFunction::EmitDecl(const Decl &D) { case Decl::ImplicitParam: case Decl::ClassTemplate: case Decl::FunctionTemplate: + case Decl::TypeAliasTemplate: case Decl::TemplateTemplateParm: case Decl::ObjCMethod: case Decl::ObjCCategory: @@ -628,15 +629,14 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) { emission.Address = DeclPtr; // Emit debug info for local var declaration. - if (CGDebugInfo *DI = getDebugInfo()) { - assert(HaveInsertPoint() && "Unexpected unreachable point!"); - - DI->setLocation(D.getLocation()); - if (Target.useGlobalsForAutomaticVariables()) { - DI->EmitGlobalVariable(static_cast<llvm::GlobalVariable *>(DeclPtr), &D); - } else - DI->EmitDeclareOfAutoVariable(&D, DeclPtr, Builder); - } + if (HaveInsertPoint()) + if (CGDebugInfo *DI = getDebugInfo()) { + DI->setLocation(D.getLocation()); + if (Target.useGlobalsForAutomaticVariables()) { + DI->EmitGlobalVariable(static_cast<llvm::GlobalVariable *>(DeclPtr), &D); + } else + DI->EmitDeclareOfAutoVariable(&D, DeclPtr, Builder); + } return emission; } @@ -741,6 +741,7 @@ void CodeGenFunction::EmitAutoVarInit(const AutoVarEmission &emission) { llvm::GlobalValue::InternalLinkage, constant, Name, 0, false, 0); GV->setAlignment(alignment.getQuantity()); + GV->setUnnamedAddr(true); llvm::Value *SrcPtr = GV; if (SrcPtr->getType() != BP) diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGDeclCXX.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGDeclCXX.cpp index 45b0b96..178badd 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGDeclCXX.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGDeclCXX.cpp @@ -117,19 +117,13 @@ CodeGenFunction::EmitCXXGlobalDtorRegistration(llvm::Constant *DtorFn, return; } - std::vector<const llvm::Type *> Params; - Params.push_back(Int8PtrTy); - // Get the destructor function type const llvm::Type *DtorFnTy = llvm::FunctionType::get(llvm::Type::getVoidTy(getLLVMContext()), - Params, false); + Int8PtrTy, false); DtorFnTy = llvm::PointerType::getUnqual(DtorFnTy); - Params.clear(); - Params.push_back(DtorFnTy); - Params.push_back(Int8PtrTy); - Params.push_back(Int8PtrTy); + const llvm::Type *Params[] = { DtorFnTy, Int8PtrTy, Int8PtrTy }; // Get the __cxa_atexit function type // extern "C" int __cxa_atexit ( void (*f)(void *), void *p, void *d ); @@ -248,6 +242,8 @@ CodeGenModule::EmitCXXGlobalInitFunc() { &CXXGlobalInits[0], CXXGlobalInits.size()); AddGlobalCtor(Fn); + CXXGlobalInits.clear(); + PrioritizedCXXGlobalInits.clear(); } void CodeGenModule::EmitCXXGlobalDtorFunc() { diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGException.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGException.cpp index 6cb9599..e8ad6da 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGException.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGException.cpp @@ -112,11 +112,18 @@ static llvm::Constant *getUnexpectedFn(CodeGenFunction &CGF) { return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_call_unexpected"); } +llvm::Constant *CodeGenFunction::getUnwindResumeFn() { + const llvm::FunctionType *FTy = + llvm::FunctionType::get(VoidTy, Int8PtrTy, /*IsVarArgs=*/false); + + if (CGM.getLangOptions().SjLjExceptions) + return CGM.CreateRuntimeFunction(FTy, "_Unwind_SjLj_Resume"); + return CGM.CreateRuntimeFunction(FTy, "_Unwind_Resume"); +} + llvm::Constant *CodeGenFunction::getUnwindResumeOrRethrowFn() { - const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(getLLVMContext()); const llvm::FunctionType *FTy = - llvm::FunctionType::get(llvm::Type::getVoidTy(getLLVMContext()), Int8PtrTy, - /*IsVarArgs=*/false); + llvm::FunctionType::get(VoidTy, Int8PtrTy, /*IsVarArgs=*/false); if (CGM.getLangOptions().SjLjExceptions) return CGM.CreateRuntimeFunction(FTy, "_Unwind_SjLj_Resume_or_Rethrow"); @@ -354,13 +361,17 @@ static void EmitAnyExprToExn(CodeGenFunction &CGF, const Expr *e, } llvm::Value *CodeGenFunction::getExceptionSlot() { - if (!ExceptionSlot) { - const llvm::Type *i8p = llvm::Type::getInt8PtrTy(getLLVMContext()); - ExceptionSlot = CreateTempAlloca(i8p, "exn.slot"); - } + if (!ExceptionSlot) + ExceptionSlot = CreateTempAlloca(Int8PtrTy, "exn.slot"); return ExceptionSlot; } +llvm::Value *CodeGenFunction::getEHSelectorSlot() { + if (!EHSelectorSlot) + EHSelectorSlot = CreateTempAlloca(Int32Ty, "ehselector.slot"); + return EHSelectorSlot; +} + void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E) { if (!E->getSubExpr()) { if (getInvokeDest()) { @@ -563,47 +574,59 @@ llvm::BasicBlock *CodeGenFunction::getInvokeDestImpl() { return LP; } +// This code contains a hack to work around a design flaw in +// LLVM's EH IR which breaks semantics after inlining. This same +// hack is implemented in llvm-gcc. +// +// The LLVM EH abstraction is basically a thin veneer over the +// traditional GCC zero-cost design: for each range of instructions +// in the function, there is (at most) one "landing pad" with an +// associated chain of EH actions. A language-specific personality +// function interprets this chain of actions and (1) decides whether +// or not to resume execution at the landing pad and (2) if so, +// provides an integer indicating why it's stopping. In LLVM IR, +// the association of a landing pad with a range of instructions is +// achieved via an invoke instruction, the chain of actions becomes +// the arguments to the @llvm.eh.selector call, and the selector +// call returns the integer indicator. Other than the required +// presence of two intrinsic function calls in the landing pad, +// the IR exactly describes the layout of the output code. +// +// A principal advantage of this design is that it is completely +// language-agnostic; in theory, the LLVM optimizers can treat +// landing pads neutrally, and targets need only know how to lower +// the intrinsics to have a functioning exceptions system (assuming +// that platform exceptions follow something approximately like the +// GCC design). Unfortunately, landing pads cannot be combined in a +// language-agnostic way: given selectors A and B, there is no way +// to make a single landing pad which faithfully represents the +// semantics of propagating an exception first through A, then +// through B, without knowing how the personality will interpret the +// (lowered form of the) selectors. This means that inlining has no +// choice but to crudely chain invokes (i.e., to ignore invokes in +// the inlined function, but to turn all unwindable calls into +// invokes), which is only semantically valid if every unwind stops +// at every landing pad. +// +// Therefore, the invoke-inline hack is to guarantee that every +// landing pad has a catch-all. +enum CleanupHackLevel_t { + /// A level of hack that requires that all landing pads have + /// catch-alls. + CHL_MandatoryCatchall, + + /// A level of hack that requires that all landing pads handle + /// cleanups. + CHL_MandatoryCleanup, + + /// No hacks at all; ideal IR generation. + CHL_Ideal +}; +const CleanupHackLevel_t CleanupHackLevel = CHL_MandatoryCleanup; + llvm::BasicBlock *CodeGenFunction::EmitLandingPad() { assert(EHStack.requiresLandingPad()); - // This function contains a hack to work around a design flaw in - // LLVM's EH IR which breaks semantics after inlining. This same - // hack is implemented in llvm-gcc. - // - // The LLVM EH abstraction is basically a thin veneer over the - // traditional GCC zero-cost design: for each range of instructions - // in the function, there is (at most) one "landing pad" with an - // associated chain of EH actions. A language-specific personality - // function interprets this chain of actions and (1) decides whether - // or not to resume execution at the landing pad and (2) if so, - // provides an integer indicating why it's stopping. In LLVM IR, - // the association of a landing pad with a range of instructions is - // achieved via an invoke instruction, the chain of actions becomes - // the arguments to the @llvm.eh.selector call, and the selector - // call returns the integer indicator. Other than the required - // presence of two intrinsic function calls in the landing pad, - // the IR exactly describes the layout of the output code. - // - // A principal advantage of this design is that it is completely - // language-agnostic; in theory, the LLVM optimizers can treat - // landing pads neutrally, and targets need only know how to lower - // the intrinsics to have a functioning exceptions system (assuming - // that platform exceptions follow something approximately like the - // GCC design). Unfortunately, landing pads cannot be combined in a - // language-agnostic way: given selectors A and B, there is no way - // to make a single landing pad which faithfully represents the - // semantics of propagating an exception first through A, then - // through B, without knowing how the personality will interpret the - // (lowered form of the) selectors. This means that inlining has no - // choice but to crudely chain invokes (i.e., to ignore invokes in - // the inlined function, but to turn all unwindable calls into - // invokes), which is only semantically valid if every unwind stops - // at every landing pad. - // - // Therefore, the invoke-inline hack is to guarantee that every - // landing pad has a catch-all. - const bool UseInvokeInlineHack = true; - for (EHScopeStack::iterator ir = EHStack.begin(); ; ) { assert(ir != EHStack.end() && "stack requiring landing pad is nothing but non-EH scopes?"); @@ -736,16 +759,23 @@ llvm::BasicBlock *CodeGenFunction::EmitLandingPad() { EHSelector.append(EHFilters.begin(), EHFilters.end()); // Also check whether we need a cleanup. - if (UseInvokeInlineHack || HasEHCleanup) - EHSelector.push_back(UseInvokeInlineHack + if (CleanupHackLevel == CHL_MandatoryCatchall || HasEHCleanup) + EHSelector.push_back(CleanupHackLevel == CHL_MandatoryCatchall ? getCatchAllValue(*this) : getCleanupValue(*this)); // Otherwise, signal that we at least have cleanups. - } else if (UseInvokeInlineHack || HasEHCleanup) { - EHSelector.push_back(UseInvokeInlineHack + } else if (CleanupHackLevel == CHL_MandatoryCatchall || HasEHCleanup) { + EHSelector.push_back(CleanupHackLevel == CHL_MandatoryCatchall ? getCatchAllValue(*this) : getCleanupValue(*this)); + + // At the MandatoryCleanup hack level, we don't need to actually + // spuriously tell the unwinder that we have cleanups, but we do + // need to always be prepared to handle cleanups. + } else if (CleanupHackLevel == CHL_MandatoryCleanup) { + // Just don't decrement LastToEmitInLoop. + } else { assert(LastToEmitInLoop > 2); LastToEmitInLoop--; @@ -758,6 +788,10 @@ llvm::BasicBlock *CodeGenFunction::EmitLandingPad() { Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::eh_selector), EHSelector.begin(), EHSelector.end(), "eh.selector"); Selection->setDoesNotThrow(); + + // Save the selector value in mandatory-cleanup mode. + if (CleanupHackLevel == CHL_MandatoryCleanup) + Builder.CreateStore(Selection, getEHSelectorSlot()); // Select the right handler. llvm::Value *llvm_eh_typeid_for = @@ -833,22 +867,13 @@ llvm::BasicBlock *CodeGenFunction::EmitLandingPad() { // If there was a cleanup, we'll need to actually check whether we // landed here because the filter triggered. - if (UseInvokeInlineHack || HasEHCleanup) { - llvm::BasicBlock *RethrowBB = createBasicBlock("cleanup"); + if (CleanupHackLevel != CHL_Ideal || HasEHCleanup) { llvm::BasicBlock *UnexpectedBB = createBasicBlock("ehspec.unexpected"); - llvm::Constant *Zero = llvm::ConstantInt::get(Builder.getInt32Ty(), 0); + llvm::Constant *Zero = llvm::ConstantInt::get(Int32Ty, 0); llvm::Value *FailsFilter = Builder.CreateICmpSLT(SavedSelection, Zero, "ehspec.fails"); - Builder.CreateCondBr(FailsFilter, UnexpectedBB, RethrowBB); - - // The rethrow block is where we land if this was a cleanup. - // TODO: can this be _Unwind_Resume if the InvokeInlineHack is off? - EmitBlock(RethrowBB); - Builder.CreateCall(getUnwindResumeOrRethrowFn(), - Builder.CreateLoad(getExceptionSlot())) - ->setDoesNotReturn(); - Builder.CreateUnreachable(); + Builder.CreateCondBr(FailsFilter, UnexpectedBB, getRethrowDest().getBlock()); EmitBlock(UnexpectedBB); } @@ -863,7 +888,7 @@ llvm::BasicBlock *CodeGenFunction::EmitLandingPad() { Builder.CreateUnreachable(); // ...or a normal catch handler... - } else if (!UseInvokeInlineHack && !HasEHCleanup) { + } else if (CleanupHackLevel == CHL_Ideal && !HasEHCleanup) { llvm::Value *Type = EHSelector.back(); EmitBranchThroughEHCleanup(EHHandlers[Type]); @@ -1440,14 +1465,39 @@ CodeGenFunction::UnwindDest CodeGenFunction::getRethrowDest() { // This can always be a call because we necessarily didn't find // anything on the EH stack which needs our help. llvm::StringRef RethrowName = Personality.getCatchallRethrowFnName(); - llvm::Constant *RethrowFn; - if (!RethrowName.empty()) - RethrowFn = getCatchallRethrowFn(*this, RethrowName); - else - RethrowFn = getUnwindResumeOrRethrowFn(); + if (!RethrowName.empty()) { + Builder.CreateCall(getCatchallRethrowFn(*this, RethrowName), + Builder.CreateLoad(getExceptionSlot())) + ->setDoesNotReturn(); + } else { + llvm::Value *Exn = Builder.CreateLoad(getExceptionSlot()); + + switch (CleanupHackLevel) { + case CHL_MandatoryCatchall: + // In mandatory-catchall mode, we need to use + // _Unwind_Resume_or_Rethrow, or whatever the personality's + // equivalent is. + Builder.CreateCall(getUnwindResumeOrRethrowFn(), Exn) + ->setDoesNotReturn(); + break; + case CHL_MandatoryCleanup: { + // In mandatory-cleanup mode, we should use llvm.eh.resume. + llvm::Value *Selector = Builder.CreateLoad(getEHSelectorSlot()); + Builder.CreateCall2(CGM.getIntrinsic(llvm::Intrinsic::eh_resume), + Exn, Selector) + ->setDoesNotReturn(); + break; + } + case CHL_Ideal: + // In an idealized mode where we don't have to worry about the + // optimizer combining landing pads, we should just use + // _Unwind_Resume (or the personality's equivalent). + Builder.CreateCall(getUnwindResumeFn(), Exn) + ->setDoesNotReturn(); + break; + } + } - Builder.CreateCall(RethrowFn, Builder.CreateLoad(getExceptionSlot())) - ->setDoesNotReturn(); Builder.CreateUnreachable(); Builder.restoreIP(SavedIP); diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGExpr.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGExpr.cpp index bc2cd35..2f6b55b 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGExpr.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGExpr.cpp @@ -1390,7 +1390,7 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E) { // The index must always be an integer, which is not an aggregate. Emit it. llvm::Value *Idx = EmitScalarExpr(E->getIdx()); QualType IdxTy = E->getIdx()->getType(); - bool IdxSigned = IdxTy->isSignedIntegerType(); + bool IdxSigned = IdxTy->isSignedIntegerOrEnumerationType(); // If the base is a vector type, then we are forming a vector element lvalue // with this subscript. @@ -1635,7 +1635,8 @@ LValue CodeGenFunction::EmitLValueForAnonRecordField(llvm::Value *BaseValue, IndirectFieldDecl::chain_iterator I = Field->chain_begin(), IEnd = Field->chain_end(); while (true) { - LValue LV = EmitLValueForField(BaseValue, cast<FieldDecl>(*I), CVRQualifiers); + LValue LV = EmitLValueForField(BaseValue, cast<FieldDecl>(*I), + CVRQualifiers); if (++I == IEnd) return LV; assert(LV.isSimple()); diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGExprAgg.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGExprAgg.cpp index 29c7688..d8da642 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGExprAgg.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGExprAgg.cpp @@ -642,7 +642,7 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) { if (const RecordType *RT = CGF.getContext() .getBaseElementType(ElementType)->getAs<RecordType>()) { const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); - hasNonTrivialCXXConstructor = !RD->hasTrivialConstructor(); + hasNonTrivialCXXConstructor = !RD->hasTrivialDefaultConstructor(); } // FIXME: were we intentionally ignoring address spaces and GC attributes? diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGExprCXX.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGExprCXX.cpp index bdaa873..81fee67 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGExprCXX.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGExprCXX.cpp @@ -345,18 +345,7 @@ CodeGenFunction::EmitCXXOperatorMemberCallExpr(const CXXOperatorCallExpr *E, } } - const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>(); - const llvm::Type *Ty = - CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD), - FPT->isVariadic()); - llvm::Value *Callee; - if (MD->isVirtual() && - !canDevirtualizeMemberFunctionCalls(getContext(), - E->getArg(0), MD)) - Callee = BuildVirtualCall(MD, This, Ty); - else - Callee = CGM.GetAddrOfFunction(MD, Ty); - + llvm::Value *Callee = EmitCXXOperatorMemberCallee(E, MD, This); return EmitCXXMemberCall(MD, Callee, ReturnValue, This, /*VTT=*/0, E->arg_begin() + 1, E->arg_end()); } @@ -403,18 +392,26 @@ CodeGenFunction::EmitCXXConstructExpr(const CXXConstructExpr *E, E->arg_begin(), E->arg_end()); } else { - CXXCtorType Type; - CXXConstructExpr::ConstructionKind K = E->getConstructionKind(); - if (K == CXXConstructExpr::CK_Delegating) { + CXXCtorType Type = Ctor_Complete; + bool ForVirtualBase = false; + + switch (E->getConstructionKind()) { + case CXXConstructExpr::CK_Delegating: // We should be emitting a constructor; GlobalDecl will assert this Type = CurGD.getCtorType(); - } else { - Type = (E->getConstructionKind() == CXXConstructExpr::CK_Complete) - ? Ctor_Complete : Ctor_Base; - } + break; + + case CXXConstructExpr::CK_Complete: + Type = Ctor_Complete; + break; + + case CXXConstructExpr::CK_VirtualBase: + ForVirtualBase = true; + // fall-through - bool ForVirtualBase = - E->getConstructionKind() == CXXConstructExpr::CK_VirtualBase; + case CXXConstructExpr::CK_NonVirtualBase: + Type = Ctor_Base; + } // Call the constructor. EmitCXXConstructorCall(CD, Type, ForVirtualBase, Dest.getAddr(), @@ -447,204 +444,256 @@ CodeGenFunction::EmitSynthesizedCXXCopyCtor(llvm::Value *Dest, E->arg_begin(), E->arg_end()); } -/// Check whether the given operator new[] is the global placement -/// operator new[]. -static bool IsPlacementOperatorNewArray(ASTContext &Ctx, - const FunctionDecl *Fn) { - // Must be in global scope. Note that allocation functions can't be - // declared in namespaces. - if (!Fn->getDeclContext()->getRedeclContext()->isFileContext()) - return false; - - // Signature must be void *operator new[](size_t, void*). - // The size_t is common to all operator new[]s. - if (Fn->getNumParams() != 2) - return false; - - CanQualType ParamType = Ctx.getCanonicalType(Fn->getParamDecl(1)->getType()); - return (ParamType == Ctx.VoidPtrTy); -} - static CharUnits CalculateCookiePadding(CodeGenFunction &CGF, const CXXNewExpr *E) { if (!E->isArray()) return CharUnits::Zero(); - // No cookie is required if the new operator being used is - // ::operator new[](size_t, void*). - const FunctionDecl *OperatorNew = E->getOperatorNew(); - if (IsPlacementOperatorNewArray(CGF.getContext(), OperatorNew)) + // No cookie is required if the operator new[] being used is the + // reserved placement operator new[]. + if (E->getOperatorNew()->isReservedGlobalPlacementOperator()) return CharUnits::Zero(); return CGF.CGM.getCXXABI().GetArrayCookieSize(E); } -static llvm::Value *EmitCXXNewAllocSize(ASTContext &Context, - CodeGenFunction &CGF, - const CXXNewExpr *E, - llvm::Value *&NumElements, - llvm::Value *&SizeWithoutCookie) { - QualType ElemType = E->getAllocatedType(); - - const llvm::IntegerType *SizeTy = - cast<llvm::IntegerType>(CGF.ConvertType(CGF.getContext().getSizeType())); - - CharUnits TypeSize = CGF.getContext().getTypeSizeInChars(ElemType); - - if (!E->isArray()) { - SizeWithoutCookie = llvm::ConstantInt::get(SizeTy, TypeSize.getQuantity()); - return SizeWithoutCookie; +static llvm::Value *EmitCXXNewAllocSize(CodeGenFunction &CGF, + const CXXNewExpr *e, + llvm::Value *&numElements, + llvm::Value *&sizeWithoutCookie) { + QualType type = e->getAllocatedType(); + + if (!e->isArray()) { + CharUnits typeSize = CGF.getContext().getTypeSizeInChars(type); + sizeWithoutCookie + = llvm::ConstantInt::get(CGF.SizeTy, typeSize.getQuantity()); + return sizeWithoutCookie; } + // The width of size_t. + unsigned sizeWidth = CGF.SizeTy->getBitWidth(); + // Figure out the cookie size. - CharUnits CookieSize = CalculateCookiePadding(CGF, E); + llvm::APInt cookieSize(sizeWidth, + CalculateCookiePadding(CGF, e).getQuantity()); // Emit the array size expression. // We multiply the size of all dimensions for NumElements. // e.g for 'int[2][3]', ElemType is 'int' and NumElements is 6. - NumElements = CGF.EmitScalarExpr(E->getArraySize()); - assert(NumElements->getType() == SizeTy && "element count not a size_t"); - - uint64_t ArraySizeMultiplier = 1; + numElements = CGF.EmitScalarExpr(e->getArraySize()); + assert(isa<llvm::IntegerType>(numElements->getType())); + + // The number of elements can be have an arbitrary integer type; + // essentially, we need to multiply it by a constant factor, add a + // cookie size, and verify that the result is representable as a + // size_t. That's just a gloss, though, and it's wrong in one + // important way: if the count is negative, it's an error even if + // the cookie size would bring the total size >= 0. + bool isSigned + = e->getArraySize()->getType()->isSignedIntegerOrEnumerationType(); + const llvm::IntegerType *numElementsType + = cast<llvm::IntegerType>(numElements->getType()); + unsigned numElementsWidth = numElementsType->getBitWidth(); + + // Compute the constant factor. + llvm::APInt arraySizeMultiplier(sizeWidth, 1); while (const ConstantArrayType *CAT - = CGF.getContext().getAsConstantArrayType(ElemType)) { - ElemType = CAT->getElementType(); - ArraySizeMultiplier *= CAT->getSize().getZExtValue(); + = CGF.getContext().getAsConstantArrayType(type)) { + type = CAT->getElementType(); + arraySizeMultiplier *= CAT->getSize(); } - llvm::Value *Size; + CharUnits typeSize = CGF.getContext().getTypeSizeInChars(type); + llvm::APInt typeSizeMultiplier(sizeWidth, typeSize.getQuantity()); + typeSizeMultiplier *= arraySizeMultiplier; + + // This will be a size_t. + llvm::Value *size; // If someone is doing 'new int[42]' there is no need to do a dynamic check. // Don't bloat the -O0 code. - if (llvm::ConstantInt *NumElementsC = - dyn_cast<llvm::ConstantInt>(NumElements)) { - llvm::APInt NEC = NumElementsC->getValue(); - unsigned SizeWidth = NEC.getBitWidth(); - - // Determine if there is an overflow here by doing an extended multiply. - NEC = NEC.zext(SizeWidth*2); - llvm::APInt SC(SizeWidth*2, TypeSize.getQuantity()); - SC *= NEC; - - if (!CookieSize.isZero()) { - // Save the current size without a cookie. We don't care if an - // overflow's already happened because SizeWithoutCookie isn't - // used if the allocator returns null or throws, as it should - // always do on an overflow. - llvm::APInt SWC = SC.trunc(SizeWidth); - SizeWithoutCookie = llvm::ConstantInt::get(SizeTy, SWC); - - // Add the cookie size. - SC += llvm::APInt(SizeWidth*2, CookieSize.getQuantity()); + if (llvm::ConstantInt *numElementsC = + dyn_cast<llvm::ConstantInt>(numElements)) { + const llvm::APInt &count = numElementsC->getValue(); + + bool hasAnyOverflow = false; + + // If 'count' was a negative number, it's an overflow. + if (isSigned && count.isNegative()) + hasAnyOverflow = true; + + // We want to do all this arithmetic in size_t. If numElements is + // wider than that, check whether it's already too big, and if so, + // overflow. + else if (numElementsWidth > sizeWidth && + numElementsWidth - sizeWidth > count.countLeadingZeros()) + hasAnyOverflow = true; + + // Okay, compute a count at the right width. + llvm::APInt adjustedCount = count.zextOrTrunc(sizeWidth); + + // Scale numElements by that. This might overflow, but we don't + // care because it only overflows if allocationSize does, too, and + // if that overflows then we shouldn't use this. + numElements = llvm::ConstantInt::get(CGF.SizeTy, + adjustedCount * arraySizeMultiplier); + + // Compute the size before cookie, and track whether it overflowed. + bool overflow; + llvm::APInt allocationSize + = adjustedCount.umul_ov(typeSizeMultiplier, overflow); + hasAnyOverflow |= overflow; + + // Add in the cookie, and check whether it's overflowed. + if (cookieSize != 0) { + // Save the current size without a cookie. This shouldn't be + // used if there was overflow. + sizeWithoutCookie = llvm::ConstantInt::get(CGF.SizeTy, allocationSize); + + allocationSize = allocationSize.uadd_ov(cookieSize, overflow); + hasAnyOverflow |= overflow; } - - if (SC.countLeadingZeros() >= SizeWidth) { - SC = SC.trunc(SizeWidth); - Size = llvm::ConstantInt::get(SizeTy, SC); + + // On overflow, produce a -1 so operator new will fail. + if (hasAnyOverflow) { + size = llvm::Constant::getAllOnesValue(CGF.SizeTy); } else { - // On overflow, produce a -1 so operator new throws. - Size = llvm::Constant::getAllOnesValue(SizeTy); + size = llvm::ConstantInt::get(CGF.SizeTy, allocationSize); } - // Scale NumElements while we're at it. - uint64_t N = NEC.getZExtValue() * ArraySizeMultiplier; - NumElements = llvm::ConstantInt::get(SizeTy, N); - - // Otherwise, we don't need to do an overflow-checked multiplication if - // we're multiplying by one. - } else if (TypeSize.isOne()) { - assert(ArraySizeMultiplier == 1); - - Size = NumElements; - - // If we need a cookie, add its size in with an overflow check. - // This is maybe a little paranoid. - if (!CookieSize.isZero()) { - SizeWithoutCookie = Size; + // Otherwise, we might need to use the overflow intrinsics. + } else { + // There are up to four conditions we need to test for: + // 1) if isSigned, we need to check whether numElements is negative; + // 2) if numElementsWidth > sizeWidth, we need to check whether + // numElements is larger than something representable in size_t; + // 3) we need to compute + // sizeWithoutCookie := numElements * typeSizeMultiplier + // and check whether it overflows; and + // 4) if we need a cookie, we need to compute + // size := sizeWithoutCookie + cookieSize + // and check whether it overflows. + + llvm::Value *hasOverflow = 0; + + // If numElementsWidth > sizeWidth, then one way or another, we're + // going to have to do a comparison for (2), and this happens to + // take care of (1), too. + if (numElementsWidth > sizeWidth) { + llvm::APInt threshold(numElementsWidth, 1); + threshold <<= sizeWidth; + + llvm::Value *thresholdV + = llvm::ConstantInt::get(numElementsType, threshold); + + hasOverflow = CGF.Builder.CreateICmpUGE(numElements, thresholdV); + numElements = CGF.Builder.CreateTrunc(numElements, CGF.SizeTy); + + // Otherwise, if we're signed, we want to sext up to size_t. + } else if (isSigned) { + if (numElementsWidth < sizeWidth) + numElements = CGF.Builder.CreateSExt(numElements, CGF.SizeTy); + + // If there's a non-1 type size multiplier, then we can do the + // signedness check at the same time as we do the multiply + // because a negative number times anything will cause an + // unsigned overflow. Otherwise, we have to do it here. + if (typeSizeMultiplier == 1) + hasOverflow = CGF.Builder.CreateICmpSLT(numElements, + llvm::ConstantInt::get(CGF.SizeTy, 0)); + + // Otherwise, zext up to size_t if necessary. + } else if (numElementsWidth < sizeWidth) { + numElements = CGF.Builder.CreateZExt(numElements, CGF.SizeTy); + } - llvm::Value *CookieSizeV - = llvm::ConstantInt::get(SizeTy, CookieSize.getQuantity()); + assert(numElements->getType() == CGF.SizeTy); - const llvm::Type *Types[] = { SizeTy }; - llvm::Value *UAddF - = CGF.CGM.getIntrinsic(llvm::Intrinsic::uadd_with_overflow, Types, 1); - llvm::Value *AddRes - = CGF.Builder.CreateCall2(UAddF, Size, CookieSizeV); + size = numElements; - Size = CGF.Builder.CreateExtractValue(AddRes, 0); - llvm::Value *DidOverflow = CGF.Builder.CreateExtractValue(AddRes, 1); - Size = CGF.Builder.CreateSelect(DidOverflow, - llvm::ConstantInt::get(SizeTy, -1), - Size); + // Multiply by the type size if necessary. This multiplier + // includes all the factors for nested arrays. + // + // This step also causes numElements to be scaled up by the + // nested-array factor if necessary. Overflow on this computation + // can be ignored because the result shouldn't be used if + // allocation fails. + if (typeSizeMultiplier != 1) { + const llvm::Type *intrinsicTypes[] = { CGF.SizeTy }; + llvm::Value *umul_with_overflow + = CGF.CGM.getIntrinsic(llvm::Intrinsic::umul_with_overflow, + intrinsicTypes, 1); + + llvm::Value *tsmV = + llvm::ConstantInt::get(CGF.SizeTy, typeSizeMultiplier); + llvm::Value *result = + CGF.Builder.CreateCall2(umul_with_overflow, size, tsmV); + + llvm::Value *overflowed = CGF.Builder.CreateExtractValue(result, 1); + if (hasOverflow) + hasOverflow = CGF.Builder.CreateOr(hasOverflow, overflowed); + else + hasOverflow = overflowed; + + size = CGF.Builder.CreateExtractValue(result, 0); + + // Also scale up numElements by the array size multiplier. + if (arraySizeMultiplier != 1) { + // If the base element type size is 1, then we can re-use the + // multiply we just did. + if (typeSize.isOne()) { + assert(arraySizeMultiplier == typeSizeMultiplier); + numElements = size; + + // Otherwise we need a separate multiply. + } else { + llvm::Value *asmV = + llvm::ConstantInt::get(CGF.SizeTy, arraySizeMultiplier); + numElements = CGF.Builder.CreateMul(numElements, asmV); + } + } + } else { + // numElements doesn't need to be scaled. + assert(arraySizeMultiplier == 1); } + + // Add in the cookie size if necessary. + if (cookieSize != 0) { + sizeWithoutCookie = size; + + const llvm::Type *intrinsicTypes[] = { CGF.SizeTy }; + llvm::Value *uadd_with_overflow + = CGF.CGM.getIntrinsic(llvm::Intrinsic::uadd_with_overflow, + intrinsicTypes, 1); + + llvm::Value *cookieSizeV = llvm::ConstantInt::get(CGF.SizeTy, cookieSize); + llvm::Value *result = + CGF.Builder.CreateCall2(uadd_with_overflow, size, cookieSizeV); + + llvm::Value *overflowed = CGF.Builder.CreateExtractValue(result, 1); + if (hasOverflow) + hasOverflow = CGF.Builder.CreateOr(hasOverflow, overflowed); + else + hasOverflow = overflowed; - // Otherwise use the int.umul.with.overflow intrinsic. - } else { - llvm::Value *OutermostElementSize - = llvm::ConstantInt::get(SizeTy, TypeSize.getQuantity()); - - llvm::Value *NumOutermostElements = NumElements; - - // Scale NumElements by the array size multiplier. This might - // overflow, but only if the multiplication below also overflows, - // in which case this multiplication isn't used. - if (ArraySizeMultiplier != 1) - NumElements = CGF.Builder.CreateMul(NumElements, - llvm::ConstantInt::get(SizeTy, ArraySizeMultiplier)); - - // The requested size of the outermost array is non-constant. - // Multiply that by the static size of the elements of that array; - // on unsigned overflow, set the size to -1 to trigger an - // exception from the allocation routine. This is sufficient to - // prevent buffer overruns from the allocator returning a - // seemingly valid pointer to insufficient space. This idea comes - // originally from MSVC, and GCC has an open bug requesting - // similar behavior: - // http://gcc.gnu.org/bugzilla/show_bug.cgi?id=19351 - // - // This will not be sufficient for C++0x, which requires a - // specific exception class (std::bad_array_new_length). - // That will require ABI support that has not yet been specified. - const llvm::Type *Types[] = { SizeTy }; - llvm::Value *UMulF - = CGF.CGM.getIntrinsic(llvm::Intrinsic::umul_with_overflow, Types, 1); - llvm::Value *MulRes = CGF.Builder.CreateCall2(UMulF, NumOutermostElements, - OutermostElementSize); - - // The overflow bit. - llvm::Value *DidOverflow = CGF.Builder.CreateExtractValue(MulRes, 1); - - // The result of the multiplication. - Size = CGF.Builder.CreateExtractValue(MulRes, 0); - - // If we have a cookie, we need to add that size in, too. - if (!CookieSize.isZero()) { - SizeWithoutCookie = Size; - - llvm::Value *CookieSizeV - = llvm::ConstantInt::get(SizeTy, CookieSize.getQuantity()); - llvm::Value *UAddF - = CGF.CGM.getIntrinsic(llvm::Intrinsic::uadd_with_overflow, Types, 1); - llvm::Value *AddRes - = CGF.Builder.CreateCall2(UAddF, SizeWithoutCookie, CookieSizeV); - - Size = CGF.Builder.CreateExtractValue(AddRes, 0); - - llvm::Value *AddDidOverflow = CGF.Builder.CreateExtractValue(AddRes, 1); - DidOverflow = CGF.Builder.CreateOr(DidOverflow, AddDidOverflow); + size = CGF.Builder.CreateExtractValue(result, 0); } - Size = CGF.Builder.CreateSelect(DidOverflow, - llvm::ConstantInt::get(SizeTy, -1), - Size); + // If we had any possibility of dynamic overflow, make a select to + // overwrite 'size' with an all-ones value, which should cause + // operator new to throw. + if (hasOverflow) + size = CGF.Builder.CreateSelect(hasOverflow, + llvm::Constant::getAllOnesValue(CGF.SizeTy), + size); } - if (CookieSize.isZero()) - SizeWithoutCookie = Size; + if (cookieSize == 0) + sizeWithoutCookie = size; else - assert(SizeWithoutCookie && "didn't set SizeWithoutCookie?"); + assert(sizeWithoutCookie && "didn't set sizeWithoutCookie?"); - return Size; + return size; } static void StoreAnyExprIntoOneUnit(CodeGenFunction &CGF, const CXXNewExpr *E, @@ -741,7 +790,7 @@ static void EmitNewInitializer(CodeGenFunction &CGF, const CXXNewExpr *E, if (E->isArray()) { if (CXXConstructorDecl *Ctor = E->getConstructor()) { bool RequiresZeroInitialization = false; - if (Ctor->getParent()->hasTrivialConstructor()) { + if (Ctor->getParent()->hasTrivialDefaultConstructor()) { // If new expression did not specify value-initialization, then there // is no initialization. if (!E->hasInitializer() || Ctor->getParent()->isEmpty()) @@ -972,8 +1021,7 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) { llvm::Value *numElements = 0; llvm::Value *allocSizeWithoutCookie = 0; llvm::Value *allocSize = - EmitCXXNewAllocSize(getContext(), *this, E, numElements, - allocSizeWithoutCookie); + EmitCXXNewAllocSize(*this, E, numElements, allocSizeWithoutCookie); allocatorArgs.add(RValue::get(allocSize), sizeType); @@ -1007,11 +1055,19 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) { EmitCallArg(allocatorArgs, *placementArg, placementArg->getType()); } - // Emit the allocation call. - RValue RV = - EmitCall(CGM.getTypes().getFunctionInfo(allocatorArgs, allocatorType), - CGM.GetAddrOfFunction(allocator), ReturnValueSlot(), - allocatorArgs, allocator); + // Emit the allocation call. If the allocator is a global placement + // operator, just "inline" it directly. + RValue RV; + if (allocator->isReservedGlobalPlacementOperator()) { + assert(allocatorArgs.size() == 2); + RV = allocatorArgs[1].RV; + // TODO: kill any unnecessary computations done for the size + // argument. + } else { + RV = EmitCall(CGM.getTypes().getFunctionInfo(allocatorArgs, allocatorType), + CGM.GetAddrOfFunction(allocator), ReturnValueSlot(), + allocatorArgs, allocator); + } // Emit a null check on the allocation result if the allocation // function is allowed to return null (because it has a non-throwing @@ -1056,7 +1112,8 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) { // If there's an operator delete, enter a cleanup to call it if an // exception is thrown. EHScopeStack::stable_iterator operatorDeleteCleanup; - if (E->getOperatorDelete()) { + if (E->getOperatorDelete() && + !E->getOperatorDelete()->isReservedGlobalPlacementOperator()) { EnterNewDeleteCleanup(*this, E, allocation, allocSize, allocatorArgs); operatorDeleteCleanup = EHStack.stable_begin(); } diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGExprConstant.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGExprConstant.cpp index 463b913..da37bd5 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGExprConstant.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGExprConstant.cpp @@ -352,8 +352,7 @@ bool ConstStructBuilder::Build(InitListExpr *ILE) { if (IsMsStruct) { // Zero-length bitfields following non-bitfield members are // ignored: - if (CGM.getContext().ZeroBitfieldFollowsNonBitfield((*Field), LastFD) || - CGM.getContext().ZeroBitfieldFollowsBitfield((*Field), LastFD)) { + if (CGM.getContext().ZeroBitfieldFollowsNonBitfield((*Field), LastFD)) { --FieldNo; continue; } @@ -611,12 +610,12 @@ public: return llvm::ConstantPointerNull::get(cast<llvm::PointerType>(destType)); case CK_IntegralCast: { - bool isSigned = subExpr->getType()->isSignedIntegerType(); + bool isSigned = subExpr->getType()->isSignedIntegerOrEnumerationType(); return llvm::ConstantExpr::getIntegerCast(C, destType, isSigned); } case CK_IntegralToPointer: { - bool isSigned = subExpr->getType()->isSignedIntegerType(); + bool isSigned = subExpr->getType()->isSignedIntegerOrEnumerationType(); C = llvm::ConstantExpr::getIntegerCast(C, CGM.IntPtrTy, isSigned); return llvm::ConstantExpr::getIntToPtr(C, destType); } @@ -626,13 +625,13 @@ public: llvm::Constant::getNullValue(C->getType())); case CK_IntegralToFloating: - if (subExpr->getType()->isSignedIntegerType()) + if (subExpr->getType()->isSignedIntegerOrEnumerationType()) return llvm::ConstantExpr::getSIToFP(C, destType); else return llvm::ConstantExpr::getUIToFP(C, destType); case CK_FloatingToIntegral: - if (E->getType()->isSignedIntegerType()) + if (E->getType()->isSignedIntegerOrEnumerationType()) return llvm::ConstantExpr::getFPToSI(C, destType); else return llvm::ConstantExpr::getFPToUI(C, destType); diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGExprScalar.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGExprScalar.cpp index 6bcc425..dff7bf4 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGExprScalar.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGExprScalar.cpp @@ -400,7 +400,7 @@ public: // Binary Operators. Value *EmitMul(const BinOpInfo &Ops) { - if (Ops.Ty->hasSignedIntegerRepresentation()) { + if (Ops.Ty->isSignedIntegerOrEnumerationType()) { switch (CGF.getContext().getLangOptions().getSignedOverflowBehavior()) { case LangOptions::SOB_Undefined: return Builder.CreateNSWMul(Ops.LHS, Ops.RHS, "mul"); @@ -508,6 +508,7 @@ public: Value *VisitObjCStringLiteral(const ObjCStringLiteral *E) { return CGF.EmitObjCStringLiteral(E); } + Value *VisitAsTypeExpr(AsTypeExpr *CE); }; } // end anonymous namespace. @@ -568,7 +569,7 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType, // First, convert to the correct width so that we control the kind of // extension. const llvm::Type *MiddleTy = CGF.IntPtrTy; - bool InputSigned = SrcType->isSignedIntegerType(); + bool InputSigned = SrcType->isSignedIntegerOrEnumerationType(); llvm::Value* IntResult = Builder.CreateIntCast(Src, MiddleTy, InputSigned, "conv"); // Then, cast to pointer. @@ -610,7 +611,7 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType, // Finally, we have the arithmetic types: real int/float. if (isa<llvm::IntegerType>(Src->getType())) { - bool InputSigned = SrcType->isSignedIntegerType(); + bool InputSigned = SrcType->isSignedIntegerOrEnumerationType(); if (isa<llvm::IntegerType>(DstTy)) return Builder.CreateIntCast(Src, DstTy, InputSigned, "conv"); else if (InputSigned) @@ -621,7 +622,7 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType, assert(Src->getType()->isFloatingPointTy() && "Unknown real conversion"); if (isa<llvm::IntegerType>(DstTy)) { - if (DstType->isSignedIntegerType()) + if (DstType->isSignedIntegerOrEnumerationType()) return Builder.CreateFPToSI(Src, DstTy, "conv"); else return Builder.CreateFPToUI(Src, DstTy, "conv"); @@ -758,19 +759,13 @@ Value *ScalarExprEmitter::VisitShuffleVectorExpr(ShuffleVectorExpr *E) { Value* V2 = CGF.EmitScalarExpr(E->getExpr(1)); // Handle vec3 special since the index will be off by one for the RHS. + const llvm::VectorType *VTy = cast<llvm::VectorType>(V1->getType()); llvm::SmallVector<llvm::Constant*, 32> indices; for (unsigned i = 2; i < E->getNumSubExprs(); i++) { - llvm::Constant *C = cast<llvm::Constant>(CGF.EmitScalarExpr(E->getExpr(i))); - const llvm::VectorType *VTy = cast<llvm::VectorType>(V1->getType()); - if (VTy->getNumElements() == 3) { - if (llvm::ConstantInt *CI = dyn_cast<llvm::ConstantInt>(C)) { - uint64_t cVal = CI->getZExtValue(); - if (cVal > 3) { - C = llvm::ConstantInt::get(C->getType(), cVal-1); - } - } - } - indices.push_back(C); + unsigned Idx = E->getShuffleMaskIdx(CGF.getContext(), i-2); + if (VTy->getNumElements() == 3 && Idx > 3) + Idx -= 1; + indices.push_back(Builder.getInt32(Idx)); } Value *SV = llvm::ConstantVector::get(indices); @@ -813,7 +808,7 @@ Value *ScalarExprEmitter::VisitArraySubscriptExpr(ArraySubscriptExpr *E) { // integer value. Value *Base = Visit(E->getBase()); Value *Idx = Visit(E->getIdx()); - bool IdxSigned = E->getIdx()->getType()->isSignedIntegerType(); + bool IdxSigned = E->getIdx()->getType()->isSignedIntegerOrEnumerationType(); Idx = Builder.CreateIntCast(Idx, CGF.Int32Ty, IdxSigned, "vecidxcast"); return Builder.CreateExtractElement(Base, Idx, "vecext"); } @@ -1142,7 +1137,7 @@ Value *ScalarExprEmitter::EmitCastExpr(CastExpr *CE) { // First, convert to the correct width so that we control the kind of // extension. const llvm::Type *MiddleTy = CGF.IntPtrTy; - bool InputSigned = E->getType()->isSignedIntegerType(); + bool InputSigned = E->getType()->isSignedIntegerOrEnumerationType(); llvm::Value* IntResult = Builder.CreateIntCast(Src, MiddleTy, InputSigned, "conv"); @@ -1285,7 +1280,7 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV, // Note that signed integer inc/dec with width less than int can't // overflow because of promotion rules; we're just eliding a few steps here. - if (type->isSignedIntegerType() && + if (type->isSignedIntegerOrEnumerationType() && value->getType()->getPrimitiveSizeInBits() >= CGF.CGM.IntTy->getBitWidth()) value = EmitAddConsiderOverflowBehavior(E, value, amt, isInc); @@ -1333,10 +1328,7 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV, if (type->hasIntegerRepresentation()) { llvm::Value *amt = llvm::ConstantInt::get(value->getType(), amount); - if (type->hasSignedIntegerRepresentation()) - value = EmitAddConsiderOverflowBehavior(E, value, amt, isInc); - else - value = Builder.CreateAdd(value, amt, isInc ? "inc" : "dec"); + value = Builder.CreateAdd(value, amt, isInc ? "inc" : "dec"); } else { value = Builder.CreateFAdd( value, @@ -1447,7 +1439,7 @@ Value *ScalarExprEmitter::VisitOffsetOfExpr(OffsetOfExpr *E) { // Compute the index Expr *IdxExpr = E->getIndexExpr(ON.getArrayExprIndex()); llvm::Value* Idx = CGF.EmitScalarExpr(IdxExpr); - bool IdxSigned = IdxExpr->getType()->isSignedIntegerType(); + bool IdxSigned = IdxExpr->getType()->isSignedIntegerOrEnumerationType(); Idx = Builder.CreateIntCast(Idx, ResultType, IdxSigned, "conv"); // Save the element type @@ -1797,9 +1789,7 @@ Value *ScalarExprEmitter::EmitOverflowCheckedBinOp(const BinOpInfo &Ops) { // Get the overflow handler. const llvm::Type *Int8Ty = llvm::Type::getInt8Ty(VMContext); - std::vector<const llvm::Type*> argTypes; - argTypes.push_back(CGF.Int64Ty); argTypes.push_back(CGF.Int64Ty); - argTypes.push_back(Int8Ty); argTypes.push_back(Int8Ty); + const llvm::Type *argTypes[] = { CGF.Int64Ty, CGF.Int64Ty, Int8Ty, Int8Ty }; llvm::FunctionType *handlerTy = llvm::FunctionType::get(CGF.Int64Ty, argTypes, true); llvm::Value *handler = CGF.CGM.CreateRuntimeFunction(handlerTy, *handlerName); @@ -1829,7 +1819,7 @@ Value *ScalarExprEmitter::EmitOverflowCheckedBinOp(const BinOpInfo &Ops) { Value *ScalarExprEmitter::EmitAdd(const BinOpInfo &Ops) { if (!Ops.Ty->isAnyPointerType()) { - if (Ops.Ty->hasSignedIntegerRepresentation()) { + if (Ops.Ty->isSignedIntegerOrEnumerationType()) { switch (CGF.getContext().getLangOptions().getSignedOverflowBehavior()) { case LangOptions::SOB_Undefined: return Builder.CreateNSWAdd(Ops.LHS, Ops.RHS, "add"); @@ -1879,7 +1869,7 @@ Value *ScalarExprEmitter::EmitAdd(const BinOpInfo &Ops) { // Zero or sign extend the pointer value based on whether the index is // signed or not. const llvm::Type *IdxType = CGF.IntPtrTy; - if (IdxExp->getType()->isSignedIntegerType()) + if (IdxExp->getType()->isSignedIntegerOrEnumerationType()) Idx = Builder.CreateSExt(Idx, IdxType, "idx.ext"); else Idx = Builder.CreateZExt(Idx, IdxType, "idx.ext"); @@ -1914,7 +1904,7 @@ Value *ScalarExprEmitter::EmitAdd(const BinOpInfo &Ops) { Value *ScalarExprEmitter::EmitSub(const BinOpInfo &Ops) { if (!isa<llvm::PointerType>(Ops.LHS->getType())) { - if (Ops.Ty->hasSignedIntegerRepresentation()) { + if (Ops.Ty->isSignedIntegerOrEnumerationType()) { switch (CGF.getContext().getLangOptions().getSignedOverflowBehavior()) { case LangOptions::SOB_Undefined: return Builder.CreateNSWSub(Ops.LHS, Ops.RHS, "sub"); @@ -1954,7 +1944,7 @@ Value *ScalarExprEmitter::EmitSub(const BinOpInfo &Ops) { // Zero or sign extend the pointer value based on whether the index is // signed or not. const llvm::Type *IdxType = CGF.IntPtrTy; - if (BinOp->getRHS()->getType()->isSignedIntegerType()) + if (BinOp->getRHS()->getType()->isSignedIntegerOrEnumerationType()) Idx = Builder.CreateSExt(Idx, IdxType, "idx.ext"); else Idx = Builder.CreateZExt(Idx, IdxType, "idx.ext"); @@ -2556,6 +2546,56 @@ Value *ScalarExprEmitter::VisitBlockExpr(const BlockExpr *block) { return CGF.EmitBlockLiteral(block); } +Value *ScalarExprEmitter::VisitAsTypeExpr(AsTypeExpr *E) { + Value *Src = CGF.EmitScalarExpr(E->getSrcExpr()); + const llvm::Type * DstTy = ConvertType(E->getDstType()); + + // Going from vec4->vec3 or vec3->vec4 is a special case and requires + // a shuffle vector instead of a bitcast. + const llvm::Type *SrcTy = Src->getType(); + if (isa<llvm::VectorType>(DstTy) && isa<llvm::VectorType>(SrcTy)) { + unsigned numElementsDst = cast<llvm::VectorType>(DstTy)->getNumElements(); + unsigned numElementsSrc = cast<llvm::VectorType>(SrcTy)->getNumElements(); + if ((numElementsDst == 3 && numElementsSrc == 4) + || (numElementsDst == 4 && numElementsSrc == 3)) { + + + // In the case of going from int4->float3, a bitcast is needed before + // doing a shuffle. + const llvm::Type *srcElemTy = + cast<llvm::VectorType>(SrcTy)->getElementType(); + const llvm::Type *dstElemTy = + cast<llvm::VectorType>(DstTy)->getElementType(); + + if ((srcElemTy->isIntegerTy() && dstElemTy->isFloatTy()) + || (srcElemTy->isFloatTy() && dstElemTy->isIntegerTy())) { + // Create a float type of the same size as the source or destination. + const llvm::VectorType *newSrcTy = llvm::VectorType::get(dstElemTy, + numElementsSrc); + + Src = Builder.CreateBitCast(Src, newSrcTy, "astypeCast"); + } + + llvm::Value *UnV = llvm::UndefValue::get(Src->getType()); + + llvm::SmallVector<llvm::Constant*, 3> Args; + Args.push_back(Builder.getInt32(0)); + Args.push_back(Builder.getInt32(1)); + Args.push_back(Builder.getInt32(2)); + + if (numElementsDst == 4) + Args.push_back(llvm::UndefValue::get( + llvm::Type::getInt32Ty(CGF.getLLVMContext()))); + + llvm::Constant *Mask = llvm::ConstantVector::get(Args); + + return Builder.CreateShuffleVector(Src, UnV, Mask, "astype"); + } + } + + return Builder.CreateBitCast(Src, DstTy, "astype"); +} + //===----------------------------------------------------------------------===// // Entry Point into this File //===----------------------------------------------------------------------===// diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGObjC.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGObjC.cpp index 5b0d41e..fa42cd1 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGObjC.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGObjC.cpp @@ -47,6 +47,23 @@ llvm::Value *CodeGenFunction::EmitObjCProtocolExpr(const ObjCProtocolExpr *E) { return CGM.getObjCRuntime().GenerateProtocolRef(Builder, E->getProtocol()); } +/// \brief Adjust the type of the result of an Objective-C message send +/// expression when the method has a related result type. +static RValue AdjustRelatedResultType(CodeGenFunction &CGF, + const Expr *E, + const ObjCMethodDecl *Method, + RValue Result) { + if (!Method) + return Result; + if (!Method->hasRelatedResultType() || + CGF.getContext().hasSameType(E->getType(), Method->getResultType()) || + !Result.isScalar()) + return Result; + + // We have applied a related result type. Cast the rvalue appropriately. + return RValue::get(CGF.Builder.CreateBitCast(Result.getScalarVal(), + CGF.ConvertType(E->getType()))); +} RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E, ReturnValueSlot Return) { @@ -59,15 +76,17 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E, bool isClassMessage = false; ObjCInterfaceDecl *OID = 0; // Find the receiver + QualType ReceiverType; llvm::Value *Receiver = 0; switch (E->getReceiverKind()) { case ObjCMessageExpr::Instance: Receiver = EmitScalarExpr(E->getInstanceReceiver()); + ReceiverType = E->getInstanceReceiver()->getType(); break; case ObjCMessageExpr::Class: { - const ObjCObjectType *ObjTy - = E->getClassReceiver()->getAs<ObjCObjectType>(); + ReceiverType = E->getClassReceiver(); + const ObjCObjectType *ObjTy = ReceiverType->getAs<ObjCObjectType>(); assert(ObjTy && "Invalid Objective-C class message send"); OID = ObjTy->getInterface(); assert(OID && "Invalid Objective-C class message send"); @@ -77,11 +96,13 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E, } case ObjCMessageExpr::SuperInstance: + ReceiverType = E->getSuperType(); Receiver = LoadObjCSelf(); isSuperMessage = true; break; case ObjCMessageExpr::SuperClass: + ReceiverType = E->getSuperType(); Receiver = LoadObjCSelf(); isSuperMessage = true; isClassMessage = true; @@ -94,31 +115,35 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E, QualType ResultType = E->getMethodDecl() ? E->getMethodDecl()->getResultType() : E->getType(); + RValue result; if (isSuperMessage) { // super is only valid in an Objective-C method const ObjCMethodDecl *OMD = cast<ObjCMethodDecl>(CurFuncDecl); bool isCategoryImpl = isa<ObjCCategoryImplDecl>(OMD->getDeclContext()); - return Runtime.GenerateMessageSendSuper(*this, Return, ResultType, - E->getSelector(), - OMD->getClassInterface(), - isCategoryImpl, - Receiver, - isClassMessage, - Args, - E->getMethodDecl()); + result = Runtime.GenerateMessageSendSuper(*this, Return, ResultType, + E->getSelector(), + OMD->getClassInterface(), + isCategoryImpl, + Receiver, + isClassMessage, + Args, + E->getMethodDecl()); + } else { + result = Runtime.GenerateMessageSend(*this, Return, ResultType, + E->getSelector(), + Receiver, Args, OID, + E->getMethodDecl()); } - - return Runtime.GenerateMessageSend(*this, Return, ResultType, - E->getSelector(), - Receiver, Args, OID, - E->getMethodDecl()); + + return AdjustRelatedResultType(*this, E, E->getMethodDecl(), result); } /// StartObjCMethod - Begin emission of an ObjCMethod. This generates /// the LLVM function and sets the other context used by /// CodeGenFunction. void CodeGenFunction::StartObjCMethod(const ObjCMethodDecl *OMD, - const ObjCContainerDecl *CD) { + const ObjCContainerDecl *CD, + SourceLocation StartLoc) { FunctionArgList args; // Check if we should generate debug info for this method. if (CGM.getModuleDebugInfo() && !OMD->hasAttr<NoDebugAttr>()) @@ -138,7 +163,7 @@ void CodeGenFunction::StartObjCMethod(const ObjCMethodDecl *OMD, CurGD = OMD; - StartFunction(OMD, OMD->getResultType(), Fn, FI, args, OMD->getLocStart()); + StartFunction(OMD, OMD->getResultType(), Fn, FI, args, StartLoc); } void CodeGenFunction::GenerateObjCGetterBody(ObjCIvarDecl *Ivar, @@ -151,16 +176,14 @@ void CodeGenFunction::GenerateObjCGetterBody(ObjCIvarDecl *Ivar, // objc_copyStruct (ReturnValue, &structIvar, // sizeof (Type of Ivar), isAtomic, false); CallArgList Args; - RValue RV = RValue::get(Builder.CreateBitCast(ReturnValue, - Types.ConvertType(getContext().VoidPtrTy))); + RValue RV = RValue::get(Builder.CreateBitCast(ReturnValue, VoidPtrTy)); Args.add(RV, getContext().VoidPtrTy); - RV = RValue::get(Builder.CreateBitCast(LV.getAddress(), - Types.ConvertType(getContext().VoidPtrTy))); + RV = RValue::get(Builder.CreateBitCast(LV.getAddress(), VoidPtrTy)); Args.add(RV, getContext().VoidPtrTy); // sizeof (Type of Ivar) CharUnits Size = getContext().getTypeSizeInChars(Ivar->getType()); llvm::Value *SizeVal = - llvm::ConstantInt::get(Types.ConvertType(getContext().LongTy), + llvm::ConstantInt::get(Types.ConvertType(getContext().LongTy), Size.getQuantity()); Args.add(RValue::get(SizeVal), getContext().LongTy); llvm::Value *isAtomic = @@ -179,7 +202,7 @@ void CodeGenFunction::GenerateObjCGetterBody(ObjCIvarDecl *Ivar, /// Generate an Objective-C method. An Objective-C method is a C function with /// its pointer, name, and types registered in the class struture. void CodeGenFunction::GenerateObjCMethod(const ObjCMethodDecl *OMD) { - StartObjCMethod(OMD, OMD->getClassInterface()); + StartObjCMethod(OMD, OMD->getClassInterface(), OMD->getLocStart()); EmitStmt(OMD->getBody()); FinishFunction(OMD->getBodyRBrace()); } @@ -199,7 +222,7 @@ void CodeGenFunction::GenerateObjCGetter(ObjCImplementationDecl *IMP, !(PD->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_nonatomic); ObjCMethodDecl *OMD = PD->getGetterMethodDecl(); assert(OMD && "Invalid call to generate getter (empty method)"); - StartObjCMethod(OMD, IMP->getClassInterface()); + StartObjCMethod(OMD, IMP->getClassInterface(), PID->getLocStart()); // Determine if we should use an objc_getProperty call for // this. Non-atomic properties are directly evaluated. @@ -292,7 +315,7 @@ void CodeGenFunction::GenerateObjCGetter(ObjCImplementationDecl *IMP, const CXXRecordDecl *classDecl = IVART->getAsCXXRecordDecl(); if (PID->getGetterCXXConstructor() && - classDecl && !classDecl->hasTrivialConstructor()) { + classDecl && !classDecl->hasTrivialDefaultConstructor()) { ReturnStmt *Stmt = new (getContext()) ReturnStmt(SourceLocation(), PID->getGetterCXXConstructor(), @@ -398,7 +421,7 @@ void CodeGenFunction::GenerateObjCSetter(ObjCImplementationDecl *IMP, const ObjCPropertyDecl *PD = PID->getPropertyDecl(); ObjCMethodDecl *OMD = PD->getSetterMethodDecl(); assert(OMD && "Invalid call to generate setter (empty method)"); - StartObjCMethod(OMD, IMP->getClassInterface()); + StartObjCMethod(OMD, IMP->getClassInterface(), PID->getLocStart()); const llvm::Triple &Triple = getContext().Target.getTriple(); QualType IVART = Ivar->getType(); bool IsCopy = PD->getSetterKind() == ObjCPropertyDecl::Copy; @@ -496,7 +519,7 @@ void CodeGenFunction::GenerateObjCSetter(ObjCImplementationDecl *IMP, } else { // FIXME: Find a clean way to avoid AST node creation. - SourceLocation Loc = PD->getLocation(); + SourceLocation Loc = PID->getLocStart(); ValueDecl *Self = OMD->getSelfDecl(); ObjCIvarDecl *Ivar = PID->getPropertyIvarDecl(); DeclRefExpr Base(Self, Self->getType(), VK_RValue, Loc); @@ -618,7 +641,7 @@ void CodeGenFunction::GenerateObjCCtorDtorMethod(ObjCImplementationDecl *IMP, ObjCMethodDecl *MD, bool ctor) { MD->createImplicitParams(CGM.getContext(), IMP->getClassInterface()); - StartObjCMethod(MD, IMP->getClassInterface()); + StartObjCMethod(MD, IMP->getClassInterface(), MD->getLocStart()); // Emit .cxx_construct. if (ctor) { @@ -712,26 +735,31 @@ RValue CodeGenFunction::EmitLoadOfPropertyRefLValue(LValue LV, const ObjCPropertyRefExpr *E = LV.getPropertyRefExpr(); QualType ResultType = E->getGetterResultType(); Selector S; + const ObjCMethodDecl *method; if (E->isExplicitProperty()) { const ObjCPropertyDecl *Property = E->getExplicitProperty(); S = Property->getGetterName(); + method = Property->getGetterMethodDecl(); } else { - const ObjCMethodDecl *Getter = E->getImplicitPropertyGetter(); - S = Getter->getSelector(); + method = E->getImplicitPropertyGetter(); + S = method->getSelector(); } llvm::Value *Receiver = LV.getPropertyRefBaseAddr(); // Accesses to 'super' follow a different code path. if (E->isSuperReceiver()) - return GenerateMessageSendSuper(*this, Return, ResultType, - S, Receiver, CallArgList()); - + return AdjustRelatedResultType(*this, E, method, + GenerateMessageSendSuper(*this, Return, + ResultType, + S, Receiver, + CallArgList())); const ObjCInterfaceDecl *ReceiverClass = (E->isClassReceiver() ? E->getClassReceiver() : 0); - return CGM.getObjCRuntime(). - GenerateMessageSend(*this, Return, ResultType, S, - Receiver, CallArgList(), ReceiverClass); + return AdjustRelatedResultType(*this, E, method, + CGM.getObjCRuntime(). + GenerateMessageSend(*this, Return, ResultType, S, + Receiver, CallArgList(), ReceiverClass)); } void CodeGenFunction::EmitStoreThroughPropertyRefLValue(RValue Src, diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGObjCGNU.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGObjCGNU.cpp index c4dc4c4..f0993c5 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGObjCGNU.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGObjCGNU.cpp @@ -52,7 +52,7 @@ class LazyRuntimeFunction { CodeGenModule *CGM; std::vector<const llvm::Type*> ArgTys; const char *FunctionName; - llvm::Function *Function; + llvm::Constant *Function; public: /// Constructor leaves this class uninitialized, because it is intended to /// be used as a field in another class and not all of the types that are @@ -78,7 +78,7 @@ class LazyRuntimeFunction { } /// Overloaded cast operator, allows the class to be implicitly cast to an /// LLVM constant. - operator llvm::Function*() { + operator llvm::Constant*() { if (!Function) { if (0 == FunctionName) return 0; // We put the return type on the end of the vector, so pop it back off @@ -86,13 +86,17 @@ class LazyRuntimeFunction { ArgTys.pop_back(); llvm::FunctionType *FTy = llvm::FunctionType::get(RetTy, ArgTys, false); Function = - cast<llvm::Function>(CGM->CreateRuntimeFunction(FTy, FunctionName)); + cast<llvm::Constant>(CGM->CreateRuntimeFunction(FTy, FunctionName)); // We won't need to use the types again, so we may as well clean up the // vector now ArgTys.resize(0); } return Function; } + operator llvm::Function*() { + return cast<llvm::Function>((llvm::Constant*)*this); + } + }; @@ -314,7 +318,7 @@ private: /// The version of the runtime that this class targets. Must match the /// version in the runtime. - const int RuntimeVersion; + int RuntimeVersion; /// The version of the protocol class. Used to differentiate between ObjC1 /// and ObjC2 protocols. Objective-C 1 protocols can not contain optional /// components and can not contain declared properties. We always emit @@ -444,10 +448,10 @@ public: const ObjCProtocolDecl *PD); virtual void GenerateProtocol(const ObjCProtocolDecl *PD); virtual llvm::Function *ModuleInitFunction(); - virtual llvm::Function *GetPropertyGetFunction(); - virtual llvm::Function *GetPropertySetFunction(); - virtual llvm::Function *GetSetStructFunction(); - virtual llvm::Function *GetGetStructFunction(); + virtual llvm::Constant *GetPropertyGetFunction(); + virtual llvm::Constant *GetPropertySetFunction(); + virtual llvm::Constant *GetSetStructFunction(); + virtual llvm::Constant *GetGetStructFunction(); virtual llvm::Constant *EnumerationMutationFunction(); virtual void EmitTryStmt(CodeGenFunction &CGF, @@ -484,6 +488,10 @@ public: const CGBlockInfo &blockInfo) { return NULLPtr; } + + virtual llvm::GlobalVariable *GetClassGlobal(const std::string &Name) { + return 0; + } }; /// Class representing the legacy GCC Objective-C ABI. This is the default when /// -fobjc-nonfragile-abi is not specified. @@ -654,7 +662,6 @@ CGObjCGNU::CGObjCGNU(CodeGenModule &cgm, unsigned runtimeABIVersion, : CGM(cgm), TheModule(CGM.getModule()), VMContext(cgm.getLLVMContext()), ClassPtrAlias(0), MetaClassPtrAlias(0), RuntimeVersion(runtimeABIVersion), ProtocolVersion(protocolClassVersion) { - msgSendMDKind = VMContext.getMDKindID("GNUObjCMessageSend"); @@ -729,14 +736,16 @@ CGObjCGNU::CGObjCGNU(CodeGenModule &cgm, unsigned runtimeABIVersion, PtrDiffTy, BoolTy, BoolTy, NULL); // IMP type - std::vector<const llvm::Type*> IMPArgs; - IMPArgs.push_back(IdTy); - IMPArgs.push_back(SelectorTy); + const llvm::Type *IMPArgs[] = { IdTy, SelectorTy }; IMPTy = llvm::PointerType::getUnqual(llvm::FunctionType::get(IdTy, IMPArgs, true)); // Don't bother initialising the GC stuff unless we're compiling in GC mode if (CGM.getLangOptions().getGCMode() != LangOptions::NonGC) { + // This is a bit of an hack. We should sort this out by having a proper + // CGObjCGNUstep subclass for GC, but we may want to really support the old + // ABI and GC added in ObjectiveC2.framework, so we fudge it a bit for now + RuntimeVersion = 10; // Get selectors needed in GC mode RetainSel = GetNullarySelector("retain", CGM.getContext()); ReleaseSel = GetNullarySelector("release", CGM.getContext()); @@ -775,11 +784,8 @@ llvm::Value *CGObjCGNU::GetClass(CGBuilderTy &Builder, EmitClassRef(OID->getNameAsString()); ClassName = Builder.CreateStructGEP(ClassName, 0); - std::vector<const llvm::Type*> Params(1, PtrToInt8Ty); llvm::Constant *ClassLookupFn = - CGM.CreateRuntimeFunction(llvm::FunctionType::get(IdTy, - Params, - true), + CGM.CreateRuntimeFunction(llvm::FunctionType::get(IdTy, PtrToInt8Ty, true), "objc_lookup_class"); return Builder.CreateCall(ClassLookupFn, ClassName); } @@ -945,16 +951,17 @@ CGObjCGNU::GenerateMessageSendSuper(CodeGenFunction &CGF, bool IsClassMessage, const CallArgList &CallArgs, const ObjCMethodDecl *Method) { - if (CGM.getLangOptions().getGCMode() != LangOptions::NonGC) { + CGBuilderTy &Builder = CGF.Builder; + if (CGM.getLangOptions().getGCMode() == LangOptions::GCOnly) { if (Sel == RetainSel || Sel == AutoreleaseSel) { - return RValue::get(Receiver); + return RValue::get(EnforceType(Builder, Receiver, + CGM.getTypes().ConvertType(ResultType))); } if (Sel == ReleaseSel) { return RValue::get(0); } } - CGBuilderTy &Builder = CGF.Builder; llvm::Value *cmd = GetSelector(Builder, Sel); @@ -971,14 +978,12 @@ CGObjCGNU::GenerateMessageSendSuper(CodeGenFunction &CGF, llvm::Value *ReceiverClass = 0; if (isCategoryImpl) { llvm::Constant *classLookupFunction = 0; - std::vector<const llvm::Type*> Params; - Params.push_back(PtrTy); if (IsClassMessage) { classLookupFunction = CGM.CreateRuntimeFunction(llvm::FunctionType::get( - IdTy, Params, true), "objc_get_meta_class"); + IdTy, PtrTy, true), "objc_get_meta_class"); } else { classLookupFunction = CGM.CreateRuntimeFunction(llvm::FunctionType::get( - IdTy, Params, true), "objc_get_class"); + IdTy, PtrTy, true), "objc_get_class"); } ReceiverClass = Builder.CreateCall(classLookupFunction, MakeConstantString(Class->getNameAsString())); @@ -1052,18 +1057,19 @@ CGObjCGNU::GenerateMessageSend(CodeGenFunction &CGF, const CallArgList &CallArgs, const ObjCInterfaceDecl *Class, const ObjCMethodDecl *Method) { + CGBuilderTy &Builder = CGF.Builder; + // Strip out message sends to retain / release in GC mode - if (CGM.getLangOptions().getGCMode() != LangOptions::NonGC) { + if (CGM.getLangOptions().getGCMode() == LangOptions::GCOnly) { if (Sel == RetainSel || Sel == AutoreleaseSel) { - return RValue::get(Receiver); + return RValue::get(EnforceType(Builder, Receiver, + CGM.getTypes().ConvertType(ResultType))); } if (Sel == ReleaseSel) { return RValue::get(0); } } - CGBuilderTy &Builder = CGF.Builder; - // If the return type is something that goes in an integer register, the // runtime will handle 0 returns. For other cases, we fill in the 0 value // ourselves. @@ -2127,7 +2133,9 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() { // The symbol table is contained in a module which has some version-checking // constants llvm::StructType * ModuleTy = llvm::StructType::get(VMContext, LongTy, LongTy, - PtrToInt8Ty, llvm::PointerType::getUnqual(SymTabTy), NULL); + PtrToInt8Ty, llvm::PointerType::getUnqual(SymTabTy), + (CGM.getLangOptions().getGCMode() == LangOptions::NonGC) ? NULL : IntTy, + NULL); Elements.clear(); // Runtime version, used for ABI compatibility checking. Elements.push_back(llvm::ConstantInt::get(LongTy, RuntimeVersion)); @@ -2144,8 +2152,17 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() { std::string path = std::string(mainFile->getDir()->getName()) + '/' + mainFile->getName(); Elements.push_back(MakeConstantString(path, ".objc_source_file_name")); - Elements.push_back(SymTab); + + switch (CGM.getLangOptions().getGCMode()) { + case LangOptions::GCOnly: + Elements.push_back(llvm::ConstantInt::get(IntTy, 2)); + case LangOptions::NonGC: + break; + case LangOptions::HybridGC: + Elements.push_back(llvm::ConstantInt::get(IntTy, 1)); + } + llvm::Value *Module = MakeGlobal(ModuleTy, Elements); // Create the load function calling the runtime entry point with the module @@ -2159,10 +2176,10 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() { CGBuilderTy Builder(VMContext); Builder.SetInsertPoint(EntryBB); - std::vector<const llvm::Type*> Params(1, - llvm::PointerType::getUnqual(ModuleTy)); - llvm::Value *Register = CGM.CreateRuntimeFunction(llvm::FunctionType::get( - llvm::Type::getVoidTy(VMContext), Params, true), "__objc_exec_class"); + llvm::FunctionType *FT = + llvm::FunctionType::get(Builder.getVoidTy(), + llvm::PointerType::getUnqual(ModuleTy), true); + llvm::Value *Register = CGM.CreateRuntimeFunction(FT, "__objc_exec_class"); Builder.CreateCall(Register, Module); Builder.CreateRetVoid(); @@ -2192,18 +2209,18 @@ llvm::Function *CGObjCGNU::GenerateMethod(const ObjCMethodDecl *OMD, return Method; } -llvm::Function *CGObjCGNU::GetPropertyGetFunction() { +llvm::Constant *CGObjCGNU::GetPropertyGetFunction() { return GetPropertyFn; } -llvm::Function *CGObjCGNU::GetPropertySetFunction() { +llvm::Constant *CGObjCGNU::GetPropertySetFunction() { return SetPropertyFn; } -llvm::Function *CGObjCGNU::GetGetStructFunction() { +llvm::Constant *CGObjCGNU::GetGetStructFunction() { return GetStructPropertyFn; } -llvm::Function *CGObjCGNU::GetSetStructFunction() { +llvm::Constant *CGObjCGNU::GetSetStructFunction() { return SetStructPropertyFn; } @@ -2273,7 +2290,7 @@ void CGObjCGNU::EmitThrowStmt(CodeGenFunction &CGF, llvm::Value * CGObjCGNU::EmitObjCWeakRead(CodeGenFunction &CGF, llvm::Value *AddrWeakObj) { CGBuilderTy B = CGF.Builder; - AddrWeakObj = EnforceType(B, AddrWeakObj, IdTy); + AddrWeakObj = EnforceType(B, AddrWeakObj, PtrToIdTy); return B.CreateCall(WeakReadFn, AddrWeakObj); } @@ -2303,7 +2320,7 @@ void CGObjCGNU::EmitObjCIvarAssign(CodeGenFunction &CGF, llvm::Value *ivarOffset) { CGBuilderTy B = CGF.Builder; src = EnforceType(B, src, IdTy); - dst = EnforceType(B, dst, PtrToIdTy); + dst = EnforceType(B, dst, IdTy); B.CreateCall3(IvarAssignFn, src, dst, ivarOffset); } @@ -2320,8 +2337,8 @@ void CGObjCGNU::EmitGCMemmoveCollectable(CodeGenFunction &CGF, llvm::Value *SrcPtr, llvm::Value *Size) { CGBuilderTy B = CGF.Builder; - DestPtr = EnforceType(B, DestPtr, IdTy); - SrcPtr = EnforceType(B, SrcPtr, PtrToIdTy); + DestPtr = EnforceType(B, DestPtr, PtrTy); + SrcPtr = EnforceType(B, SrcPtr, PtrTy); B.CreateCall3(MemMoveFn, DestPtr, SrcPtr, Size); } diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGObjCMac.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGObjCMac.cpp index 2b1cfe3..8c3e9a3 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGObjCMac.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGObjCMac.cpp @@ -43,18 +43,6 @@ using namespace clang; using namespace CodeGen; -static void EmitNullReturnInitialization(CodeGenFunction &CGF, - ReturnValueSlot &returnSlot, - QualType resultType) { - // Force the return slot to exist. - if (!returnSlot.getValue()) - returnSlot = ReturnValueSlot(CGF.CreateMemTemp(resultType), false); - CGF.EmitNullInitialization(returnSlot.getValue(), resultType); -} - - -/// - namespace { typedef std::vector<llvm::Constant*> ConstantVector; @@ -67,89 +55,89 @@ protected: llvm::LLVMContext &VMContext; private: + // The types of these functions don't really matter because we + // should always bitcast before calling them. + + /// id objc_msgSend (id, SEL, ...) + /// + /// The default messenger, used for sends whose ABI is unchanged from + /// the all-integer/pointer case. llvm::Constant *getMessageSendFn() const { - // id objc_msgSend (id, SEL, ...) - std::vector<const llvm::Type*> Params; - Params.push_back(ObjectPtrTy); - Params.push_back(SelectorPtrTy); - return - CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy, - Params, true), - "objc_msgSend"); + const llvm::Type *params[] = { ObjectPtrTy, SelectorPtrTy }; + return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy, + params, true), + "objc_msgSend"); } + /// void objc_msgSend_stret (id, SEL, ...) + /// + /// The messenger used when the return value is an aggregate returned + /// by indirect reference in the first argument, and therefore the + /// self and selector parameters are shifted over by one. llvm::Constant *getMessageSendStretFn() const { - // id objc_msgSend_stret (id, SEL, ...) - std::vector<const llvm::Type*> Params; - Params.push_back(ObjectPtrTy); - Params.push_back(SelectorPtrTy); - return - CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), - Params, true), - "objc_msgSend_stret"); + const llvm::Type *params[] = { ObjectPtrTy, SelectorPtrTy }; + return CGM.CreateRuntimeFunction(llvm::FunctionType::get(CGM.VoidTy, + params, true), + "objc_msgSend_stret"); } + /// [double | long double] objc_msgSend_fpret(id self, SEL op, ...) + /// + /// The messenger used when the return value is returned on the x87 + /// floating-point stack; without a special entrypoint, the nil case + /// would be unbalanced. llvm::Constant *getMessageSendFpretFn() const { - // FIXME: This should be long double on x86_64? - // [double | long double] objc_msgSend_fpret(id self, SEL op, ...) - std::vector<const llvm::Type*> Params; - Params.push_back(ObjectPtrTy); - Params.push_back(SelectorPtrTy); - return - CGM.CreateRuntimeFunction(llvm::FunctionType::get( + const llvm::Type *params[] = { ObjectPtrTy, SelectorPtrTy }; + return CGM.CreateRuntimeFunction(llvm::FunctionType::get( llvm::Type::getDoubleTy(VMContext), - Params, - true), - "objc_msgSend_fpret"); + params, true), + "objc_msgSend_fpret"); } + /// id objc_msgSendSuper(struct objc_super *super, SEL op, ...) + /// + /// The messenger used for super calls, which have different dispatch + /// semantics. The class passed is the superclass of the current + /// class. llvm::Constant *getMessageSendSuperFn() const { - // id objc_msgSendSuper(struct objc_super *super, SEL op, ...) - const char *SuperName = "objc_msgSendSuper"; - std::vector<const llvm::Type*> Params; - Params.push_back(SuperPtrTy); - Params.push_back(SelectorPtrTy); + const llvm::Type *params[] = { SuperPtrTy, SelectorPtrTy }; return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy, - Params, true), - SuperName); + params, true), + "objc_msgSendSuper"); } + /// id objc_msgSendSuper2(struct objc_super *super, SEL op, ...) + /// + /// A slightly different messenger used for super calls. The class + /// passed is the current class. llvm::Constant *getMessageSendSuperFn2() const { - // id objc_msgSendSuper2(struct objc_super *super, SEL op, ...) - const char *SuperName = "objc_msgSendSuper2"; - std::vector<const llvm::Type*> Params; - Params.push_back(SuperPtrTy); - Params.push_back(SelectorPtrTy); + const llvm::Type *params[] = { SuperPtrTy, SelectorPtrTy }; return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy, - Params, true), - SuperName); + params, true), + "objc_msgSendSuper2"); } + /// void objc_msgSendSuper_stret(void *stretAddr, struct objc_super *super, + /// SEL op, ...) + /// + /// The messenger used for super calls which return an aggregate indirectly. llvm::Constant *getMessageSendSuperStretFn() const { - // void objc_msgSendSuper_stret(void * stretAddr, struct objc_super *super, - // SEL op, ...) - std::vector<const llvm::Type*> Params; - Params.push_back(Int8PtrTy); - Params.push_back(SuperPtrTy); - Params.push_back(SelectorPtrTy); + const llvm::Type *params[] = { Int8PtrTy, SuperPtrTy, SelectorPtrTy }; return CGM.CreateRuntimeFunction( - llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), - Params, true), + llvm::FunctionType::get(CGM.VoidTy, params, true), "objc_msgSendSuper_stret"); } + /// void objc_msgSendSuper2_stret(void * stretAddr, struct objc_super *super, + /// SEL op, ...) + /// + /// objc_msgSendSuper_stret with the super2 semantics. llvm::Constant *getMessageSendSuperStretFn2() const { - // void objc_msgSendSuper2_stret(void * stretAddr, struct objc_super *super, - // SEL op, ...) - std::vector<const llvm::Type*> Params; - Params.push_back(Int8PtrTy); - Params.push_back(SuperPtrTy); - Params.push_back(SelectorPtrTy); + const llvm::Type *params[] = { Int8PtrTy, SuperPtrTy, SelectorPtrTy }; return CGM.CreateRuntimeFunction( - llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), - Params, true), + llvm::FunctionType::get(CGM.VoidTy, params, true), "objc_msgSendSuper2_stret"); } @@ -282,107 +270,97 @@ public: /// GcReadWeakFn -- LLVM objc_read_weak (id *src) function. llvm::Constant *getGcReadWeakFn() { // id objc_read_weak (id *) - std::vector<const llvm::Type*> Args; - Args.push_back(ObjectPtrTy->getPointerTo()); + const llvm::Type *args[] = { ObjectPtrTy->getPointerTo() }; llvm::FunctionType *FTy = - llvm::FunctionType::get(ObjectPtrTy, Args, false); + llvm::FunctionType::get(ObjectPtrTy, args, false); return CGM.CreateRuntimeFunction(FTy, "objc_read_weak"); } /// GcAssignWeakFn -- LLVM objc_assign_weak function. llvm::Constant *getGcAssignWeakFn() { // id objc_assign_weak (id, id *) - std::vector<const llvm::Type*> Args(1, ObjectPtrTy); - Args.push_back(ObjectPtrTy->getPointerTo()); + const llvm::Type *args[] = { ObjectPtrTy, ObjectPtrTy->getPointerTo() }; llvm::FunctionType *FTy = - llvm::FunctionType::get(ObjectPtrTy, Args, false); + llvm::FunctionType::get(ObjectPtrTy, args, false); return CGM.CreateRuntimeFunction(FTy, "objc_assign_weak"); } /// GcAssignGlobalFn -- LLVM objc_assign_global function. llvm::Constant *getGcAssignGlobalFn() { // id objc_assign_global(id, id *) - std::vector<const llvm::Type*> Args(1, ObjectPtrTy); - Args.push_back(ObjectPtrTy->getPointerTo()); + const llvm::Type *args[] = { ObjectPtrTy, ObjectPtrTy->getPointerTo() }; llvm::FunctionType *FTy = - llvm::FunctionType::get(ObjectPtrTy, Args, false); + llvm::FunctionType::get(ObjectPtrTy, args, false); return CGM.CreateRuntimeFunction(FTy, "objc_assign_global"); } /// GcAssignThreadLocalFn -- LLVM objc_assign_threadlocal function. llvm::Constant *getGcAssignThreadLocalFn() { // id objc_assign_threadlocal(id src, id * dest) - std::vector<const llvm::Type*> Args(1, ObjectPtrTy); - Args.push_back(ObjectPtrTy->getPointerTo()); + const llvm::Type *args[] = { ObjectPtrTy, ObjectPtrTy->getPointerTo() }; llvm::FunctionType *FTy = - llvm::FunctionType::get(ObjectPtrTy, Args, false); + llvm::FunctionType::get(ObjectPtrTy, args, false); return CGM.CreateRuntimeFunction(FTy, "objc_assign_threadlocal"); } /// GcAssignIvarFn -- LLVM objc_assign_ivar function. llvm::Constant *getGcAssignIvarFn() { // id objc_assign_ivar(id, id *, ptrdiff_t) - std::vector<const llvm::Type*> Args(1, ObjectPtrTy); - Args.push_back(ObjectPtrTy->getPointerTo()); - Args.push_back(LongTy); + const llvm::Type *args[] = { ObjectPtrTy, ObjectPtrTy->getPointerTo(), + CGM.PtrDiffTy }; llvm::FunctionType *FTy = - llvm::FunctionType::get(ObjectPtrTy, Args, false); + llvm::FunctionType::get(ObjectPtrTy, args, false); return CGM.CreateRuntimeFunction(FTy, "objc_assign_ivar"); } /// GcMemmoveCollectableFn -- LLVM objc_memmove_collectable function. llvm::Constant *GcMemmoveCollectableFn() { // void *objc_memmove_collectable(void *dst, const void *src, size_t size) - std::vector<const llvm::Type*> Args(1, Int8PtrTy); - Args.push_back(Int8PtrTy); - Args.push_back(LongTy); - llvm::FunctionType *FTy = llvm::FunctionType::get(Int8PtrTy, Args, false); + const llvm::Type *args[] = { Int8PtrTy, Int8PtrTy, LongTy }; + llvm::FunctionType *FTy = llvm::FunctionType::get(Int8PtrTy, args, false); return CGM.CreateRuntimeFunction(FTy, "objc_memmove_collectable"); } /// GcAssignStrongCastFn -- LLVM objc_assign_strongCast function. llvm::Constant *getGcAssignStrongCastFn() { // id objc_assign_strongCast(id, id *) - std::vector<const llvm::Type*> Args(1, ObjectPtrTy); - Args.push_back(ObjectPtrTy->getPointerTo()); + const llvm::Type *args[] = { ObjectPtrTy, ObjectPtrTy->getPointerTo() }; llvm::FunctionType *FTy = - llvm::FunctionType::get(ObjectPtrTy, Args, false); + llvm::FunctionType::get(ObjectPtrTy, args, false); return CGM.CreateRuntimeFunction(FTy, "objc_assign_strongCast"); } /// ExceptionThrowFn - LLVM objc_exception_throw function. llvm::Constant *getExceptionThrowFn() { // void objc_exception_throw(id) - std::vector<const llvm::Type*> Args(1, ObjectPtrTy); + const llvm::Type *args[] = { ObjectPtrTy }; llvm::FunctionType *FTy = - llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), Args, false); + llvm::FunctionType::get(CGM.VoidTy, args, false); return CGM.CreateRuntimeFunction(FTy, "objc_exception_throw"); } /// ExceptionRethrowFn - LLVM objc_exception_rethrow function. llvm::Constant *getExceptionRethrowFn() { // void objc_exception_rethrow(void) - std::vector<const llvm::Type*> Args; - llvm::FunctionType *FTy = - llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), Args, false); + llvm::FunctionType *FTy = llvm::FunctionType::get(CGM.VoidTy, false); return CGM.CreateRuntimeFunction(FTy, "objc_exception_rethrow"); } /// SyncEnterFn - LLVM object_sync_enter function. llvm::Constant *getSyncEnterFn() { // void objc_sync_enter (id) - std::vector<const llvm::Type*> Args(1, ObjectPtrTy); + const llvm::Type *args[] = { ObjectPtrTy }; llvm::FunctionType *FTy = - llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), Args, false); + llvm::FunctionType::get(CGM.VoidTy, args, false); return CGM.CreateRuntimeFunction(FTy, "objc_sync_enter"); } /// SyncExitFn - LLVM object_sync_exit function. llvm::Constant *getSyncExitFn() { // void objc_sync_exit (id) - std::vector<const llvm::Type*> Args(1, ObjectPtrTy); + const llvm::Type *args[] = { ObjectPtrTy }; llvm::FunctionType *FTy = - llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), Args, false); + llvm::FunctionType::get(CGM.VoidTy, args, false); return CGM.CreateRuntimeFunction(FTy, "objc_sync_exit"); } @@ -474,55 +452,44 @@ public: /// ExceptionTryEnterFn - LLVM objc_exception_try_enter function. llvm::Constant *getExceptionTryEnterFn() { - std::vector<const llvm::Type*> Params; - Params.push_back(llvm::PointerType::getUnqual(ExceptionDataTy)); + const llvm::Type *params[] = { ExceptionDataTy->getPointerTo() }; return CGM.CreateRuntimeFunction( - llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), - Params, false), + llvm::FunctionType::get(CGM.VoidTy, params, false), "objc_exception_try_enter"); } /// ExceptionTryExitFn - LLVM objc_exception_try_exit function. llvm::Constant *getExceptionTryExitFn() { - std::vector<const llvm::Type*> Params; - Params.push_back(llvm::PointerType::getUnqual(ExceptionDataTy)); + const llvm::Type *params[] = { ExceptionDataTy->getPointerTo() }; return CGM.CreateRuntimeFunction( - llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), - Params, false), + llvm::FunctionType::get(CGM.VoidTy, params, false), "objc_exception_try_exit"); } /// ExceptionExtractFn - LLVM objc_exception_extract function. llvm::Constant *getExceptionExtractFn() { - std::vector<const llvm::Type*> Params; - Params.push_back(llvm::PointerType::getUnqual(ExceptionDataTy)); + const llvm::Type *params[] = { ExceptionDataTy->getPointerTo() }; return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy, - Params, false), + params, false), "objc_exception_extract"); - } /// ExceptionMatchFn - LLVM objc_exception_match function. llvm::Constant *getExceptionMatchFn() { - std::vector<const llvm::Type*> Params; - Params.push_back(ClassPtrTy); - Params.push_back(ObjectPtrTy); + const llvm::Type *params[] = { ClassPtrTy, ObjectPtrTy }; return CGM.CreateRuntimeFunction( - llvm::FunctionType::get(llvm::Type::getInt32Ty(VMContext), - Params, false), + llvm::FunctionType::get(CGM.Int32Ty, params, false), "objc_exception_match"); } /// SetJmpFn - LLVM _setjmp function. llvm::Constant *getSetJmpFn() { - std::vector<const llvm::Type*> Params; - Params.push_back(llvm::Type::getInt32PtrTy(VMContext)); - return - CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getInt32Ty(VMContext), - Params, false), - "_setjmp"); - + // This is specifically the prototype for x86. + const llvm::Type *params[] = { CGM.Int32Ty->getPointerTo() }; + return CGM.CreateRuntimeFunction(llvm::FunctionType::get(CGM.Int32Ty, + params, false), + "_setjmp"); } public: @@ -608,68 +575,56 @@ public: llvm::Constant *getMessageSendFixupFn() { // id objc_msgSend_fixup(id, struct message_ref_t*, ...) - std::vector<const llvm::Type*> Params; - Params.push_back(ObjectPtrTy); - Params.push_back(MessageRefPtrTy); + const llvm::Type *params[] = { ObjectPtrTy, MessageRefPtrTy }; return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy, - Params, true), + params, true), "objc_msgSend_fixup"); } llvm::Constant *getMessageSendFpretFixupFn() { // id objc_msgSend_fpret_fixup(id, struct message_ref_t*, ...) - std::vector<const llvm::Type*> Params; - Params.push_back(ObjectPtrTy); - Params.push_back(MessageRefPtrTy); + const llvm::Type *params[] = { ObjectPtrTy, MessageRefPtrTy }; return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy, - Params, true), + params, true), "objc_msgSend_fpret_fixup"); } llvm::Constant *getMessageSendStretFixupFn() { // id objc_msgSend_stret_fixup(id, struct message_ref_t*, ...) - std::vector<const llvm::Type*> Params; - Params.push_back(ObjectPtrTy); - Params.push_back(MessageRefPtrTy); + const llvm::Type *params[] = { ObjectPtrTy, MessageRefPtrTy }; return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy, - Params, true), + params, true), "objc_msgSend_stret_fixup"); } llvm::Constant *getMessageSendSuper2FixupFn() { // id objc_msgSendSuper2_fixup (struct objc_super *, // struct _super_message_ref_t*, ...) - std::vector<const llvm::Type*> Params; - Params.push_back(SuperPtrTy); - Params.push_back(SuperMessageRefPtrTy); + const llvm::Type *params[] = { SuperPtrTy, SuperMessageRefPtrTy }; return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy, - Params, true), + params, true), "objc_msgSendSuper2_fixup"); } llvm::Constant *getMessageSendSuper2StretFixupFn() { // id objc_msgSendSuper2_stret_fixup(struct objc_super *, // struct _super_message_ref_t*, ...) - std::vector<const llvm::Type*> Params; - Params.push_back(SuperPtrTy); - Params.push_back(SuperMessageRefPtrTy); + const llvm::Type *params[] = { SuperPtrTy, SuperMessageRefPtrTy }; return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy, - Params, true), + params, true), "objc_msgSendSuper2_stret_fixup"); } llvm::Constant *getObjCEndCatchFn() { - return CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), - false), + return CGM.CreateRuntimeFunction(llvm::FunctionType::get(CGM.VoidTy, false), "objc_end_catch"); } llvm::Constant *getObjCBeginCatchFn() { - std::vector<const llvm::Type*> Params; - Params.push_back(Int8PtrTy); + const llvm::Type *params[] = { Int8PtrTy }; return CGM.CreateRuntimeFunction(llvm::FunctionType::get(Int8PtrTy, - Params, false), + params, false), "objc_begin_catch"); } @@ -865,16 +820,16 @@ protected: unsigned Align, bool AddToUsed); - CodeGen::RValue EmitLegacyMessageSend(CodeGen::CodeGenFunction &CGF, - ReturnValueSlot Return, - QualType ResultType, - llvm::Value *Sel, - llvm::Value *Arg0, - QualType Arg0Ty, - bool IsSuper, - const CallArgList &CallArgs, - const ObjCMethodDecl *OMD, - const ObjCCommonTypesHelper &ObjCTypes); + CodeGen::RValue EmitMessageSend(CodeGen::CodeGenFunction &CGF, + ReturnValueSlot Return, + QualType ResultType, + llvm::Value *Sel, + llvm::Value *Arg0, + QualType Arg0Ty, + bool IsSuper, + const CallArgList &CallArgs, + const ObjCMethodDecl *OMD, + const ObjCCommonTypesHelper &ObjCTypes); /// EmitImageInfo - Emit the image info marker used to encode some module /// level information. @@ -1093,6 +1048,13 @@ public: virtual llvm::Value *EmitIvarOffset(CodeGen::CodeGenFunction &CGF, const ObjCInterfaceDecl *Interface, const ObjCIvarDecl *Ivar); + + /// GetClassGlobal - Return the global variable for the Objective-C + /// class of the given name. + virtual llvm::GlobalVariable *GetClassGlobal(const std::string &Name) { + assert(false && "CGObjCMac::GetClassGlobal"); + return 0; + } }; class CGObjCNonFragileABIMac : public CGObjCCommonMac { @@ -1110,16 +1072,16 @@ private: /// EHTypeReferences - uniqued class ehtype references. llvm::DenseMap<IdentifierInfo*, llvm::GlobalVariable*> EHTypeReferences; - /// NonLegacyDispatchMethods - List of methods for which we do *not* generate - /// legacy messaging dispatch. - llvm::DenseSet<Selector> NonLegacyDispatchMethods; + /// VTableDispatchMethods - List of methods for which we generate + /// vtable-based message dispatch. + llvm::DenseSet<Selector> VTableDispatchMethods; /// DefinedMetaClasses - List of defined meta-classes. std::vector<llvm::GlobalValue*> DefinedMetaClasses; - /// LegacyDispatchedSelector - Returns true if SEL is not in the list of - /// NonLegacyDispatchMethods; false otherwise. - bool LegacyDispatchedSelector(Selector Sel); + /// isVTableDispatchedSelector - Returns true if SEL is a + /// vtable-based selector. + bool isVTableDispatchedSelector(Selector Sel); /// FinishNonFragileABIModule - Write out global data structures at the end of /// processing a translation unit. @@ -1178,20 +1140,20 @@ private: ObjCProtocolDecl::protocol_iterator begin, ObjCProtocolDecl::protocol_iterator end); - CodeGen::RValue EmitMessageSend(CodeGen::CodeGenFunction &CGF, - ReturnValueSlot Return, - QualType ResultType, - Selector Sel, - llvm::Value *Receiver, - QualType Arg0Ty, - bool IsSuper, - const CallArgList &CallArgs, - const ObjCMethodDecl *Method); - + CodeGen::RValue EmitVTableMessageSend(CodeGen::CodeGenFunction &CGF, + ReturnValueSlot Return, + QualType ResultType, + Selector Sel, + llvm::Value *Receiver, + QualType Arg0Ty, + bool IsSuper, + const CallArgList &CallArgs, + const ObjCMethodDecl *Method); + /// GetClassGlobal - Return the global variable for the Objective-C /// class of the given name. llvm::GlobalVariable *GetClassGlobal(const std::string &Name); - + /// EmitClassRef - Return a Value*, of type ObjCTypes.ClassPtrTy, /// for the given class reference. llvm::Value *EmitClassRef(CGBuilderTy &Builder, @@ -1347,6 +1309,46 @@ public: const ObjCIvarDecl *Ivar); }; +/// A helper class for performing the null-initialization of a return +/// value. +struct NullReturnState { + llvm::BasicBlock *NullBB; + + NullReturnState() : NullBB(0) {} + + void init(CodeGenFunction &CGF, llvm::Value *receiver) { + // Make blocks for the null-init and call edges. + NullBB = CGF.createBasicBlock("msgSend.nullinit"); + llvm::BasicBlock *callBB = CGF.createBasicBlock("msgSend.call"); + + // Check for a null receiver and, if there is one, jump to the + // null-init test. + llvm::Value *isNull = CGF.Builder.CreateIsNull(receiver); + CGF.Builder.CreateCondBr(isNull, NullBB, callBB); + + // Otherwise, start performing the call. + CGF.EmitBlock(callBB); + } + + RValue complete(CodeGenFunction &CGF, RValue result, QualType resultType) { + if (!NullBB) return result; + + // Finish the call path. + llvm::BasicBlock *contBB = CGF.createBasicBlock("msgSend.cont"); + if (CGF.HaveInsertPoint()) CGF.Builder.CreateBr(contBB); + + // Emit the null-init block and perform the null-initialization there. + CGF.EmitBlock(NullBB); + assert(result.isAggregate() && "null init of non-aggregate result?"); + CGF.EmitNullInitialization(result.getAggregateAddr(), resultType); + + // Jump to the continuation block. + CGF.EmitBlock(contBB); + + return result; + } +}; + } // end anonymous namespace /* *** Helper Functions *** */ @@ -1487,10 +1489,10 @@ CGObjCMac::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF, Target = CGF.Builder.CreateBitCast(Target, ClassTy); CGF.Builder.CreateStore(Target, CGF.Builder.CreateStructGEP(ObjCSuper, 1)); - return EmitLegacyMessageSend(CGF, Return, ResultType, - EmitSelector(CGF.Builder, Sel), - ObjCSuper, ObjCTypes.SuperPtrCTy, - true, CallArgs, Method, ObjCTypes); + return EmitMessageSend(CGF, Return, ResultType, + EmitSelector(CGF.Builder, Sel), + ObjCSuper, ObjCTypes.SuperPtrCTy, + true, CallArgs, Method, ObjCTypes); } /// Generate code for a message send expression. @@ -1502,23 +1504,23 @@ CodeGen::RValue CGObjCMac::GenerateMessageSend(CodeGen::CodeGenFunction &CGF, const CallArgList &CallArgs, const ObjCInterfaceDecl *Class, const ObjCMethodDecl *Method) { - return EmitLegacyMessageSend(CGF, Return, ResultType, - EmitSelector(CGF.Builder, Sel), - Receiver, CGF.getContext().getObjCIdType(), - false, CallArgs, Method, ObjCTypes); + return EmitMessageSend(CGF, Return, ResultType, + EmitSelector(CGF.Builder, Sel), + Receiver, CGF.getContext().getObjCIdType(), + false, CallArgs, Method, ObjCTypes); } CodeGen::RValue -CGObjCCommonMac::EmitLegacyMessageSend(CodeGen::CodeGenFunction &CGF, - ReturnValueSlot Return, - QualType ResultType, - llvm::Value *Sel, - llvm::Value *Arg0, - QualType Arg0Ty, - bool IsSuper, - const CallArgList &CallArgs, - const ObjCMethodDecl *Method, - const ObjCCommonTypesHelper &ObjCTypes) { +CGObjCCommonMac::EmitMessageSend(CodeGen::CodeGenFunction &CGF, + ReturnValueSlot Return, + QualType ResultType, + llvm::Value *Sel, + llvm::Value *Arg0, + QualType Arg0Ty, + bool IsSuper, + const CallArgList &CallArgs, + const ObjCMethodDecl *Method, + const ObjCCommonTypesHelper &ObjCTypes) { CallArgList ActualArgs; if (!IsSuper) Arg0 = CGF.Builder.CreateBitCast(Arg0, ObjCTypes.ObjectPtrTy, "tmp"); @@ -1537,9 +1539,11 @@ CGObjCCommonMac::EmitLegacyMessageSend(CodeGen::CodeGenFunction &CGF, CGM.getContext().getCanonicalType(ResultType) && "Result type mismatch!"); + NullReturnState nullReturn; + llvm::Constant *Fn = NULL; if (CGM.ReturnTypeUsesSRet(FnInfo)) { - EmitNullReturnInitialization(CGF, Return, ResultType); + if (!IsSuper) nullReturn.init(CGF, Arg0); Fn = (ObjCABI == 2) ? ObjCTypes.getSendStretFn2(IsSuper) : ObjCTypes.getSendStretFn(IsSuper); } else if (CGM.ReturnTypeUsesFPRet(ResultType)) { @@ -1550,7 +1554,8 @@ CGObjCCommonMac::EmitLegacyMessageSend(CodeGen::CodeGenFunction &CGF, : ObjCTypes.getSendFn(IsSuper); } Fn = llvm::ConstantExpr::getBitCast(Fn, llvm::PointerType::getUnqual(FTy)); - return CGF.EmitCall(FnInfo, Fn, Return, ActualArgs); + RValue rvalue = CGF.EmitCall(FnInfo, Fn, Return, ActualArgs); + return nullReturn.complete(CGF, rvalue, ResultType); } static Qualifiers::GC GetGCAttrTypeForType(ASTContext &Ctx, QualType FQT) { @@ -1681,6 +1686,7 @@ void CGObjCCommonMac::GenerateProtocol(const ObjCProtocolDecl *PD) { llvm::Constant *CGObjCCommonMac::GetProtocolRef(const ObjCProtocolDecl *PD) { if (DefinedProtocols.count(PD->getIdentifier())) return GetOrEmitProtocol(PD); + return GetOrEmitProtocolRef(PD); } @@ -1714,6 +1720,9 @@ llvm::Constant *CGObjCMac::GetOrEmitProtocol(const ObjCProtocolDecl *PD) { i = PD->instmeth_begin(), e = PD->instmeth_end(); i != e; ++i) { ObjCMethodDecl *MD = *i; llvm::Constant *C = GetMethodDescriptionConstant(MD); + if (!C) + return GetOrEmitProtocolRef(PD); + if (MD->getImplementationControl() == ObjCMethodDecl::Optional) { OptInstanceMethods.push_back(C); } else { @@ -1725,6 +1734,9 @@ llvm::Constant *CGObjCMac::GetOrEmitProtocol(const ObjCProtocolDecl *PD) { i = PD->classmeth_begin(), e = PD->classmeth_end(); i != e; ++i) { ObjCMethodDecl *MD = *i; llvm::Constant *C = GetMethodDescriptionConstant(MD); + if (!C) + return GetOrEmitProtocolRef(PD); + if (MD->getImplementationControl() == ObjCMethodDecl::Optional) { OptClassMethods.push_back(C); } else { @@ -1968,6 +1980,9 @@ CGObjCMac::GetMethodDescriptionConstant(const ObjCMethodDecl *MD) { llvm::ConstantExpr::getBitCast(GetMethodVarName(MD->getSelector()), ObjCTypes.SelectorPtrTy); Desc[1] = GetMethodVarType(MD); + if (!Desc[1]) + return 0; + return llvm::ConstantStruct::get(ObjCTypes.MethodDescriptionTy, Desc); } @@ -2730,10 +2745,10 @@ void FragileHazards::collectLocals() { } llvm::FunctionType *FragileHazards::GetAsmFnType() { - std::vector<const llvm::Type *> Tys(Locals.size()); - for (unsigned I = 0, E = Locals.size(); I != E; ++I) - Tys[I] = Locals[I]->getType(); - return llvm::FunctionType::get(CGF.Builder.getVoidTy(), Tys, false); + llvm::SmallVector<const llvm::Type *, 16> tys(Locals.size()); + for (unsigned i = 0, e = Locals.size(); i != e; ++i) + tys[i] = Locals[i]->getType(); + return llvm::FunctionType::get(CGF.VoidTy, tys, false); } /* @@ -3930,8 +3945,10 @@ llvm::Constant *CGObjCCommonMac::GetMethodVarType(const FieldDecl *Field) { llvm::Constant *CGObjCCommonMac::GetMethodVarType(const ObjCMethodDecl *D) { std::string TypeStr; - CGM.getContext().getObjCEncodingForMethodDecl(const_cast<ObjCMethodDecl*>(D), - TypeStr); + if (CGM.getContext().getObjCEncodingForMethodDecl( + const_cast<ObjCMethodDecl*>(D), + TypeStr)) + return 0; llvm::GlobalVariable *&Entry = MethodVarTypes[TypeStr]; @@ -4081,9 +4098,9 @@ ObjCCommonTypesHelper::ObjCCommonTypesHelper(CodeGen::CodeGenModule &cgm) SourceLocation(), SourceLocation(), &Ctx.Idents.get("_objc_super")); RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), SourceLocation(), 0, - Ctx.getObjCIdType(), 0, 0, false)); + Ctx.getObjCIdType(), 0, 0, false, false)); RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), SourceLocation(), 0, - Ctx.getObjCClassType(), 0, 0, false)); + Ctx.getObjCClassType(), 0, 0, false, false)); RD->completeDefinition(); SuperCTy = Ctx.getTagDeclType(RD); @@ -4480,11 +4497,9 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul ClassRonfABITy); // ImpnfABITy - LLVM for id (*)(id, SEL, ...) - std::vector<const llvm::Type*> Params; - Params.push_back(ObjectPtrTy); - Params.push_back(SelectorPtrTy); - ImpnfABITy = llvm::PointerType::getUnqual( - llvm::FunctionType::get(ObjectPtrTy, Params, false)); + const llvm::Type *params[] = { ObjectPtrTy, SelectorPtrTy }; + ImpnfABITy = llvm::FunctionType::get(ObjectPtrTy, params, false) + ->getPointerTo(); // struct _class_t { // struct _class_t *isa; @@ -4544,9 +4559,9 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul SourceLocation(), SourceLocation(), &Ctx.Idents.get("_message_ref_t")); RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), SourceLocation(), 0, - Ctx.VoidPtrTy, 0, 0, false)); + Ctx.VoidPtrTy, 0, 0, false, false)); RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), SourceLocation(), 0, - Ctx.getObjCSelType(), 0, 0, false)); + Ctx.getObjCSelType(), 0, 0, false, false)); RD->completeDefinition(); MessageRefCTy = Ctx.getTagDeclType(RD); @@ -4658,56 +4673,68 @@ void CGObjCNonFragileABIMac::FinishNonFragileABIModule() { EmitImageInfo(); } -/// LegacyDispatchedSelector - Returns true if SEL is not in the list of -/// NonLegacyDispatchMethods; false otherwise. What this means is that +/// isVTableDispatchedSelector - Returns true if SEL is not in the list of +/// VTableDispatchMethods; false otherwise. What this means is that /// except for the 19 selectors in the list, we generate 32bit-style /// message dispatch call for all the rest. -/// -bool CGObjCNonFragileABIMac::LegacyDispatchedSelector(Selector Sel) { +bool CGObjCNonFragileABIMac::isVTableDispatchedSelector(Selector Sel) { + // At various points we've experimented with using vtable-based + // dispatch for all methods. switch (CGM.getCodeGenOpts().getObjCDispatchMethod()) { default: - assert(0 && "Invalid dispatch method!"); + llvm_unreachable("Invalid dispatch method!"); case CodeGenOptions::Legacy: - return true; - case CodeGenOptions::NonLegacy: return false; + case CodeGenOptions::NonLegacy: + return true; case CodeGenOptions::Mixed: break; } // If so, see whether this selector is in the white-list of things which must // use the new dispatch convention. We lazily build a dense set for this. - if (NonLegacyDispatchMethods.empty()) { - NonLegacyDispatchMethods.insert(GetNullarySelector("alloc")); - NonLegacyDispatchMethods.insert(GetNullarySelector("class")); - NonLegacyDispatchMethods.insert(GetNullarySelector("self")); - NonLegacyDispatchMethods.insert(GetNullarySelector("isFlipped")); - NonLegacyDispatchMethods.insert(GetNullarySelector("length")); - NonLegacyDispatchMethods.insert(GetNullarySelector("count")); - NonLegacyDispatchMethods.insert(GetNullarySelector("retain")); - NonLegacyDispatchMethods.insert(GetNullarySelector("release")); - NonLegacyDispatchMethods.insert(GetNullarySelector("autorelease")); - NonLegacyDispatchMethods.insert(GetNullarySelector("hash")); - - NonLegacyDispatchMethods.insert(GetUnarySelector("allocWithZone")); - NonLegacyDispatchMethods.insert(GetUnarySelector("isKindOfClass")); - NonLegacyDispatchMethods.insert(GetUnarySelector("respondsToSelector")); - NonLegacyDispatchMethods.insert(GetUnarySelector("objectForKey")); - NonLegacyDispatchMethods.insert(GetUnarySelector("objectAtIndex")); - NonLegacyDispatchMethods.insert(GetUnarySelector("isEqualToString")); - NonLegacyDispatchMethods.insert(GetUnarySelector("isEqual")); - NonLegacyDispatchMethods.insert(GetUnarySelector("addObject")); - // "countByEnumeratingWithState:objects:count" - IdentifierInfo *KeyIdents[] = { - &CGM.getContext().Idents.get("countByEnumeratingWithState"), - &CGM.getContext().Idents.get("objects"), - &CGM.getContext().Idents.get("count") - }; - NonLegacyDispatchMethods.insert( - CGM.getContext().Selectors.getSelector(3, KeyIdents)); - } - - return (NonLegacyDispatchMethods.count(Sel) == 0); + if (VTableDispatchMethods.empty()) { + VTableDispatchMethods.insert(GetNullarySelector("alloc")); + VTableDispatchMethods.insert(GetNullarySelector("class")); + VTableDispatchMethods.insert(GetNullarySelector("self")); + VTableDispatchMethods.insert(GetNullarySelector("isFlipped")); + VTableDispatchMethods.insert(GetNullarySelector("length")); + VTableDispatchMethods.insert(GetNullarySelector("count")); + + // These are vtable-based if GC is disabled. + // Optimistically use vtable dispatch for hybrid compiles. + if (CGM.getLangOptions().getGCMode() != LangOptions::GCOnly) { + VTableDispatchMethods.insert(GetNullarySelector("retain")); + VTableDispatchMethods.insert(GetNullarySelector("release")); + VTableDispatchMethods.insert(GetNullarySelector("autorelease")); + } + + VTableDispatchMethods.insert(GetUnarySelector("allocWithZone")); + VTableDispatchMethods.insert(GetUnarySelector("isKindOfClass")); + VTableDispatchMethods.insert(GetUnarySelector("respondsToSelector")); + VTableDispatchMethods.insert(GetUnarySelector("objectForKey")); + VTableDispatchMethods.insert(GetUnarySelector("objectAtIndex")); + VTableDispatchMethods.insert(GetUnarySelector("isEqualToString")); + VTableDispatchMethods.insert(GetUnarySelector("isEqual")); + + // These are vtable-based if GC is enabled. + // Optimistically use vtable dispatch for hybrid compiles. + if (CGM.getLangOptions().getGCMode() != LangOptions::NonGC) { + VTableDispatchMethods.insert(GetNullarySelector("hash")); + VTableDispatchMethods.insert(GetUnarySelector("addObject")); + + // "countByEnumeratingWithState:objects:count" + IdentifierInfo *KeyIdents[] = { + &CGM.getContext().Idents.get("countByEnumeratingWithState"), + &CGM.getContext().Idents.get("objects"), + &CGM.getContext().Idents.get("count") + }; + VTableDispatchMethods.insert( + CGM.getContext().Selectors.getSelector(3, KeyIdents)); + } + } + + return VTableDispatchMethods.count(Sel); } // Metadata flags @@ -5209,7 +5236,7 @@ CGObjCNonFragileABIMac::EmitIvarOffsetVar(const ObjCInterfaceDecl *ID, IvarOffsetGV->setVisibility(llvm::GlobalValue::HiddenVisibility); else IvarOffsetGV->setVisibility(llvm::GlobalValue::DefaultVisibility); - IvarOffsetGV->setSection("__DATA, __objc_const"); + IvarOffsetGV->setSection("__DATA, __objc_ivar"); return IvarOffsetGV; } @@ -5344,6 +5371,9 @@ llvm::Constant *CGObjCNonFragileABIMac::GetOrEmitProtocol( i = PD->instmeth_begin(), e = PD->instmeth_end(); i != e; ++i) { ObjCMethodDecl *MD = *i; llvm::Constant *C = GetMethodDescriptionConstant(MD); + if (!C) + return GetOrEmitProtocolRef(PD); + if (MD->getImplementationControl() == ObjCMethodDecl::Optional) { OptInstanceMethods.push_back(C); } else { @@ -5355,6 +5385,9 @@ llvm::Constant *CGObjCNonFragileABIMac::GetOrEmitProtocol( i = PD->classmeth_begin(), e = PD->classmeth_end(); i != e; ++i) { ObjCMethodDecl *MD = *i; llvm::Constant *C = GetMethodDescriptionConstant(MD); + if (!C) + return GetOrEmitProtocolRef(PD); + if (MD->getImplementationControl() == ObjCMethodDecl::Optional) { OptClassMethods.push_back(C); } else { @@ -5494,6 +5527,9 @@ CGObjCNonFragileABIMac::GetMethodDescriptionConstant(const ObjCMethodDecl *MD) { llvm::ConstantExpr::getBitCast(GetMethodVarName(MD->getSelector()), ObjCTypes.SelectorPtrTy); Desc[1] = GetMethodVarType(MD); + if (!Desc[1]) + return 0; + // Protocol methods have no implementation. So, this entry is always NULL. Desc[2] = llvm::Constant::getNullValue(ObjCTypes.Int8PtrTy); return llvm::ConstantStruct::get(ObjCTypes.MethodTy, Desc); @@ -5523,90 +5559,131 @@ llvm::Value *CGObjCNonFragileABIMac::EmitIvarOffset( return CGF.Builder.CreateLoad(ObjCIvarOffsetVariable(Interface, Ivar),"ivar"); } -CodeGen::RValue CGObjCNonFragileABIMac::EmitMessageSend( - CodeGen::CodeGenFunction &CGF, - ReturnValueSlot Return, - QualType ResultType, - Selector Sel, - llvm::Value *Receiver, - QualType Arg0Ty, - bool IsSuper, - const CallArgList &CallArgs, - const ObjCMethodDecl *Method) { - // FIXME. Even though IsSuper is passes. This function doese not handle calls - // to 'super' receivers. - CodeGenTypes &Types = CGM.getTypes(); - llvm::Value *Arg0 = Receiver; - if (!IsSuper) - Arg0 = CGF.Builder.CreateBitCast(Arg0, ObjCTypes.ObjectPtrTy, "tmp"); +static void appendSelectorForMessageRefTable(std::string &buffer, + Selector selector) { + if (selector.isUnarySelector()) { + buffer += selector.getNameForSlot(0); + return; + } - // Find the message function name. - // FIXME. This is too much work to get the ABI-specific result type needed to - // find the message name. - const CGFunctionInfo &FnInfo - = Types.getFunctionInfo(ResultType, CallArgList(), - FunctionType::ExtInfo()); - llvm::Constant *Fn = 0; - std::string Name("\01l_"); - if (CGM.ReturnTypeUsesSRet(FnInfo)) { - EmitNullReturnInitialization(CGF, Return, ResultType); - if (IsSuper) { - Fn = ObjCTypes.getMessageSendSuper2StretFixupFn(); - Name += "objc_msgSendSuper2_stret_fixup"; + for (unsigned i = 0, e = selector.getNumArgs(); i != e; ++i) { + buffer += selector.getNameForSlot(i); + buffer += '_'; + } +} + +/// Emit a "v-table" message send. We emit a weak hidden-visibility +/// struct, initially containing the selector pointer and a pointer to +/// a "fixup" variant of the appropriate objc_msgSend. To call, we +/// load and call the function pointer, passing the address of the +/// struct as the second parameter. The runtime determines whether +/// the selector is currently emitted using vtable dispatch; if so, it +/// substitutes a stub function which simply tail-calls through the +/// appropriate vtable slot, and if not, it substitues a stub function +/// which tail-calls objc_msgSend. Both stubs adjust the selector +/// argument to correctly point to the selector. +RValue +CGObjCNonFragileABIMac::EmitVTableMessageSend(CodeGenFunction &CGF, + ReturnValueSlot returnSlot, + QualType resultType, + Selector selector, + llvm::Value *arg0, + QualType arg0Type, + bool isSuper, + const CallArgList &formalArgs, + const ObjCMethodDecl *method) { + // Compute the actual arguments. + CallArgList args; + + // First argument: the receiver / super-call structure. + if (!isSuper) + arg0 = CGF.Builder.CreateBitCast(arg0, ObjCTypes.ObjectPtrTy); + args.add(RValue::get(arg0), arg0Type); + + // Second argument: a pointer to the message ref structure. Leave + // the actual argument value blank for now. + args.add(RValue::get(0), ObjCTypes.MessageRefCPtrTy); + + args.insert(args.end(), formalArgs.begin(), formalArgs.end()); + + const CGFunctionInfo &fnInfo = + CGM.getTypes().getFunctionInfo(resultType, args, + FunctionType::ExtInfo()); + + NullReturnState nullReturn; + + // Find the function to call and the mangled name for the message + // ref structure. Using a different mangled name wouldn't actually + // be a problem; it would just be a waste. + // + // The runtime currently never uses vtable dispatch for anything + // except normal, non-super message-sends. + // FIXME: don't use this for that. + llvm::Constant *fn = 0; + std::string messageRefName("\01l_"); + if (CGM.ReturnTypeUsesSRet(fnInfo)) { + if (isSuper) { + fn = ObjCTypes.getMessageSendSuper2StretFixupFn(); + messageRefName += "objc_msgSendSuper2_stret_fixup"; } else { - Fn = ObjCTypes.getMessageSendStretFixupFn(); - Name += "objc_msgSend_stret_fixup"; + nullReturn.init(CGF, arg0); + fn = ObjCTypes.getMessageSendStretFixupFn(); + messageRefName += "objc_msgSend_stret_fixup"; } - } else if (!IsSuper && CGM.ReturnTypeUsesFPRet(ResultType)) { - Fn = ObjCTypes.getMessageSendFpretFixupFn(); - Name += "objc_msgSend_fpret_fixup"; + } else if (!isSuper && CGM.ReturnTypeUsesFPRet(resultType)) { + fn = ObjCTypes.getMessageSendFpretFixupFn(); + messageRefName += "objc_msgSend_fpret_fixup"; } else { - if (IsSuper) { - Fn = ObjCTypes.getMessageSendSuper2FixupFn(); - Name += "objc_msgSendSuper2_fixup"; + if (isSuper) { + fn = ObjCTypes.getMessageSendSuper2FixupFn(); + messageRefName += "objc_msgSendSuper2_fixup"; } else { - Fn = ObjCTypes.getMessageSendFixupFn(); - Name += "objc_msgSend_fixup"; + fn = ObjCTypes.getMessageSendFixupFn(); + messageRefName += "objc_msgSend_fixup"; } } - assert(Fn && "CGObjCNonFragileABIMac::EmitMessageSend"); - Name += '_'; - std::string SelName(Sel.getAsString()); - // Replace all ':' in selector name with '_' ouch! - for (unsigned i = 0; i < SelName.size(); i++) - if (SelName[i] == ':') - SelName[i] = '_'; - Name += SelName; - llvm::GlobalVariable *GV = CGM.getModule().getGlobalVariable(Name); - if (!GV) { - // Build message ref table entry. - std::vector<llvm::Constant*> Values(2); - Values[0] = Fn; - Values[1] = GetMethodVarName(Sel); - llvm::Constant *Init = llvm::ConstantStruct::get(VMContext, Values, false); - GV = new llvm::GlobalVariable(CGM.getModule(), Init->getType(), false, - llvm::GlobalValue::WeakAnyLinkage, - Init, - Name); - GV->setVisibility(llvm::GlobalValue::HiddenVisibility); - GV->setAlignment(16); - GV->setSection("__DATA, __objc_msgrefs, coalesced"); - } - llvm::Value *Arg1 = CGF.Builder.CreateBitCast(GV, ObjCTypes.MessageRefPtrTy); - - CallArgList ActualArgs; - ActualArgs.add(RValue::get(Arg0), Arg0Ty); - ActualArgs.add(RValue::get(Arg1), ObjCTypes.MessageRefCPtrTy); - ActualArgs.insert(ActualArgs.end(), CallArgs.begin(), CallArgs.end()); - const CGFunctionInfo &FnInfo1 = Types.getFunctionInfo(ResultType, ActualArgs, - FunctionType::ExtInfo()); - llvm::Value *Callee = CGF.Builder.CreateStructGEP(Arg1, 0); - Callee = CGF.Builder.CreateLoad(Callee); - const llvm::FunctionType *FTy = - Types.GetFunctionType(FnInfo1, Method ? Method->isVariadic() : false); - Callee = CGF.Builder.CreateBitCast(Callee, - llvm::PointerType::getUnqual(FTy)); - return CGF.EmitCall(FnInfo1, Callee, Return, ActualArgs); + assert(fn && "CGObjCNonFragileABIMac::EmitMessageSend"); + messageRefName += '_'; + + // Append the selector name, except use underscores anywhere we + // would have used colons. + appendSelectorForMessageRefTable(messageRefName, selector); + + llvm::GlobalVariable *messageRef + = CGM.getModule().getGlobalVariable(messageRefName); + if (!messageRef) { + // Build the message ref structure. + llvm::Constant *values[] = { fn, GetMethodVarName(selector) }; + llvm::Constant *init = + llvm::ConstantStruct::get(VMContext, values, 2, false); + messageRef = new llvm::GlobalVariable(CGM.getModule(), + init->getType(), + /*constant*/ false, + llvm::GlobalValue::WeakAnyLinkage, + init, + messageRefName); + messageRef->setVisibility(llvm::GlobalValue::HiddenVisibility); + messageRef->setAlignment(16); + messageRef->setSection("__DATA, __objc_msgrefs, coalesced"); + } + llvm::Value *mref = + CGF.Builder.CreateBitCast(messageRef, ObjCTypes.MessageRefPtrTy); + + // Update the message ref argument. + args[1].RV = RValue::get(mref); + + // Load the function to call from the message ref table. + llvm::Value *callee = CGF.Builder.CreateStructGEP(mref, 0); + callee = CGF.Builder.CreateLoad(callee, "msgSend_fn"); + + bool variadic = method ? method->isVariadic() : false; + const llvm::FunctionType *fnType = + CGF.getTypes().GetFunctionType(fnInfo, variadic); + callee = CGF.Builder.CreateBitCast(callee, + llvm::PointerType::getUnqual(fnType)); + + RValue result = CGF.EmitCall(fnInfo, callee, returnSlot, args); + return nullReturn.complete(CGF, result, resultType); } /// Generate code for a message send expression in the nonfragile abi. @@ -5619,14 +5696,14 @@ CGObjCNonFragileABIMac::GenerateMessageSend(CodeGen::CodeGenFunction &CGF, const CallArgList &CallArgs, const ObjCInterfaceDecl *Class, const ObjCMethodDecl *Method) { - return LegacyDispatchedSelector(Sel) - ? EmitLegacyMessageSend(CGF, Return, ResultType, - EmitSelector(CGF.Builder, Sel), + return isVTableDispatchedSelector(Sel) + ? EmitVTableMessageSend(CGF, Return, ResultType, Sel, Receiver, CGF.getContext().getObjCIdType(), - false, CallArgs, Method, ObjCTypes) - : EmitMessageSend(CGF, Return, ResultType, Sel, + false, CallArgs, Method) + : EmitMessageSend(CGF, Return, ResultType, + EmitSelector(CGF.Builder, Sel), Receiver, CGF.getContext().getObjCIdType(), - false, CallArgs, Method); + false, CallArgs, Method, ObjCTypes); } llvm::GlobalVariable * @@ -5773,14 +5850,14 @@ CGObjCNonFragileABIMac::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF, CGF.Builder.CreateStore(Target, CGF.Builder.CreateStructGEP(ObjCSuper, 1)); - return (LegacyDispatchedSelector(Sel)) - ? EmitLegacyMessageSend(CGF, Return, ResultType, - EmitSelector(CGF.Builder, Sel), + return (isVTableDispatchedSelector(Sel)) + ? EmitVTableMessageSend(CGF, Return, ResultType, Sel, ObjCSuper, ObjCTypes.SuperPtrCTy, - true, CallArgs, Method, ObjCTypes) - : EmitMessageSend(CGF, Return, ResultType, Sel, + true, CallArgs, Method) + : EmitMessageSend(CGF, Return, ResultType, + EmitSelector(CGF.Builder, Sel), ObjCSuper, ObjCTypes.SuperPtrCTy, - true, CallArgs, Method); + true, CallArgs, Method, ObjCTypes); } llvm::Value *CGObjCNonFragileABIMac::EmitSelector(CGBuilderTy &Builder, diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGObjCRuntime.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGObjCRuntime.cpp index 3d854d4..21150f1 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGObjCRuntime.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGObjCRuntime.cpp @@ -165,9 +165,9 @@ namespace { void CGObjCRuntime::EmitTryCatchStmt(CodeGenFunction &CGF, const ObjCAtTryStmt &S, - llvm::Function *beginCatchFn, - llvm::Function *endCatchFn, - llvm::Function *exceptionRethrowFn) { + llvm::Constant *beginCatchFn, + llvm::Constant *endCatchFn, + llvm::Constant *exceptionRethrowFn) { // Jump destination for falling out of catch bodies. CodeGenFunction::JumpDest Cont; if (S.getNumCatchStmts()) @@ -233,6 +233,8 @@ void CGObjCRuntime::EmitTryCatchStmt(CodeGenFunction &CGF, cast<llvm::CallInst>(Exn)->setDoesNotThrow(); } + CodeGenFunction::RunCleanupsScope cleanups(CGF); + if (endCatchFn) { // Add a cleanup to leave the catch. bool EndCatchMightThrow = (Handler.Variable == 0); @@ -255,9 +257,8 @@ void CGObjCRuntime::EmitTryCatchStmt(CodeGenFunction &CGF, CGF.EmitStmt(Handler.Body); CGF.ObjCEHValueStack.pop_back(); - // Leave the earlier cleanup. - if (endCatchFn) - CGF.PopCleanupBlock(); + // Leave any cleanups associated with the catch. + cleanups.ForceCleanup(); CGF.EmitBranchThroughCleanup(Cont); } diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGObjCRuntime.h b/contrib/llvm/tools/clang/lib/CodeGen/CGObjCRuntime.h index 0cc2d82..866d5d8 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGObjCRuntime.h +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGObjCRuntime.h @@ -95,9 +95,9 @@ protected: /// thrown object directly. void EmitTryCatchStmt(CodeGenFunction &CGF, const ObjCAtTryStmt &S, - llvm::Function *beginCatchFn, - llvm::Function *endCatchFn, - llvm::Function *exceptionRethrowFn); + llvm::Constant *beginCatchFn, + llvm::Constant *endCatchFn, + llvm::Constant *exceptionRethrowFn); /// Emits an @synchronize() statement, using the syncEnterFn and syncExitFn /// arguments as the functions called to lock and unlock the object. This /// function can be called by subclasses that use zero-cost exception @@ -243,6 +243,7 @@ public: llvm::Value *Size) = 0; virtual llvm::Constant *BuildGCBlockLayout(CodeGen::CodeGenModule &CGM, const CodeGen::CGBlockInfo &blockInfo) = 0; + virtual llvm::GlobalVariable *GetClassGlobal(const std::string &Name) = 0; }; /// Creates an instance of an Objective-C runtime class. diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp index a4ac390..0d72f85 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp @@ -234,7 +234,7 @@ CGBitFieldInfo CGBitFieldInfo::MakeInfo(CodeGenTypes &Types, CharUnits::fromQuantity(Types.getTargetData().getTypeAllocSize(Ty)); uint64_t TypeSizeInBits = Types.getContext().toBits(TypeSizeInBytes); - bool IsSigned = FD->getType()->isSignedIntegerType(); + bool IsSigned = FD->getType()->isSignedIntegerOrEnumerationType(); if (FieldSize > TypeSizeInBits) { // We have a wide bit-field. The extra bits are only used for padding, so @@ -753,8 +753,7 @@ bool CGRecordLayoutBuilder::LayoutFields(const RecordDecl *D) { // Zero-length bitfields following non-bitfield members are // ignored: const FieldDecl *FD = (*Field); - if (Types.getContext().ZeroBitfieldFollowsNonBitfield(FD, LastFD) || - Types.getContext().ZeroBitfieldFollowsBitfield(FD, LastFD)) { + if (Types.getContext().ZeroBitfieldFollowsNonBitfield(FD, LastFD)) { --FieldNo; continue; } @@ -997,8 +996,7 @@ CGRecordLayout *CodeGenTypes::ComputeRecordLayout(const RecordDecl *D) { if (IsMsStruct) { // Zero-length bitfields following non-bitfield members are // ignored: - if (getContext().ZeroBitfieldFollowsNonBitfield(FD, LastFD) || - getContext().ZeroBitfieldFollowsBitfield(FD, LastFD)) { + if (getContext().ZeroBitfieldFollowsNonBitfield(FD, LastFD)) { --i; continue; } diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGStmt.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGStmt.cpp index 99bc3f4..a982621 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGStmt.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGStmt.cpp @@ -773,10 +773,8 @@ void CodeGenFunction::EmitReturnStmt(const ReturnStmt &S) { void CodeGenFunction::EmitDeclStmt(const DeclStmt &S) { // As long as debug info is modeled with instructions, we have to ensure we // have a place to insert here and write the stop point here. - if (getDebugInfo()) { - EnsureInsertPoint(); + if (getDebugInfo() && HaveInsertPoint()) EmitStopPoint(&S); - } for (DeclStmt::const_decl_iterator I = S.decl_begin(), E = S.decl_end(); I != E; ++I) @@ -999,7 +997,7 @@ static CSFC_Result CollectStatementsForCase(const Stmt *S, // If we're looking for the case, just see if we can skip each of the // substatements. for (; Case && I != E; ++I) { - HadSkippedDecl |= isa<DeclStmt>(I); + HadSkippedDecl |= isa<DeclStmt>(*I); switch (CollectStatementsForCase(*I, Case, FoundCase, ResultStmts)) { case CSFC_Failure: return CSFC_Failure; @@ -1224,7 +1222,7 @@ SimplifyConstraint(const char *Constraint, const TargetInfo &Target, while (*Constraint) { switch (*Constraint) { default: - Result += Target.convertConstraint(*Constraint); + Result += Target.convertConstraint(Constraint); break; // Ignore these case '*': @@ -1422,8 +1420,8 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { const Expr *OutExpr = S.getOutputExpr(i); OutExpr = OutExpr->IgnoreParenNoopCasts(getContext()); - OutputConstraint = AddVariableConstraints(OutputConstraint, *OutExpr, Target, - CGM, S); + OutputConstraint = AddVariableConstraints(OutputConstraint, *OutExpr, + Target, CGM, S); LValue Dest = EmitLValue(OutExpr); if (!Constraints.empty()) diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGVTT.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGVTT.cpp index a6849f8..aefc41e 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGVTT.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGVTT.cpp @@ -411,6 +411,8 @@ llvm::GlobalVariable *CodeGenVTables::GetAddrOfVTT(const CXXRecordDecl *RD) { Out.flush(); llvm::StringRef Name = OutName.str(); + ComputeVTableRelatedInformation(RD, /*VTableRequired=*/true); + VTTBuilder Builder(CGM, RD, /*GenerateDefinition=*/false); const llvm::Type *Int8PtrTy = diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGVTables.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGVTables.cpp index 581467c..9ac5e67 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGVTables.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGVTables.cpp @@ -21,6 +21,7 @@ #include "llvm/ADT/SetVector.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/Format.h" +#include "llvm/Transforms/Utils/Cloning.h" #include <algorithm> #include <cstdio> @@ -2636,6 +2637,131 @@ static bool similar(const ABIArgInfo &infoL, CanQualType typeL, } #endif +static RValue PerformReturnAdjustment(CodeGenFunction &CGF, + QualType ResultType, RValue RV, + const ThunkInfo &Thunk) { + // Emit the return adjustment. + bool NullCheckValue = !ResultType->isReferenceType(); + + llvm::BasicBlock *AdjustNull = 0; + llvm::BasicBlock *AdjustNotNull = 0; + llvm::BasicBlock *AdjustEnd = 0; + + llvm::Value *ReturnValue = RV.getScalarVal(); + + if (NullCheckValue) { + AdjustNull = CGF.createBasicBlock("adjust.null"); + AdjustNotNull = CGF.createBasicBlock("adjust.notnull"); + AdjustEnd = CGF.createBasicBlock("adjust.end"); + + llvm::Value *IsNull = CGF.Builder.CreateIsNull(ReturnValue); + CGF.Builder.CreateCondBr(IsNull, AdjustNull, AdjustNotNull); + CGF.EmitBlock(AdjustNotNull); + } + + ReturnValue = PerformTypeAdjustment(CGF, ReturnValue, + Thunk.Return.NonVirtual, + Thunk.Return.VBaseOffsetOffset); + + if (NullCheckValue) { + CGF.Builder.CreateBr(AdjustEnd); + CGF.EmitBlock(AdjustNull); + CGF.Builder.CreateBr(AdjustEnd); + CGF.EmitBlock(AdjustEnd); + + llvm::PHINode *PHI = CGF.Builder.CreatePHI(ReturnValue->getType(), 2); + PHI->addIncoming(ReturnValue, AdjustNotNull); + PHI->addIncoming(llvm::Constant::getNullValue(ReturnValue->getType()), + AdjustNull); + ReturnValue = PHI; + } + + return RValue::get(ReturnValue); +} + +// This function does roughly the same thing as GenerateThunk, but in a +// very different way, so that va_start and va_end work correctly. +// FIXME: This function assumes "this" is the first non-sret LLVM argument of +// a function, and that there is an alloca built in the entry block +// for all accesses to "this". +// FIXME: This function assumes there is only one "ret" statement per function. +// FIXME: Cloning isn't correct in the presence of indirect goto! +// FIXME: This implementation of thunks bloats codesize by duplicating the +// function definition. There are alternatives: +// 1. Add some sort of stub support to LLVM for cases where we can +// do a this adjustment, then a sibcall. +// 2. We could transform the definition to take a va_list instead of an +// actual variable argument list, then have the thunks (including a +// no-op thunk for the regular definition) call va_start/va_end. +// There's a bit of per-call overhead for this solution, but it's +// better for codesize if the definition is long. +void CodeGenFunction::GenerateVarArgsThunk( + llvm::Function *Fn, + const CGFunctionInfo &FnInfo, + GlobalDecl GD, const ThunkInfo &Thunk) { + const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl()); + const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>(); + QualType ResultType = FPT->getResultType(); + + // Get the original function + const llvm::Type *Ty = + CGM.getTypes().GetFunctionType(FnInfo, /*IsVariadic*/true); + llvm::Value *Callee = CGM.GetAddrOfFunction(GD, Ty, /*ForVTable=*/true); + llvm::Function *BaseFn = cast<llvm::Function>(Callee); + + // Clone to thunk. + llvm::Function *NewFn = llvm::CloneFunction(BaseFn); + CGM.getModule().getFunctionList().push_back(NewFn); + Fn->replaceAllUsesWith(NewFn); + NewFn->takeName(Fn); + Fn->eraseFromParent(); + Fn = NewFn; + + // "Initialize" CGF (minimally). + CurFn = Fn; + + // Get the "this" value + llvm::Function::arg_iterator AI = Fn->arg_begin(); + if (CGM.ReturnTypeUsesSRet(FnInfo)) + ++AI; + + // Find the first store of "this", which will be to the alloca associated + // with "this". + llvm::Value *ThisPtr = &*AI; + llvm::BasicBlock *EntryBB = Fn->begin(); + llvm::Instruction *ThisStore = 0; + for (llvm::BasicBlock::iterator I = EntryBB->begin(), E = EntryBB->end(); + I != E; I++) { + if (isa<llvm::StoreInst>(I) && I->getOperand(0) == ThisPtr) { + ThisStore = cast<llvm::StoreInst>(I); + break; + } + } + assert(ThisStore && "Store of this should be in entry block?"); + // Adjust "this", if necessary. + Builder.SetInsertPoint(ThisStore); + llvm::Value *AdjustedThisPtr = + PerformTypeAdjustment(*this, ThisPtr, + Thunk.This.NonVirtual, + Thunk.This.VCallOffsetOffset); + ThisStore->setOperand(0, AdjustedThisPtr); + + if (!Thunk.Return.isEmpty()) { + // Fix up the returned value, if necessary. + for (llvm::Function::iterator I = Fn->begin(), E = Fn->end(); I != E; I++) { + llvm::Instruction *T = I->getTerminator(); + if (isa<llvm::ReturnInst>(T)) { + RValue RV = RValue::get(T->getOperand(0)); + T->eraseFromParent(); + Builder.SetInsertPoint(&*I); + RV = PerformReturnAdjustment(*this, ResultType, RV, Thunk); + Builder.CreateRet(RV.getScalarVal()); + break; + } + } + } +} + void CodeGenFunction::GenerateThunk(llvm::Function *Fn, const CGFunctionInfo &FnInfo, GlobalDecl GD, const ThunkInfo &Thunk) { @@ -2715,45 +2841,8 @@ void CodeGenFunction::GenerateThunk(llvm::Function *Fn, // Now emit our call. RValue RV = EmitCall(FnInfo, Callee, Slot, CallArgs, MD); - if (!Thunk.Return.isEmpty()) { - // Emit the return adjustment. - bool NullCheckValue = !ResultType->isReferenceType(); - - llvm::BasicBlock *AdjustNull = 0; - llvm::BasicBlock *AdjustNotNull = 0; - llvm::BasicBlock *AdjustEnd = 0; - - llvm::Value *ReturnValue = RV.getScalarVal(); - - if (NullCheckValue) { - AdjustNull = createBasicBlock("adjust.null"); - AdjustNotNull = createBasicBlock("adjust.notnull"); - AdjustEnd = createBasicBlock("adjust.end"); - - llvm::Value *IsNull = Builder.CreateIsNull(ReturnValue); - Builder.CreateCondBr(IsNull, AdjustNull, AdjustNotNull); - EmitBlock(AdjustNotNull); - } - - ReturnValue = PerformTypeAdjustment(*this, ReturnValue, - Thunk.Return.NonVirtual, - Thunk.Return.VBaseOffsetOffset); - - if (NullCheckValue) { - Builder.CreateBr(AdjustEnd); - EmitBlock(AdjustNull); - Builder.CreateBr(AdjustEnd); - EmitBlock(AdjustEnd); - - llvm::PHINode *PHI = Builder.CreatePHI(ReturnValue->getType(), 2); - PHI->addIncoming(ReturnValue, AdjustNotNull); - PHI->addIncoming(llvm::Constant::getNullValue(ReturnValue->getType()), - AdjustNull); - ReturnValue = PHI; - } - - RV = RValue::get(ReturnValue); - } + if (!Thunk.Return.isEmpty()) + RV = PerformReturnAdjustment(*this, ResultType, RV, Thunk); if (!ResultType->isVoidType() && Slot.isNull()) CGM.getCXXABI().EmitReturnFromThunk(*this, RV, ResultType); @@ -2823,8 +2912,18 @@ void CodeGenVTables::EmitThunk(GlobalDecl GD, const ThunkInfo &Thunk, return; } - // Actually generate the thunk body. - CodeGenFunction(CGM).GenerateThunk(ThunkFn, FnInfo, GD, Thunk); + if (ThunkFn->isVarArg()) { + // Varargs thunks are special; we can't just generate a call because + // we can't copy the varargs. Our implementation is rather + // expensive/sucky at the moment, so don't generate the thunk unless + // we have to. + // FIXME: Do something better here; GenerateVarArgsThunk is extremely ugly. + if (!UseAvailableExternallyLinkage) + CodeGenFunction(CGM).GenerateVarArgsThunk(ThunkFn, FnInfo, GD, Thunk); + } else { + // Normal thunk body generation. + CodeGenFunction(CGM).GenerateThunk(ThunkFn, FnInfo, GD, Thunk); + } if (UseAvailableExternallyLinkage) ThunkFn->setLinkage(llvm::GlobalValue::AvailableExternallyLinkage); @@ -3076,7 +3175,7 @@ llvm::GlobalVariable *CodeGenVTables::GetAddrOfVTable(const CXXRecordDecl *RD) { Out.flush(); llvm::StringRef Name = OutName.str(); - ComputeVTableRelatedInformation(RD, true); + ComputeVTableRelatedInformation(RD, /*VTableRequired=*/true); const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGM.getLLVMContext()); llvm::ArrayType *ArrayType = diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenFunction.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenFunction.cpp index 626c2b0..150cb69 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenFunction.cpp @@ -33,9 +33,9 @@ CodeGenFunction::CodeGenFunction(CodeGenModule &cgm) Target(CGM.getContext().Target), Builder(cgm.getModule().getContext()), BlockInfo(0), BlockPointer(0), NormalCleanupDest(0), EHCleanupDest(0), NextCleanupDestIndex(1), - ExceptionSlot(0), DebugInfo(0), DisableDebugInfo(false), IndirectBranch(0), - SwitchInsn(0), CaseRangeBlock(0), - DidCallStackSave(false), UnreachableBlock(0), + ExceptionSlot(0), EHSelectorSlot(0), + DebugInfo(0), DisableDebugInfo(false), DidCallStackSave(false), + IndirectBranch(0), SwitchInsn(0), CaseRangeBlock(0), UnreachableBlock(0), CXXThisDecl(0), CXXThisValue(0), CXXVTTDecl(0), CXXVTTValue(0), OutermostConditional(0), TerminateLandingPad(0), TerminateHandler(0), TrapBB(0) { @@ -44,10 +44,6 @@ CodeGenFunction::CodeGenFunction(CodeGenModule &cgm) CGM.getCXXABI().getMangleContext().startNewFunction(); } -ASTContext &CodeGenFunction::getContext() const { - return CGM.getContext(); -} - const llvm::Type *CodeGenFunction::ConvertTypeForMem(QualType T) { return CGM.getTypes().ConvertTypeForMem(T); @@ -57,9 +53,41 @@ const llvm::Type *CodeGenFunction::ConvertType(QualType T) { return CGM.getTypes().ConvertType(T); } -bool CodeGenFunction::hasAggregateLLVMType(QualType T) { - return T->isRecordType() || T->isArrayType() || T->isAnyComplexType() || - T->isObjCObjectType(); +bool CodeGenFunction::hasAggregateLLVMType(QualType type) { + switch (type.getCanonicalType()->getTypeClass()) { +#define TYPE(name, parent) +#define ABSTRACT_TYPE(name, parent) +#define NON_CANONICAL_TYPE(name, parent) case Type::name: +#define DEPENDENT_TYPE(name, parent) case Type::name: +#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(name, parent) case Type::name: +#include "clang/AST/TypeNodes.def" + llvm_unreachable("non-canonical or dependent type in IR-generation"); + + case Type::Builtin: + case Type::Pointer: + case Type::BlockPointer: + case Type::LValueReference: + case Type::RValueReference: + case Type::MemberPointer: + case Type::Vector: + case Type::ExtVector: + case Type::FunctionProto: + case Type::FunctionNoProto: + case Type::Enum: + case Type::ObjCObjectPointer: + return false; + + // Complexes, arrays, records, and Objective-C objects. + case Type::Complex: + case Type::ConstantArray: + case Type::IncompleteArray: + case Type::VariableArray: + case Type::Record: + case Type::ObjCObject: + case Type::ObjCInterface: + return true; + } + llvm_unreachable("unknown type kind!"); } void CodeGenFunction::EmitReturnBlock() { @@ -168,7 +196,7 @@ void CodeGenFunction::FinishFunction(SourceLocation EndLoc) { bool CodeGenFunction::ShouldInstrumentFunction() { if (!CGM.getCodeGenOpts().InstrumentFunctions) return false; - if (CurFuncDecl->hasAttr<NoInstrumentFunctionAttr>()) + if (!CurFuncDecl || CurFuncDecl->hasAttr<NoInstrumentFunctionAttr>()) return false; return true; } @@ -177,16 +205,12 @@ bool CodeGenFunction::ShouldInstrumentFunction() { /// instrumentation function with the current function and the call site, if /// function instrumentation is enabled. void CodeGenFunction::EmitFunctionInstrumentation(const char *Fn) { - const llvm::PointerType *PointerTy; - const llvm::FunctionType *FunctionTy; - std::vector<const llvm::Type*> ProfileFuncArgs; - // void __cyg_profile_func_{enter,exit} (void *this_fn, void *call_site); - PointerTy = Int8PtrTy; - ProfileFuncArgs.push_back(PointerTy); - ProfileFuncArgs.push_back(PointerTy); - FunctionTy = llvm::FunctionType::get(llvm::Type::getVoidTy(getLLVMContext()), - ProfileFuncArgs, false); + const llvm::PointerType *PointerTy = Int8PtrTy; + const llvm::Type *ProfileFuncArgs[] = { PointerTy, PointerTy }; + const llvm::FunctionType *FunctionTy = + llvm::FunctionType::get(llvm::Type::getVoidTy(getLLVMContext()), + ProfileFuncArgs, false); llvm::Constant *F = CGM.CreateRuntimeFunction(FunctionTy, Fn); llvm::CallInst *CallSite = Builder.CreateCall( diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenFunction.h b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenFunction.h index 169c576..bb8fd8e 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenFunction.h +++ b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenFunction.h @@ -603,6 +603,10 @@ public: /// exception pointer into this alloca. llvm::Value *ExceptionSlot; + /// The selector slot. Under the MandatoryCleanup model, all + /// landing pads write the current selector value into this alloca. + llvm::AllocaInst *EHSelectorSlot; + /// Emits a landing pad for the current EH stack. llvm::BasicBlock *EmitLandingPad(); @@ -951,6 +955,10 @@ private: CGDebugInfo *DebugInfo; bool DisableDebugInfo; + /// DidCallStackSave - Whether llvm.stacksave has been called. Used to avoid + /// calling llvm.stacksave for multiple VLAs in the same scope. + bool DidCallStackSave; + /// IndirectBranch - The first time an indirect goto is seen we create a block /// with an indirect branch. Every time we see the address of a label taken, /// we add the label to the indirect goto. Every subsequent indirect goto is @@ -997,10 +1005,6 @@ private: // enter/leave scopes. llvm::DenseMap<const Expr*, llvm::Value*> VLASizeMap; - /// DidCallStackSave - Whether llvm.stacksave has been called. Used to avoid - /// calling llvm.stacksave for multiple VLAs in the same scope. - bool DidCallStackSave; - /// A block containing a single 'unreachable' instruction. Created /// lazily by getUnreachableBlock(). llvm::BasicBlock *UnreachableBlock; @@ -1035,7 +1039,7 @@ public: CodeGenFunction(CodeGenModule &cgm); CodeGenTypes &getTypes() const { return CGM.getTypes(); } - ASTContext &getContext() const; + ASTContext &getContext() const { return CGM.getContext(); } CGDebugInfo *getDebugInfo() { if (DisableDebugInfo) return NULL; @@ -1050,6 +1054,7 @@ public: /// Returns a pointer to the function's exception object slot, which /// is assigned in every landing pad. llvm::Value *getExceptionSlot(); + llvm::Value *getEHSelectorSlot(); llvm::Value *getNormalCleanupDestSlot(); llvm::Value *getEHCleanupDestSlot(); @@ -1076,7 +1081,8 @@ public: void GenerateObjCMethod(const ObjCMethodDecl *OMD); void StartObjCMethod(const ObjCMethodDecl *MD, - const ObjCContainerDecl *CD); + const ObjCContainerDecl *CD, + SourceLocation StartLoc); /// GenerateObjCGetter - Synthesize an Objective-C property getter function. void GenerateObjCGetter(ObjCImplementationDecl *IMP, @@ -1157,6 +1163,9 @@ public: void GenerateThunk(llvm::Function *Fn, const CGFunctionInfo &FnInfo, GlobalDecl GD, const ThunkInfo &Thunk); + void GenerateVarArgsThunk(llvm::Function *Fn, const CGFunctionInfo &FnInfo, + GlobalDecl GD, const ThunkInfo &Thunk); + void EmitCtorPrologue(const CXXConstructorDecl *CD, CXXCtorType Type, FunctionArgList &Args); @@ -1701,6 +1710,7 @@ public: void EmitObjCAtThrowStmt(const ObjCAtThrowStmt &S); void EmitObjCAtSynchronizedStmt(const ObjCAtSynchronizedStmt &S); + llvm::Constant *getUnwindResumeFn(); llvm::Constant *getUnwindResumeOrRethrowFn(); void EnterCXXTryStmt(const CXXTryStmt &S, bool IsFnTryBlock = false); void ExitCXXTryStmt(const CXXTryStmt &S, bool IsFnTryBlock = false); @@ -1915,6 +1925,9 @@ public: RValue EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E, ReturnValueSlot ReturnValue); + llvm::Value *EmitCXXOperatorMemberCallee(const CXXOperatorCallExpr *E, + const CXXMethodDecl *MD, + llvm::Value *This); RValue EmitCXXOperatorMemberCallExpr(const CXXOperatorCallExpr *E, const CXXMethodDecl *MD, ReturnValueSlot ReturnValue); diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenModule.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenModule.cpp index 83e927f..7a1a968 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenModule.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenModule.cpp @@ -90,9 +90,10 @@ CodeGenModule::CodeGenModule(ASTContext &C, const CodeGenOptions &CGO, // Initialize the type cache. llvm::LLVMContext &LLVMContext = M.getContext(); - Int8Ty = llvm::Type::getInt8Ty(LLVMContext); - Int32Ty = llvm::Type::getInt32Ty(LLVMContext); - Int64Ty = llvm::Type::getInt64Ty(LLVMContext); + VoidTy = llvm::Type::getVoidTy(LLVMContext); + Int8Ty = llvm::Type::getInt8Ty(LLVMContext); + Int32Ty = llvm::Type::getInt32Ty(LLVMContext); + Int64Ty = llvm::Type::getInt64Ty(LLVMContext); PointerWidthInBits = C.Target.getPointerWidth(0); PointerAlignInBytes = C.toCharUnitsFromBits(C.Target.getPointerAlign(0)).getQuantity(); @@ -132,6 +133,9 @@ void CodeGenModule::Release() { if (getCodeGenOpts().EmitDeclMetadata) EmitDeclMetadata(); + + if (getCodeGenOpts().EmitGcovArcs || getCodeGenOpts().EmitGcovNotes) + EmitCoverageFile(); } void CodeGenModule::UpdateCompletedType(const TagDecl *TD) { @@ -339,8 +343,7 @@ void CodeGenModule::AddGlobalDtor(llvm::Function * Dtor, int Priority) { void CodeGenModule::EmitCtorList(const CtorList &Fns, const char *GlobalName) { // Ctor function type is void()*. - llvm::FunctionType* CtorFTy = - llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), false); + llvm::FunctionType* CtorFTy = llvm::FunctionType::get(VoidTy, false); llvm::Type *CtorPFTy = llvm::PointerType::getUnqual(CtorFTy); // Get the type of a ctor entry, { i32, void ()* }. @@ -449,6 +452,9 @@ void CodeGenModule::SetLLVMFunctionAttributes(const Decl *D, void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D, llvm::Function *F) { + if (CodeGenOpts.UnwindTables) + F->setHasUWTable(); + if (!Features.Exceptions && !Features.ObjCNonFragileABI) F->addFnAttr(llvm::Attribute::NoUnwind); @@ -724,7 +730,7 @@ void CodeGenModule::EmitGlobal(GlobalDecl GD) { } // Forward declarations are emitted lazily on first use. - if (!FD->isThisDeclarationADefinition()) + if (!FD->doesThisDeclarationHaveABody()) return; } else { const VarDecl *VD = cast<VarDecl>(Global); @@ -790,14 +796,19 @@ void CodeGenModule::EmitGlobalDefinition(GlobalDecl GD) { return; if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) { + // Make sure to emit the definition(s) before we emit the thunks. + // This is necessary for the generation of certain thunks. + if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(Method)) + EmitCXXConstructor(CD, GD.getCtorType()); + else if (const CXXDestructorDecl *DD =dyn_cast<CXXDestructorDecl>(Method)) + EmitCXXDestructor(DD, GD.getDtorType()); + else + EmitGlobalFunctionDefinition(GD); + if (Method->isVirtual()) getVTables().EmitThunks(GD); - if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(Method)) - return EmitCXXConstructor(CD, GD.getCtorType()); - - if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(Method)) - return EmitCXXDestructor(DD, GD.getDtorType()); + return; } return EmitGlobalFunctionDefinition(GD); @@ -848,7 +859,7 @@ CodeGenModule::GetOrCreateLLVMFunction(llvm::StringRef MangledName, if (isa<llvm::FunctionType>(Ty)) { FTy = cast<llvm::FunctionType>(Ty); } else { - FTy = llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), false); + FTy = llvm::FunctionType::get(VoidTy, false); IsIncompleteFunction = true; } @@ -889,7 +900,7 @@ CodeGenModule::GetOrCreateLLVMFunction(llvm::StringRef MangledName, assert(FD->isUsed() && "Sema didn't mark implicit function as used!"); DeferredDeclsToEmit.push_back(D.getWithDecl(FD)); break; - } else if (FD->isThisDeclarationADefinition()) { + } else if (FD->doesThisDeclarationHaveABody()) { DeferredDeclsToEmit.push_back(D.getWithDecl(FD)); break; } @@ -930,14 +941,19 @@ CodeGenModule::CreateRuntimeFunction(const llvm::FunctionType *FTy, return GetOrCreateLLVMFunction(Name, FTy, GlobalDecl(), /*ForVTable=*/false); } -static bool DeclIsConstantGlobal(ASTContext &Context, const VarDecl *D) { +static bool DeclIsConstantGlobal(ASTContext &Context, const VarDecl *D, + bool ConstantInit) { if (!D->getType().isConstant(Context) && !D->getType()->isReferenceType()) return false; - if (Context.getLangOptions().CPlusPlus && - Context.getBaseElementType(D->getType())->getAs<RecordType>()) { - // FIXME: We should do something fancier here! - return false; + + if (Context.getLangOptions().CPlusPlus) { + if (const RecordType *Record + = Context.getBaseElementType(D->getType())->getAs<RecordType>()) + return ConstantInit && + cast<CXXRecordDecl>(Record->getDecl())->isPOD() && + !cast<CXXRecordDecl>(Record->getDecl())->hasMutableFields(); } + return true; } @@ -994,7 +1010,7 @@ CodeGenModule::GetOrCreateLLVMGlobal(llvm::StringRef MangledName, if (D) { // FIXME: This code is overly simple and should be merged with other global // handling. - GV->setConstant(DeclIsConstantGlobal(Context, D)); + GV->setConstant(DeclIsConstantGlobal(Context, D, false)); // Set linkage and visibility in case we never see a definition. NamedDecl::LinkageInfo LV = D->getLinkageAndVisibility(); @@ -1109,7 +1125,7 @@ void CodeGenModule::EmitVTable(CXXRecordDecl *Class, bool DefinitionRequired) { llvm::GlobalVariable::LinkageTypes CodeGenModule::getVTableLinkage(const CXXRecordDecl *RD) { - if (RD->isInAnonymousNamespace() || !RD->hasLinkage()) + if (RD->getLinkage() != ExternalLinkage) return llvm::GlobalVariable::InternalLinkage; if (const CXXMethodDecl *KeyFunction @@ -1276,7 +1292,7 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) { // If it is safe to mark the global 'constant', do so now. GV->setConstant(false); - if (!NonConstInit && DeclIsConstantGlobal(Context, D)) + if (!NonConstInit && DeclIsConstantGlobal(Context, D, true)) GV->setConstant(true); GV->setAlignment(getContext().getDeclAlign(D).getQuantity()); @@ -1561,14 +1577,24 @@ llvm::Value *CodeGenModule::getBuiltinLibFunction(const FunctionDecl *FD, "isn't a lib fn"); // Get the name, skip over the __builtin_ prefix (if necessary). - const char *Name = Context.BuiltinInfo.GetName(BuiltinID); - if (Context.BuiltinInfo.isLibFunction(BuiltinID)) - Name += 10; + llvm::StringRef Name; + GlobalDecl D(FD); + + // If the builtin has been declared explicitly with an assembler label, + // use the mangled name. This differs from the plain label on platforms + // that prefix labels. + if (FD->hasAttr<AsmLabelAttr>()) + Name = getMangledName(D); + else if (Context.BuiltinInfo.isLibFunction(BuiltinID)) + Name = Context.BuiltinInfo.GetName(BuiltinID) + 10; + else + Name = Context.BuiltinInfo.GetName(BuiltinID); + const llvm::FunctionType *Ty = cast<llvm::FunctionType>(getTypes().ConvertType(FD->getType())); - return GetOrCreateLLVMFunction(Name, Ty, GlobalDecl(FD), /*ForVTable=*/false); + return GetOrCreateLLVMFunction(Name, Ty, D, /*ForVTable=*/false); } llvm::Function *CodeGenModule::getIntrinsic(unsigned IID,const llvm::Type **Tys, @@ -1628,6 +1654,16 @@ GetConstantCFStringEntry(llvm::StringMap<llvm::Constant*> &Map, return Map.GetOrCreateValue(llvm::StringRef(AsBytes.data(), AsBytes.size())); } +static llvm::StringMapEntry<llvm::Constant*> & +GetConstantStringEntry(llvm::StringMap<llvm::Constant*> &Map, + const StringLiteral *Literal, + unsigned &StringLength) +{ + llvm::StringRef String = Literal->getString(); + StringLength = String.size(); + return Map.GetOrCreateValue(String); +} + llvm::Constant * CodeGenModule::GetAddrOfConstantCFString(const StringLiteral *Literal) { unsigned StringLength = 0; @@ -1721,11 +1757,8 @@ CodeGenModule::GetAddrOfConstantCFString(const StringLiteral *Literal) { llvm::Constant * CodeGenModule::GetAddrOfConstantString(const StringLiteral *Literal) { unsigned StringLength = 0; - bool isUTF16 = false; llvm::StringMapEntry<llvm::Constant*> &Entry = - GetConstantCFStringEntry(CFConstantStringMap, Literal, - getTargetData().isLittleEndian(), - isUTF16, StringLength); + GetConstantStringEntry(CFConstantStringMap, Literal, StringLength); if (llvm::Constant *C = Entry.getValue()) return C; @@ -1738,24 +1771,26 @@ CodeGenModule::GetAddrOfConstantString(const StringLiteral *Literal) { if (!ConstantStringClassRef) { std::string StringClass(getLangOptions().ObjCConstantStringClass); const llvm::Type *Ty = getTypes().ConvertType(getContext().IntTy); - Ty = llvm::ArrayType::get(Ty, 0); llvm::Constant *GV; - if (StringClass.empty()) - GV = CreateRuntimeVariable(Ty, - Features.ObjCNonFragileABI ? - "OBJC_CLASS_$_NSConstantString" : - "_NSConstantStringClassReference"); - else { - std::string str; - if (Features.ObjCNonFragileABI) - str = "OBJC_CLASS_$_" + StringClass; - else - str = "_" + StringClass + "ClassReference"; - GV = CreateRuntimeVariable(Ty, str); + if (Features.ObjCNonFragileABI) { + std::string str = + StringClass.empty() ? "OBJC_CLASS_$_NSConstantString" + : "OBJC_CLASS_$_" + StringClass; + GV = getObjCRuntime().GetClassGlobal(str); + // Make sure the result is of the correct type. + const llvm::Type *PTy = llvm::PointerType::getUnqual(Ty); + ConstantStringClassRef = + llvm::ConstantExpr::getBitCast(GV, PTy); + } else { + std::string str = + StringClass.empty() ? "_NSConstantStringClassReference" + : "_" + StringClass + "ClassReference"; + const llvm::Type *PTy = llvm::ArrayType::get(Ty, 0); + GV = CreateRuntimeVariable(PTy, str); + // Decay array -> ptr + ConstantStringClassRef = + llvm::ConstantExpr::getGetElementPtr(GV, Zeros, 2); } - // Decay array -> ptr - ConstantStringClassRef = - llvm::ConstantExpr::getGetElementPtr(GV, Zeros, 2); } QualType NSTy = getContext().getNSConstantStringType(); @@ -1773,28 +1808,15 @@ CodeGenModule::GetAddrOfConstantString(const StringLiteral *Literal) { llvm::GlobalValue::LinkageTypes Linkage; bool isConstant; - if (isUTF16) { - // FIXME: why do utf strings get "_" labels instead of "L" labels? - Linkage = llvm::GlobalValue::InternalLinkage; - // Note: -fwritable-strings doesn't make unicode NSStrings writable, but - // does make plain ascii ones writable. - isConstant = true; - } else { - Linkage = llvm::GlobalValue::PrivateLinkage; - isConstant = !Features.WritableStrings; - } + Linkage = llvm::GlobalValue::PrivateLinkage; + isConstant = !Features.WritableStrings; llvm::GlobalVariable *GV = new llvm::GlobalVariable(getModule(), C->getType(), isConstant, Linkage, C, ".str"); GV->setUnnamedAddr(true); - if (isUTF16) { - CharUnits Align = getContext().getTypeAlignInChars(getContext().ShortTy); - GV->setAlignment(Align.getQuantity()); - } else { - CharUnits Align = getContext().getTypeAlignInChars(getContext().CharTy); - GV->setAlignment(Align.getQuantity()); - } + CharUnits Align = getContext().getTypeAlignInChars(getContext().CharTy); + GV->setAlignment(Align.getQuantity()); Fields[1] = llvm::ConstantExpr::getGetElementPtr(GV, Zeros, 2); // String length. @@ -1877,6 +1899,7 @@ static llvm::Constant *GenerateStringLiteral(llvm::StringRef str, new llvm::GlobalVariable(CGM.getModule(), C->getType(), constant, llvm::GlobalValue::PrivateLinkage, C, GlobalName); + GV->setAlignment(1); GV->setUnnamedAddr(true); return GV; } @@ -2057,7 +2080,9 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) { case Decl::UsingDirective: case Decl::ClassTemplate: case Decl::FunctionTemplate: + case Decl::TypeAliasTemplate: case Decl::NamespaceAlias: + case Decl::Block: break; case Decl::CXXConstructor: // Skip function templates @@ -2216,6 +2241,23 @@ void CodeGenFunction::EmitDeclMetadata() { } } +void CodeGenModule::EmitCoverageFile() { + if (!getCodeGenOpts().CoverageFile.empty()) { + if (llvm::NamedMDNode *CUNode = TheModule.getNamedMetadata("llvm.dbg.cu")) { + llvm::NamedMDNode *GCov = TheModule.getOrInsertNamedMetadata("llvm.gcov"); + llvm::LLVMContext &Ctx = TheModule.getContext(); + llvm::MDString *CoverageFile = + llvm::MDString::get(Ctx, getCodeGenOpts().CoverageFile); + for (int i = 0, e = CUNode->getNumOperands(); i != e; ++i) { + llvm::MDNode *CU = CUNode->getOperand(i); + llvm::Value *node[] = { CoverageFile, CU }; + llvm::MDNode *N = llvm::MDNode::get(Ctx, node); + GCov->addOperand(N); + } + } + } +} + ///@name Custom Runtime Function Interfaces ///@{ // @@ -2234,14 +2276,11 @@ llvm::Constant *CodeGenModule::getBlockObjectDispose() { } // Otherwise construct the function by hand. - const llvm::FunctionType *FTy; - std::vector<const llvm::Type*> ArgTys; - const llvm::Type *ResultType = llvm::Type::getVoidTy(VMContext); - ArgTys.push_back(Int8PtrTy); - ArgTys.push_back(llvm::Type::getInt32Ty(VMContext)); - FTy = llvm::FunctionType::get(ResultType, ArgTys, false); + const llvm::Type *args[] = { Int8PtrTy, Int32Ty }; + const llvm::FunctionType *fty + = llvm::FunctionType::get(VoidTy, args, false); return BlockObjectDispose = - CreateRuntimeFunction(FTy, "_Block_object_dispose"); + CreateRuntimeFunction(fty, "_Block_object_dispose"); } llvm::Constant *CodeGenModule::getBlockObjectAssign() { @@ -2256,15 +2295,11 @@ llvm::Constant *CodeGenModule::getBlockObjectAssign() { } // Otherwise construct the function by hand. - const llvm::FunctionType *FTy; - std::vector<const llvm::Type*> ArgTys; - const llvm::Type *ResultType = llvm::Type::getVoidTy(VMContext); - ArgTys.push_back(Int8PtrTy); - ArgTys.push_back(Int8PtrTy); - ArgTys.push_back(llvm::Type::getInt32Ty(VMContext)); - FTy = llvm::FunctionType::get(ResultType, ArgTys, false); + const llvm::Type *args[] = { Int8PtrTy, Int8PtrTy, Int32Ty }; + const llvm::FunctionType *fty + = llvm::FunctionType::get(VoidTy, args, false); return BlockObjectAssign = - CreateRuntimeFunction(FTy, "_Block_object_assign"); + CreateRuntimeFunction(fty, "_Block_object_assign"); } llvm::Constant *CodeGenModule::getNSConcreteGlobalBlock() { diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenModule.h b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenModule.h index 99c973c..779a352 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenModule.h +++ b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenModule.h @@ -97,16 +97,20 @@ namespace CodeGen { }; struct CodeGenTypeCache { + /// void + const llvm::Type *VoidTy; + /// i8, i32, and i64 const llvm::IntegerType *Int8Ty, *Int32Ty, *Int64Ty; /// int const llvm::IntegerType *IntTy; - /// intptr_t and size_t, which we assume are the same + /// intptr_t, size_t, and ptrdiff_t, which we assume are the same size. union { const llvm::IntegerType *IntPtrTy; const llvm::IntegerType *SizeTy; + const llvm::IntegerType *PtrDiffTy; }; /// void* in address space 0 @@ -735,6 +739,10 @@ private: void EmitDeclMetadata(); + /// EmitCoverageFile - Emit the llvm.gcov metadata used to tell LLVM where + /// to emit the .gcno and .gcda files in a way that persists in .bc files. + void EmitCoverageFile(); + /// MayDeferGeneration - Determine if the given decl can be emitted /// lazily; this is only relevant for definitions. The given decl /// must be either a function or var decl. diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenTypes.h b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenTypes.h index dc383cb..ff1eb4c 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenTypes.h +++ b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenTypes.h @@ -220,8 +220,9 @@ public: // These are internal details of CGT that shouldn't be used externally. /// GetExpandedTypes - Expand the type \arg Ty into the LLVM /// argument types it would be passed as on the provided vector \arg /// ArgTys. See ABIArgInfo::Expand. - void GetExpandedTypes(QualType Ty, std::vector<const llvm::Type*> &ArgTys, - bool IsRecursive); + void GetExpandedTypes(QualType type, + llvm::SmallVectorImpl<const llvm::Type*> &expanded, + bool isRecursive); /// IsZeroInitializable - Return whether a type can be /// zero-initialized (in the C++ sense) with an LLVM zeroinitializer. diff --git a/contrib/llvm/tools/clang/lib/CodeGen/ItaniumCXXABI.cpp b/contrib/llvm/tools/clang/lib/CodeGen/ItaniumCXXABI.cpp index 33abf3a..12ef9bd 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/ItaniumCXXABI.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/ItaniumCXXABI.cpp @@ -1007,11 +1007,9 @@ void ARMCXXABI::ReadArrayCookie(CodeGenFunction &CGF, static llvm::Constant *getGuardAcquireFn(CodeGenModule &CGM, const llvm::PointerType *GuardPtrTy) { // int __cxa_guard_acquire(__guard *guard_object); - - std::vector<const llvm::Type*> Args(1, GuardPtrTy); const llvm::FunctionType *FTy = llvm::FunctionType::get(CGM.getTypes().ConvertType(CGM.getContext().IntTy), - Args, /*isVarArg=*/false); + GuardPtrTy, /*isVarArg=*/false); return CGM.CreateRuntimeFunction(FTy, "__cxa_guard_acquire"); } @@ -1019,12 +1017,9 @@ static llvm::Constant *getGuardAcquireFn(CodeGenModule &CGM, static llvm::Constant *getGuardReleaseFn(CodeGenModule &CGM, const llvm::PointerType *GuardPtrTy) { // void __cxa_guard_release(__guard *guard_object); - - std::vector<const llvm::Type*> Args(1, GuardPtrTy); - const llvm::FunctionType *FTy = llvm::FunctionType::get(llvm::Type::getVoidTy(CGM.getLLVMContext()), - Args, /*isVarArg=*/false); + GuardPtrTy, /*isVarArg=*/false); return CGM.CreateRuntimeFunction(FTy, "__cxa_guard_release"); } @@ -1032,12 +1027,9 @@ static llvm::Constant *getGuardReleaseFn(CodeGenModule &CGM, static llvm::Constant *getGuardAbortFn(CodeGenModule &CGM, const llvm::PointerType *GuardPtrTy) { // void __cxa_guard_abort(__guard *guard_object); - - std::vector<const llvm::Type*> Args(1, GuardPtrTy); - const llvm::FunctionType *FTy = llvm::FunctionType::get(llvm::Type::getVoidTy(CGM.getLLVMContext()), - Args, /*isVarArg=*/false); + GuardPtrTy, /*isVarArg=*/false); return CGM.CreateRuntimeFunction(FTy, "__cxa_guard_abort"); } diff --git a/contrib/llvm/tools/clang/lib/CodeGen/ModuleBuilder.cpp b/contrib/llvm/tools/clang/lib/CodeGen/ModuleBuilder.cpp index 8945028..4a2c4abbe 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/ModuleBuilder.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/ModuleBuilder.cpp @@ -79,7 +79,7 @@ namespace { MEnd = D->decls_end(); M != MEnd; ++M) if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(*M)) - if (Method->isThisDeclarationADefinition() && + if (Method->doesThisDeclarationHaveABody() && (Method->hasAttr<UsedAttr>() || Method->hasAttr<ConstructorAttr>())) Builder->EmitTopLevelDecl(Method); diff --git a/contrib/llvm/tools/clang/lib/CodeGen/TargetInfo.cpp b/contrib/llvm/tools/clang/lib/CodeGen/TargetInfo.cpp index bc2472c..043ead7 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/TargetInfo.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/TargetInfo.cpp @@ -648,7 +648,7 @@ ABIArgInfo X86_32ABIInfo::getIndirectResult(QualType Ty, bool ByVal) const { unsigned TypeAlign = getContext().getTypeAlign(Ty) / 8; unsigned StackAlign = getTypeStackAlignInBytes(Ty, TypeAlign); if (StackAlign == 0) - return ABIArgInfo::getIndirect(0); + return ABIArgInfo::getIndirect(4); // If the stack alignment is less than the type alignment, realign the // argument. @@ -1315,13 +1315,10 @@ ABIArgInfo X86_64ABIInfo::getIndirectResult(QualType Ty) const { if (isRecordWithNonTrivialDestructorOrCopyConstructor(Ty)) return ABIArgInfo::getIndirect(0, /*ByVal=*/false); - // Compute the byval alignment. We trust the back-end to honor the - // minimum ABI alignment for byval, to make cleaner IR. - const unsigned MinABIAlign = 8; - unsigned Align = getContext().getTypeAlign(Ty) / 8; - if (Align > MinABIAlign) - return ABIArgInfo::getIndirect(Align); - return ABIArgInfo::getIndirect(0); + // Compute the byval alignment. We specify the alignment of the byval in all + // cases so that the mid-level optimizer knows the alignment of the byval. + unsigned Align = std::max(getContext().getTypeAlign(Ty) / 8, 8U); + return ABIArgInfo::getIndirect(Align); } /// Get16ByteVectorType - The ABI specifies that a value should be passed in an @@ -2279,6 +2276,22 @@ public: int getDwarfEHStackPointer(CodeGen::CodeGenModule &M) const { return 13; } + + bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF, + llvm::Value *Address) const { + CodeGen::CGBuilderTy &Builder = CGF.Builder; + llvm::LLVMContext &Context = CGF.getLLVMContext(); + + const llvm::IntegerType *i8 = llvm::Type::getInt8Ty(Context); + llvm::Value *Four8 = llvm::ConstantInt::get(i8, 4); + + // 0-15 are the 16 integer registers. + AssignToArrayRange(Builder, Address, Four8, 0, 15); + + return false; + } + + }; } @@ -2845,10 +2858,21 @@ void MSP430TargetCodeGenInfo::SetTargetAttributes(const Decl *D, //===----------------------------------------------------------------------===// namespace { +class MipsABIInfo : public ABIInfo { +public: + MipsABIInfo(CodeGenTypes &CGT) : ABIInfo(CGT) {} + + ABIArgInfo classifyReturnType(QualType RetTy) const; + ABIArgInfo classifyArgumentType(QualType RetTy) const; + virtual void computeInfo(CGFunctionInfo &FI) const; + virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty, + CodeGenFunction &CGF) const; +}; + class MIPSTargetCodeGenInfo : public TargetCodeGenInfo { public: MIPSTargetCodeGenInfo(CodeGenTypes &CGT) - : TargetCodeGenInfo(new DefaultABIInfo(CGT)) {} + : TargetCodeGenInfo(new MipsABIInfo(CGT)) {} int getDwarfEHStackPointer(CodeGen::CodeGenModule &CGM) const { return 29; @@ -2859,6 +2883,54 @@ public: }; } +ABIArgInfo MipsABIInfo::classifyArgumentType(QualType Ty) const { + if (isAggregateTypeForABI(Ty)) { + // Ignore empty aggregates. + if (getContext().getTypeSize(Ty) == 0) + return ABIArgInfo::getIgnore(); + + return ABIArgInfo::getIndirect(0); + } + + // Treat an enum type as its underlying type. + if (const EnumType *EnumTy = Ty->getAs<EnumType>()) + Ty = EnumTy->getDecl()->getIntegerType(); + + return (Ty->isPromotableIntegerType() ? + ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); +} + +ABIArgInfo MipsABIInfo::classifyReturnType(QualType RetTy) const { + if (RetTy->isVoidType()) + return ABIArgInfo::getIgnore(); + + if (isAggregateTypeForABI(RetTy)) { + if (RetTy->isAnyComplexType()) + return ABIArgInfo::getDirect(); + + return ABIArgInfo::getIndirect(0); + } + + // Treat an enum type as its underlying type. + if (const EnumType *EnumTy = RetTy->getAs<EnumType>()) + RetTy = EnumTy->getDecl()->getIntegerType(); + + return (RetTy->isPromotableIntegerType() ? + ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); +} + +void MipsABIInfo::computeInfo(CGFunctionInfo &FI) const { + FI.getReturnInfo() = classifyReturnType(FI.getReturnType()); + for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end(); + it != ie; ++it) + it->info = classifyArgumentType(it->type); +} + +llvm::Value* MipsABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty, + CodeGenFunction &CGF) const { + return 0; +} + bool MIPSTargetCodeGenInfo::initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF, llvm::Value *Address) const { diff --git a/contrib/llvm/tools/clang/lib/Driver/Driver.cpp b/contrib/llvm/tools/clang/lib/Driver/Driver.cpp index 302779b..20bc495 100644 --- a/contrib/llvm/tools/clang/lib/Driver/Driver.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/Driver.cpp @@ -46,14 +46,14 @@ using namespace clang::driver; using namespace clang; -Driver::Driver(llvm::StringRef _ClangExecutable, - llvm::StringRef _DefaultHostTriple, - llvm::StringRef _DefaultImageName, +Driver::Driver(llvm::StringRef ClangExecutable, + llvm::StringRef DefaultHostTriple, + llvm::StringRef DefaultImageName, bool IsProduction, bool CXXIsProduction, - Diagnostic &_Diags) - : Opts(createDriverOptTable()), Diags(_Diags), - ClangExecutable(_ClangExecutable), UseStdLib(true), - DefaultHostTriple(_DefaultHostTriple), DefaultImageName(_DefaultImageName), + Diagnostic &Diags) + : Opts(createDriverOptTable()), Diags(Diags), + ClangExecutable(ClangExecutable), UseStdLib(true), + DefaultHostTriple(DefaultHostTriple), DefaultImageName(DefaultImageName), DriverTitle("clang \"gcc-compatible\" driver"), Host(0), CCPrintOptionsFilename(0), CCPrintHeadersFilename(0), @@ -398,9 +398,10 @@ void Driver::PrintVersion(const Compilation &C, llvm::raw_ostream &OS) const { /// PrintDiagnosticCategories - Implement the --print-diagnostic-categories /// option. static void PrintDiagnosticCategories(llvm::raw_ostream &OS) { - for (unsigned i = 1; // Skip the empty category. - const char *CategoryName = DiagnosticIDs::getCategoryNameFromID(i); ++i) - OS << i << ',' << CategoryName << '\n'; + // Skip the empty category. + for (unsigned i = 1, max = DiagnosticIDs::getNumberOfCategories(); + i != max; ++i) + OS << i << ',' << DiagnosticIDs::getCategoryNameFromID(i) << '\n'; } bool Driver::HandleImmediateArgs(const Compilation &C) { @@ -569,14 +570,14 @@ void Driver::PrintActions(const Compilation &C) const { PrintActions1(C, *it, Ids); } -/// \brief Check whether the given input tree contains any compilation (or -/// assembly) actions. -static bool ContainsCompileAction(const Action *A) { +/// \brief Check whether the given input tree contains any compilation or +/// assembly actions. +static bool ContainsCompileOrAssembleAction(const Action *A) { if (isa<CompileJobAction>(A) || isa<AssembleJobAction>(A)) return true; for (Action::const_iterator it = A->begin(), ie = A->end(); it != ie; ++it) - if (ContainsCompileAction(*it)) + if (ContainsCompileOrAssembleAction(*it)) return true; return false; @@ -667,7 +668,7 @@ void Driver::BuildUniversalActions(const ToolChain &TC, Arg *A = Args.getLastArg(options::OPT_g_Group); if (A && !A->getOption().matches(options::OPT_g0) && !A->getOption().matches(options::OPT_gstabs) && - ContainsCompileAction(Actions.back())) { + ContainsCompileOrAssembleAction(Actions.back())) { ActionList Inputs; Inputs.push_back(Actions.back()); Actions.pop_back(); diff --git a/contrib/llvm/tools/clang/lib/Driver/HostInfo.cpp b/contrib/llvm/tools/clang/lib/Driver/HostInfo.cpp index 198af54..3b1c2c7 100644 --- a/contrib/llvm/tools/clang/lib/Driver/HostInfo.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/HostInfo.cpp @@ -414,15 +414,20 @@ ToolChain *NetBSDHostInfo::CreateToolChain(const ArgList &Args, (A->getOption().matches(options::OPT_m32)) ? "powerpc" : "powerpc64"; } } + llvm::Triple TargetTriple(getTriple()); + TargetTriple.setArchName(ArchName); - ToolChain *&TC = ToolChains[ArchName]; - if (!TC) { - llvm::Triple TCTriple(getTriple()); - TCTriple.setArchName(ArchName); + ToolChain *TC; - TC = new toolchains::NetBSD(*this, TCTriple); + // XXX Cache toolchain even if -m32 is used + if (Arch == ArchName) { + TC = ToolChains[ArchName]; + if (TC) + return TC; } + TC = new toolchains::NetBSD(*this, TargetTriple, getTriple()); + return TC; } diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChains.cpp index 499587a..2f7bd75 100644 --- a/contrib/llvm/tools/clang/lib/Driver/ToolChains.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains.cpp @@ -9,6 +9,10 @@ #include "ToolChains.h" +#ifdef HAVE_CLANG_CONFIG_H +# include "clang/Config/config.h" +#endif + #include "clang/Driver/Arg.h" #include "clang/Driver/ArgList.h" #include "clang/Driver/Compilation.h" @@ -119,7 +123,7 @@ llvm::StringRef Darwin::getDarwinArchName(const ArgList &Args) const { switch (getTriple().getArch()) { default: return getArchName(); - + case llvm::Triple::thumb: case llvm::Triple::arm: { if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) @@ -149,10 +153,10 @@ std::string Darwin::ComputeEffectiveClangTriple(const ArgList &Args) const { // the default triple). if (!isTargetInitialized()) return Triple.getTriple(); - + unsigned Version[3]; getTargetVersion(Version); - + llvm::SmallString<16> Str; llvm::raw_svector_ostream(Str) << (isTargetIPhoneOS() ? "ios" : "macosx") @@ -562,7 +566,7 @@ void DarwinClang::AddCCKextLibArgs(const ArgList &Args, P.appendComponent("lib"); P.appendComponent("darwin"); P.appendComponent("libclang_rt.cc_kext.a"); - + // For now, allow missing resource libraries to support developers who may // not have compiler-rt checked out or integrated into their build. bool Exists; @@ -628,7 +632,7 @@ DerivedArgList *Darwin::TranslateArgs(const DerivedArgList &Args, DAL->AddSeparateArg(OriginalArg, Opts.getOption(options::OPT_Zlinker_input), A->getValue(Args, i)); - + } continue; } @@ -919,8 +923,8 @@ TCEToolChain::~TCEToolChain() { delete it->second; } -bool TCEToolChain::IsMathErrnoDefault() const { - return true; +bool TCEToolChain::IsMathErrnoDefault() const { + return true; } bool TCEToolChain::IsUnwindTablesDefault() const { @@ -935,7 +939,7 @@ const char *TCEToolChain::GetForcedPicModel() const { return 0; } -Tool &TCEToolChain::SelectTool(const Compilation &C, +Tool &TCEToolChain::SelectTool(const Compilation &C, const JobAction &JA, const ActionList &Inputs) const { Action::ActionClass Key; @@ -1006,7 +1010,12 @@ FreeBSD::FreeBSD(const HostInfo &Host, const llvm::Triple& Triple) llvm::Triple(getDriver().DefaultHostTriple).getArch() == llvm::Triple::x86_64) Lib32 = true; - + + if (Triple.getArch() == llvm::Triple::ppc && + llvm::Triple(getDriver().DefaultHostTriple).getArch() == + llvm::Triple::ppc64) + Lib32 = true; + if (Lib32) { getFilePaths().push_back(CLANG_PREFIX "/usr/lib32"); } else { @@ -1047,14 +1056,14 @@ Tool &FreeBSD::SelectTool(const Compilation &C, const JobAction &JA, /// NetBSD - NetBSD tool chain which can call as(1) and ld(1) directly. -NetBSD::NetBSD(const HostInfo &Host, const llvm::Triple& Triple) - : Generic_ELF(Host, Triple) { +NetBSD::NetBSD(const HostInfo &Host, const llvm::Triple& Triple, + const llvm::Triple& ToolTriple) + : Generic_ELF(Host, Triple), ToolTriple(ToolTriple) { // Determine if we are compiling 32-bit code on an x86_64 platform. bool Lib32 = false; - if (Triple.getArch() == llvm::Triple::x86 && - llvm::Triple(getDriver().DefaultHostTriple).getArch() == - llvm::Triple::x86_64) + if (ToolTriple.getArch() == llvm::Triple::x86_64 && + Triple.getArch() == llvm::Triple::x86) Lib32 = true; if (getDriver().UseStdLib) { @@ -1084,10 +1093,11 @@ Tool &NetBSD::SelectTool(const Compilation &C, const JobAction &JA, if (UseIntegratedAs) T = new tools::ClangAs(*this); else - T = new tools::netbsd::Assemble(*this); + T = new tools::netbsd::Assemble(*this, ToolTriple); break; case Action::LinkJobClass: - T = new tools::netbsd::Link(*this); break; + T = new tools::netbsd::Link(*this, ToolTriple); + break; default: T = &Generic_GCC::SelectTool(C, JA, Inputs); } @@ -1176,12 +1186,18 @@ enum LinuxDistro { ArchLinux, DebianLenny, DebianSqueeze, + DebianWheezy, Exherbo, + RHEL4, + RHEL5, + RHEL6, Fedora13, Fedora14, Fedora15, FedoraRawhide, OpenSuse11_3, + OpenSuse11_4, + OpenSuse12_1, UbuntuHardy, UbuntuIntrepid, UbuntuJaunty, @@ -1189,27 +1205,31 @@ enum LinuxDistro { UbuntuLucid, UbuntuMaverick, UbuntuNatty, + UbuntuOneiric, UnknownDistro }; -static bool IsFedora(enum LinuxDistro Distro) { +static bool IsRedhat(enum LinuxDistro Distro) { return Distro == Fedora13 || Distro == Fedora14 || - Distro == Fedora15 || Distro == FedoraRawhide; + Distro == Fedora15 || Distro == FedoraRawhide || + Distro == RHEL4 || Distro == RHEL5 || Distro == RHEL6; } static bool IsOpenSuse(enum LinuxDistro Distro) { - return Distro == OpenSuse11_3; + return Distro == OpenSuse11_3 || Distro == OpenSuse11_4 || + Distro == OpenSuse12_1; } static bool IsDebian(enum LinuxDistro Distro) { - return Distro == DebianLenny || Distro == DebianSqueeze; + return Distro == DebianLenny || Distro == DebianSqueeze || + Distro == DebianWheezy; } static bool IsUbuntu(enum LinuxDistro Distro) { return Distro == UbuntuHardy || Distro == UbuntuIntrepid || - Distro == UbuntuLucid || Distro == UbuntuMaverick || + Distro == UbuntuLucid || Distro == UbuntuMaverick || Distro == UbuntuJaunty || Distro == UbuntuKarmic || - Distro == UbuntuNatty; + Distro == UbuntuNatty || Distro == UbuntuOneiric; } static bool IsDebianBased(enum LinuxDistro Distro) { @@ -1227,7 +1247,8 @@ static bool HasMultilib(llvm::Triple::ArchType Arch, enum LinuxDistro Distro) { } if (Arch == llvm::Triple::ppc64) return true; - if ((Arch == llvm::Triple::x86 || Arch == llvm::Triple::ppc) && IsDebianBased(Distro)) + if ((Arch == llvm::Triple::x86 || Arch == llvm::Triple::ppc) && + IsDebianBased(Distro)) return true; return false; } @@ -1253,6 +1274,8 @@ static LinuxDistro DetectLinuxDistro(llvm::Triple::ArchType Arch) { return UbuntuMaverick; else if (Lines[i] == "DISTRIB_CODENAME=natty") return UbuntuNatty; + else if (Lines[i] == "DISTRIB_CODENAME=oneiric") + return UbuntuOneiric; } return UnknownDistro; } @@ -1268,6 +1291,17 @@ static LinuxDistro DetectLinuxDistro(llvm::Triple::ArchType Arch) { else if (Data.startswith("Fedora release") && Data.find("Rawhide") != llvm::StringRef::npos) return FedoraRawhide; + else if (Data.startswith("Red Hat Enterprise Linux") && + Data.find("release 6") != llvm::StringRef::npos) + return RHEL6; + else if ((Data.startswith("Red Hat Enterprise Linux") || + Data.startswith("CentOS")) && + Data.find("release 5") != llvm::StringRef::npos) + return RHEL5; + else if ((Data.startswith("Red Hat Enterprise Linux") || + Data.startswith("CentOS")) && + Data.find("release 4") != llvm::StringRef::npos) + return RHEL4; return UnknownDistro; } @@ -1277,6 +1311,8 @@ static LinuxDistro DetectLinuxDistro(llvm::Triple::ArchType Arch) { return DebianLenny; else if (Data.startswith("squeeze/sid")) return DebianSqueeze; + else if (Data.startswith("wheezy/sid")) + return DebianWheezy; return UnknownDistro; } @@ -1284,6 +1320,10 @@ static LinuxDistro DetectLinuxDistro(llvm::Triple::ArchType Arch) { llvm::StringRef Data = File.get()->getBuffer(); if (Data.startswith("openSUSE 11.3")) return OpenSuse11_3; + else if (Data.startswith("openSUSE 11.4")) + return OpenSuse11_4; + else if (Data.startswith("openSUSE 12.1")) + return OpenSuse12_1; return UnknownDistro; } @@ -1297,6 +1337,54 @@ static LinuxDistro DetectLinuxDistro(llvm::Triple::ArchType Arch) { return UnknownDistro; } +static std::string findGCCBaseLibDir(const std::string &GccTriple) { + // FIXME: Using CXX_INCLUDE_ROOT is here is a bit of a hack, but + // avoids adding yet another option to configure/cmake. + // It would probably be cleaner to break it in two variables + // CXX_GCC_ROOT with just /foo/bar + // CXX_GCC_VER with 4.5.2 + // Then we would have + // CXX_INCLUDE_ROOT = CXX_GCC_ROOT/include/c++/CXX_GCC_VER + // and this function would return + // CXX_GCC_ROOT/lib/gcc/CXX_INCLUDE_ARCH/CXX_GCC_VER + llvm::SmallString<128> CxxIncludeRoot(CXX_INCLUDE_ROOT); + if (CxxIncludeRoot != "") { + // This is of the form /foo/bar/include/c++/4.5.2/ + if (CxxIncludeRoot.back() == '/') + llvm::sys::path::remove_filename(CxxIncludeRoot); // remove the / + llvm::StringRef Version = llvm::sys::path::filename(CxxIncludeRoot); + llvm::sys::path::remove_filename(CxxIncludeRoot); // remove the version + llvm::sys::path::remove_filename(CxxIncludeRoot); // remove the c++ + llvm::sys::path::remove_filename(CxxIncludeRoot); // remove the include + std::string ret(CxxIncludeRoot.c_str()); + ret.append("/lib/gcc/"); + ret.append(CXX_INCLUDE_ARCH); + ret.append("/"); + ret.append(Version); + return ret; + } + static const char* GccVersions[] = {"4.6.0", "4.6", + "4.5.2", "4.5.1", "4.5", + "4.4.5", "4.4.4", "4.4.3", "4.4", + "4.3.4", "4.3.3", "4.3.2", "4.3", + "4.2.4", "4.2.3", "4.2.2", "4.2.1", + "4.2", "4.1.1"}; + bool Exists; + for (unsigned i = 0; i < sizeof(GccVersions)/sizeof(char*); ++i) { + std::string Suffix = GccTriple + "/" + GccVersions[i]; + std::string t1 = "/usr/lib/gcc/" + Suffix; + if (!llvm::sys::fs::exists(t1 + "/crtbegin.o", Exists) && Exists) + return t1; + std::string t2 = "/usr/lib64/gcc/" + Suffix; + if (!llvm::sys::fs::exists(t2 + "/crtbegin.o", Exists) && Exists) + return t2; + std::string t3 = "/usr/lib/" + GccTriple + "/gcc/" + Suffix; + if (!llvm::sys::fs::exists(t3 + "/crtbegin.o", Exists) && Exists) + return t3; + } + return ""; +} + Linux::Linux(const HostInfo &Host, const llvm::Triple &Triple) : Generic_ELF(Host, Triple) { llvm::Triple::ArchType Arch = @@ -1370,42 +1458,23 @@ Linux::Linux(const HostInfo &Host, const llvm::Triple &Triple) } else if (Arch == llvm::Triple::ppc) { if (!llvm::sys::fs::exists("/usr/lib/powerpc-linux-gnu", Exists) && Exists) GccTriple = "powerpc-linux-gnu"; - else if (!llvm::sys::fs::exists("/usr/lib/gcc/powerpc-unknown-linux-gnu", Exists) && Exists) + else if (!llvm::sys::fs::exists("/usr/lib/gcc/powerpc-unknown-linux-gnu", + Exists) && Exists) GccTriple = "powerpc-unknown-linux-gnu"; } else if (Arch == llvm::Triple::ppc64) { - if (!llvm::sys::fs::exists("/usr/lib/gcc/powerpc64-unknown-linux-gnu", Exists) && Exists) + if (!llvm::sys::fs::exists("/usr/lib/gcc/powerpc64-unknown-linux-gnu", + Exists) && Exists) GccTriple = "powerpc64-unknown-linux-gnu"; - else if (!llvm::sys::fs::exists("/usr/lib64/gcc/powerpc64-unknown-linux-gnu", Exists) && Exists) + else if (!llvm::sys::fs::exists("/usr/lib64/gcc/" + "powerpc64-unknown-linux-gnu", Exists) && + Exists) GccTriple = "powerpc64-unknown-linux-gnu"; } - const char* GccVersions[] = {"4.6.0", - "4.5.2", "4.5.1", "4.5", - "4.4.5", "4.4.4", "4.4.3", "4.4", - "4.3.4", "4.3.3", "4.3.2", "4.3", - "4.2.4", "4.2.3", "4.2.2", "4.2.1", "4.2"}; - std::string Base = ""; - for (unsigned i = 0; i < sizeof(GccVersions)/sizeof(char*); ++i) { - std::string Suffix = GccTriple + "/" + GccVersions[i]; - std::string t1 = "/usr/lib/gcc/" + Suffix; - if (!llvm::sys::fs::exists(t1 + "/crtbegin.o", Exists) && Exists) { - Base = t1; - break; - } - std::string t2 = "/usr/lib64/gcc/" + Suffix; - if (!llvm::sys::fs::exists(t2 + "/crtbegin.o", Exists) && Exists) { - Base = t2; - break; - } - std::string t3 = "/usr/lib/" + GccTriple + "/gcc/" + Suffix; - if (!llvm::sys::fs::exists(t3 + "/crtbegin.o", Exists) && Exists) { - Base = t3; - break; - } - } - + std::string Base = findGCCBaseLibDir(GccTriple); path_list &Paths = getFilePaths(); - bool Is32Bits = (getArch() == llvm::Triple::x86 || getArch() == llvm::Triple::ppc); + bool Is32Bits = (getArch() == llvm::Triple::x86 || + getArch() == llvm::Triple::ppc); std::string Suffix; std::string Lib; @@ -1426,7 +1495,7 @@ Linux::Linux(const HostInfo &Host, const llvm::Triple &Triple) LinuxDistro Distro = DetectLinuxDistro(Arch); - if (IsUbuntu(Distro)) { + if (IsOpenSuse(Distro) || IsUbuntu(Distro)) { ExtraOpts.push_back("-z"); ExtraOpts.push_back("relro"); } @@ -1434,21 +1503,28 @@ Linux::Linux(const HostInfo &Host, const llvm::Triple &Triple) if (Arch == llvm::Triple::arm || Arch == llvm::Triple::thumb) ExtraOpts.push_back("-X"); - if (IsFedora(Distro) || Distro == UbuntuMaverick || Distro == UbuntuNatty) + if (IsRedhat(Distro) || IsOpenSuse(Distro) || Distro == UbuntuMaverick || + Distro == UbuntuNatty || Distro == UbuntuOneiric) ExtraOpts.push_back("--hash-style=gnu"); - if (IsDebian(Distro) || Distro == UbuntuLucid || Distro == UbuntuJaunty || - Distro == UbuntuKarmic) + if (IsDebian(Distro) || IsOpenSuse(Distro) || Distro == UbuntuLucid || + Distro == UbuntuJaunty || Distro == UbuntuKarmic) ExtraOpts.push_back("--hash-style=both"); - if (IsFedora(Distro)) + if (IsRedhat(Distro)) ExtraOpts.push_back("--no-add-needed"); - if (Distro == DebianSqueeze || IsOpenSuse(Distro) || - IsFedora(Distro) || Distro == UbuntuLucid || Distro == UbuntuMaverick || - Distro == UbuntuKarmic || Distro == UbuntuNatty) + if (Distro == DebianSqueeze || Distro == DebianWheezy || + IsOpenSuse(Distro) || + (IsRedhat(Distro) && Distro != RHEL4 && Distro != RHEL5) || + Distro == UbuntuLucid || + Distro == UbuntuMaverick || Distro == UbuntuKarmic || + Distro == UbuntuNatty || Distro == UbuntuOneiric) ExtraOpts.push_back("--build-id"); + if (IsOpenSuse(Distro)) + ExtraOpts.push_back("--enable-new-dtags"); + if (Distro == ArchLinux) Lib = "lib"; @@ -1457,9 +1533,14 @@ Linux::Linux(const HostInfo &Host, const llvm::Triple &Triple) if (IsOpenSuse(Distro) && Is32Bits) Paths.push_back(Base + "/../../../../" + GccTriple + "/lib/../lib"); Paths.push_back(Base + "/../../../../" + Lib); - Paths.push_back("/lib/../" + Lib); - Paths.push_back("/usr/lib/../" + Lib); } + + // FIXME: This is in here to find crt1.o. It is provided by libc, and + // libc (like gcc), can be installed in any directory. Once we are + // fetching this from a config file, we should have a libc prefix. + Paths.push_back("/lib/../" + Lib); + Paths.push_back("/usr/lib/../" + Lib); + if (!Suffix.empty()) Paths.push_back(Base); if (IsOpenSuse(Distro)) diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains.h b/contrib/llvm/tools/clang/lib/Driver/ToolChains.h index 7a1a050..ace9b84 100644 --- a/contrib/llvm/tools/clang/lib/Driver/ToolChains.h +++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains.h @@ -308,8 +308,11 @@ public: }; class LLVM_LIBRARY_VISIBILITY NetBSD : public Generic_ELF { + const llvm::Triple ToolTriple; + public: - NetBSD(const HostInfo &Host, const llvm::Triple& Triple); + NetBSD(const HostInfo &Host, const llvm::Triple& Triple, + const llvm::Triple& ToolTriple); virtual Tool &SelectTool(const Compilation &C, const JobAction &JA, const ActionList &Inputs) const; diff --git a/contrib/llvm/tools/clang/lib/Driver/Tools.cpp b/contrib/llvm/tools/clang/lib/Driver/Tools.cpp index 7b78cd5..b7f0f83 100644 --- a/contrib/llvm/tools/clang/lib/Driver/Tools.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/Tools.cpp @@ -47,8 +47,9 @@ using namespace clang::driver::tools; /// FindTargetProgramPath - Return path of the target specific version of /// ProgName. If it doesn't exist, return path of ProgName itself. static std::string FindTargetProgramPath(const ToolChain &TheToolChain, + const std::string TripleString, const char *ProgName) { - std::string Executable(TheToolChain.getTripleString() + "-" + ProgName); + std::string Executable(TripleString + "-" + ProgName); std::string Path(TheToolChain.GetProgramPath(Executable.c_str())); if (Path != Executable) return Path; @@ -146,6 +147,22 @@ static void AddLinkerInputs(const ToolChain &TC, } } +static void addProfileRT(const ToolChain &TC, const ArgList &Args, + ArgStringList &CmdArgs) { + if (Args.hasArg(options::OPT_fprofile_arcs) || + Args.hasArg(options::OPT_fprofile_generate) || + Args.hasArg(options::OPT_fcreate_profile) || + Args.hasArg(options::OPT_coverage)) { + // GCC links libgcov.a by adding -L<inst>/gcc/lib/gcc/<triple>/<ver> -lgcov + // to the link line. We cannot do the same thing because unlike gcov + // there is a libprofile_rt.so. We used to use the -l:libprofile_rt.a + // syntax, but that is not supported by old linkers. + const char *lib = Args.MakeArgString(TC.getDriver().Dir + "/../lib/" + + "libprofile_rt.a"); + CmdArgs.push_back(lib); + } +} + void Clang::AddPreprocessingOptions(const Driver &D, const ArgList &Args, ArgStringList &CmdArgs, @@ -428,6 +445,7 @@ static bool isSignedCharDefault(const llvm::Triple &Triple) { default: return true; + case llvm::Triple::arm: case llvm::Triple::ppc: case llvm::Triple::ppc64: if (Triple.getOS() == llvm::Triple::Darwin) @@ -652,7 +670,7 @@ void Clang::AddMIPSTargetArgs(const ArgList &Args, else if (MArch == "r6000") CmdArgs.push_back("mips2"); else - CmdArgs.push_back(MArch.str().c_str()); + CmdArgs.push_back(Args.MakeArgString(MArch)); } // Select the float ABI as determined by -msoft-float, -mhard-float, and @@ -761,34 +779,34 @@ void Clang::AddX86TargetArgs(const ArgList &Args, if (!CPUName) { // FIXME: Need target hooks. if (getToolChain().getOS().startswith("darwin")) { - if (getToolChain().getArchName() == "x86_64") + if (getToolChain().getArch() == llvm::Triple::x86_64) CPUName = "core2"; - else if (getToolChain().getArchName() == "i386") + else if (getToolChain().getArch() == llvm::Triple::x86) CPUName = "yonah"; } else if (getToolChain().getOS().startswith("haiku")) { - if (getToolChain().getArchName() == "x86_64") + if (getToolChain().getArch() == llvm::Triple::x86_64) CPUName = "x86-64"; - else if (getToolChain().getArchName() == "i386") + else if (getToolChain().getArch() == llvm::Triple::x86) CPUName = "i586"; } else if (getToolChain().getOS().startswith("openbsd")) { - if (getToolChain().getArchName() == "x86_64") + if (getToolChain().getArch() == llvm::Triple::x86_64) CPUName = "x86-64"; - else if (getToolChain().getArchName() == "i386") + else if (getToolChain().getArch() == llvm::Triple::x86) CPUName = "i486"; } else if (getToolChain().getOS().startswith("freebsd")) { - if (getToolChain().getArchName() == "x86_64") + if (getToolChain().getArch() == llvm::Triple::x86_64) CPUName = "x86-64"; - else if (getToolChain().getArchName() == "i386") + else if (getToolChain().getArch() == llvm::Triple::x86) CPUName = "i486"; } else if (getToolChain().getOS().startswith("netbsd")) { - if (getToolChain().getArchName() == "x86_64") + if (getToolChain().getArch() == llvm::Triple::x86_64) CPUName = "x86-64"; - else if (getToolChain().getArchName() == "i386") + else if (getToolChain().getArch() == llvm::Triple::x86) CPUName = "i486"; } else { - if (getToolChain().getArchName() == "x86_64") + if (getToolChain().getArch() == llvm::Triple::x86_64) CPUName = "x86-64"; - else if (getToolChain().getArchName() == "i386") + else if (getToolChain().getArch() == llvm::Triple::x86) CPUName = "pentium4"; } } @@ -907,21 +925,63 @@ static void addExceptionArgs(const ArgList &Args, types::ID InputType, static bool ShouldDisableCFI(const ArgList &Args, const ToolChain &TC) { + if (TC.getTriple().getOS() == llvm::Triple::Darwin) { + // The native darwin assembler doesn't support cfi directives, so + // we disable them if we think the .s file will be passed to it. + + // FIXME: Duplicated code with ToolChains.cpp + // FIXME: This doesn't belong here, but ideally we will support static soon + // anyway. + bool HasStatic = (Args.hasArg(options::OPT_mkernel) || + Args.hasArg(options::OPT_static) || + Args.hasArg(options::OPT_fapple_kext)); + bool IsIADefault = TC.IsIntegratedAssemblerDefault() && !HasStatic; + bool UseIntegratedAs = Args.hasFlag(options::OPT_integrated_as, + options::OPT_no_integrated_as, + IsIADefault); + bool UseCFI = Args.hasFlag(options::OPT_fdwarf2_cfi_asm, + options::OPT_fno_dwarf2_cfi_asm, + UseIntegratedAs); + return !UseCFI; + } + + // For now we assume that every other assembler support CFI. + return false; +} + +/// \brief Check whether the given input tree contains any compilation actions. +static bool ContainsCompileAction(const Action *A) { + if (isa<CompileJobAction>(A)) + return true; + + for (Action::const_iterator it = A->begin(), ie = A->end(); it != ie; ++it) + if (ContainsCompileAction(*it)) + return true; - // FIXME: Duplicated code with ToolChains.cpp - // FIXME: This doesn't belong here, but ideally we will support static soon - // anyway. - bool HasStatic = (Args.hasArg(options::OPT_mkernel) || - Args.hasArg(options::OPT_static) || - Args.hasArg(options::OPT_fapple_kext)); - bool IsIADefault = TC.IsIntegratedAssemblerDefault() && !HasStatic; - bool UseIntegratedAs = Args.hasFlag(options::OPT_integrated_as, - options::OPT_no_integrated_as, - IsIADefault); - bool UseCFI = Args.hasFlag(options::OPT_fdwarf2_cfi_asm, - options::OPT_fno_dwarf2_cfi_asm, - UseIntegratedAs); - return !UseCFI; + return false; +} + +/// \brief Check if -relax-all should be passed to the internal assembler. +/// This is done by default when compiling non-assembler source with -O0. +static bool UseRelaxAll(Compilation &C, const ArgList &Args) { + bool RelaxDefault = true; + + if (Arg *A = Args.getLastArg(options::OPT_O_Group)) + RelaxDefault = A->getOption().matches(options::OPT_O0); + + if (RelaxDefault) { + RelaxDefault = false; + for (ActionList::const_iterator it = C.getActions().begin(), + ie = C.getActions().end(); it != ie; ++it) { + if (ContainsCompileAction(*it)) { + RelaxDefault = true; + break; + } + } + } + + return Args.hasFlag(options::OPT_mrelax_all, options::OPT_mno_relax_all, + RelaxDefault); } void Clang::ConstructJob(Compilation &C, const JobAction &JA, @@ -959,13 +1019,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } else if (isa<AssembleJobAction>(JA)) { CmdArgs.push_back("-emit-obj"); - // At -O0, we use -mrelax-all by default. - bool IsOpt = false; - if (Arg *A = Args.getLastArg(options::OPT_O_Group)) - IsOpt = !A->getOption().matches(options::OPT_O0); - if (Args.hasFlag(options::OPT_mrelax_all, - options::OPT_mno_relax_all, - !IsOpt)) + if (UseRelaxAll(C, Args)) CmdArgs.push_back("-mrelax-all"); // When using an integrated assembler, translate -Wa, and -Xassembler @@ -983,6 +1037,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // Do nothing, this is the default and we don't support anything else. } else if (Value == "-L") { CmdArgs.push_back("-msave-temp-labels"); + } else if (Value == "--fatal-warnings") { + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back("-fatal-assembler-warnings"); } else { D.Diag(clang::diag::err_drv_unsupported_option_argument) << A->getOption().getName() << Value; @@ -1303,6 +1360,14 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.hasArg(options::OPT_coverage)) CmdArgs.push_back("-femit-coverage-data"); + if (C.getArgs().hasArg(options::OPT_c) || + C.getArgs().hasArg(options::OPT_S)) { + if (Output.isFilename()) { + CmdArgs.push_back("-coverage-file"); + CmdArgs.push_back(Args.MakeArgString(Output.getFilename())); + } + } + Args.AddLastArg(CmdArgs, options::OPT_nostdinc); Args.AddLastArg(CmdArgs, options::OPT_nostdincxx); Args.AddLastArg(CmdArgs, options::OPT_nobuiltininc); @@ -1478,6 +1543,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, options::OPT_fno_lax_vector_conversions)) CmdArgs.push_back("-fno-lax-vector-conversions"); + // -fobjc-infer-related-result-type is the default. + if (Args.hasFlag(options::OPT_fobjc_infer_related_result_type, + options::OPT_fno_objc_infer_related_result_type, + /*Default=*/true)) + CmdArgs.push_back("-fobjc-infer-related-result-type"); + // Handle -fobjc-gc and -fobjc-gc-only. They are exclusive, and -fobjc-gc-only // takes precedence. const Arg *GCArg = Args.getLastArg(options::OPT_fobjc_gc_only); @@ -1496,7 +1567,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (Args.getLastArg(options::OPT_fapple_kext)) CmdArgs.push_back("-fapple-kext"); - Args.AddLastArg(CmdArgs, options::OPT_fno_show_column); Args.AddLastArg(CmdArgs, options::OPT_fobjc_sender_dependent_dispatch); Args.AddLastArg(CmdArgs, options::OPT_fdiagnostics_print_source_range_info); Args.AddLastArg(CmdArgs, options::OPT_fdiagnostics_parseable_fixits); @@ -1547,6 +1617,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(Args.MakeArgString(llvm::Twine(StackProtectorLevel))); } + // Translate -mstackrealign + if (Args.hasArg(options::OPT_mstackrealign)) { + CmdArgs.push_back("-backend-option"); + CmdArgs.push_back("-force-align-stack"); + } + // Forward -f options with positive and negative forms; we translate // these by hand. @@ -1654,6 +1730,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, options::OPT_fno_gnu_keywords)) A->render(Args, CmdArgs); + if (Args.hasFlag(options::OPT_fgnu89_inline, + options::OPT_fno_gnu89_inline, + false)) + CmdArgs.push_back("-fgnu89-inline"); + // -fnext-runtime defaults to on Darwin and when rewriting Objective-C, and is // -the -cc1 default. bool NeXTRuntimeIsDefault = @@ -1816,6 +1897,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(A->getValue(Args)); } + if (const Arg *A = + Args.getLastArg(options::OPT_fdiagnostics_format_EQ)) { + CmdArgs.push_back("-fdiagnostics-format"); + CmdArgs.push_back(A->getValue(Args)); + } + if (Arg *A = Args.getLastArg( options::OPT_fdiagnostics_show_note_include_stack, options::OPT_fno_diagnostics_show_note_include_stack)) { @@ -1837,6 +1924,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, options::OPT_fno_show_source_location)) CmdArgs.push_back("-fno-show-source-location"); + if (!Args.hasFlag(options::OPT_fshow_column, + options::OPT_fno_show_column, + true)) + CmdArgs.push_back("-fno-show-column"); + if (!Args.hasFlag(options::OPT_fspell_checking, options::OPT_fno_spell_checking)) CmdArgs.push_back("-fno-spell-checking"); @@ -2006,13 +2098,7 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-filetype"); CmdArgs.push_back("obj"); - // At -O0, we use -mrelax-all by default. - bool IsOpt = false; - if (Arg *A = Args.getLastArg(options::OPT_O_Group)) - IsOpt = !A->getOption().matches(options::OPT_O0); - if (Args.hasFlag(options::OPT_mrelax_all, - options::OPT_mno_relax_all, - !IsOpt)) + if (UseRelaxAll(C, Args)) CmdArgs.push_back("-relax-all"); // Ignore explicit -force_cpusubtype_ALL option. @@ -2894,12 +2980,17 @@ void darwin::Link::AddLinkArgs(Compilation &C, Args.AddAllArgs(CmdArgs, options::OPT_sub__library); Args.AddAllArgs(CmdArgs, options::OPT_sub__umbrella); - Args.AddAllArgsTranslated(CmdArgs, options::OPT_isysroot, "-syslibroot"); - if (getDarwinToolChain().isTargetIPhoneOS()) { - if (!Args.hasArg(options::OPT_isysroot)) { - CmdArgs.push_back("-syslibroot"); - CmdArgs.push_back("/Developer/SDKs/Extra"); - } + // Give --sysroot= preference, over the Apple specific behavior to also use + // --isysroot as the syslibroot. + if (const Arg *A = Args.getLastArg(options::OPT__sysroot_EQ)) { + CmdArgs.push_back("-syslibroot"); + CmdArgs.push_back(A->getValue(Args)); + } else if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) { + CmdArgs.push_back("-syslibroot"); + CmdArgs.push_back(A->getValue(Args)); + } else if (getDarwinToolChain().isTargetIPhoneOS()) { + CmdArgs.push_back("-syslibroot"); + CmdArgs.push_back("/Developer/SDKs/Extra"); } Args.AddLastArg(CmdArgs, options::OPT_twolevel__namespace); @@ -3060,12 +3151,6 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(LinkingOutput); } - if (Args.hasArg(options::OPT_fprofile_arcs) || - Args.hasArg(options::OPT_fprofile_generate) || - Args.hasArg(options::OPT_fcreate_profile) || - Args.hasArg(options::OPT_coverage)) - CmdArgs.push_back("-lgcov"); - if (Args.hasArg(options::OPT_fnested_functions)) CmdArgs.push_back("-allow_stack_execute"); @@ -3086,6 +3171,8 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA, // endfile_spec is empty. } + addProfileRT(getToolChain(), Args, CmdArgs); + Args.AddAllArgs(CmdArgs, options::OPT_T_Group); Args.AddAllArgs(CmdArgs, options::OPT_F); @@ -3125,14 +3212,14 @@ void darwin::Dsymutil::ConstructJob(Compilation &C, const JobAction &JA, const char *LinkingOutput) const { ArgStringList CmdArgs; + CmdArgs.push_back("-o"); + CmdArgs.push_back(Output.getFilename()); + assert(Inputs.size() == 1 && "Unable to handle multiple inputs."); const InputInfo &Input = Inputs[0]; assert(Input.isFilename() && "Unexpected dsymutil input."); CmdArgs.push_back(Input.getFilename()); - CmdArgs.push_back("-o"); - CmdArgs.push_back(Output.getFilename()); - const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("dsymutil")); C.addCommand(new Command(JA, *this, Exec, CmdArgs)); @@ -3243,6 +3330,8 @@ void auroraux::Link::ConstructJob(Compilation &C, const JobAction &JA, getToolChain().GetFilePath("crtend.o"))); } + addProfileRT(getToolChain(), Args, CmdArgs); + const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("ld")); C.addCommand(new Command(JA, *this, Exec, CmdArgs)); @@ -3378,6 +3467,8 @@ void freebsd::Assemble::ConstructJob(Compilation &C, const JobAction &JA, if (getToolChain().getArchName() == "i386") CmdArgs.push_back("--32"); + if (getToolChain().getArchName() == "powerpc") + CmdArgs.push_back("-a32"); // Set byte order explicitly if (getToolChain().getArchName() == "mips") @@ -3434,6 +3525,11 @@ void freebsd::Link::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("elf_i386_fbsd"); } + if (getToolChain().getArchName() == "powerpc") { + CmdArgs.push_back("-m"); + CmdArgs.push_back("elf32ppc"); + } + if (Output.isFilename()) { CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); @@ -3542,6 +3638,8 @@ void freebsd::Link::ConstructJob(Compilation &C, const JobAction &JA, "crtn.o"))); } + addProfileRT(getToolChain(), Args, CmdArgs); + const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("ld")); C.addCommand(new Command(JA, *this, Exec, CmdArgs)); @@ -3556,7 +3654,8 @@ void netbsd::Assemble::ConstructJob(Compilation &C, const JobAction &JA, // When building 32-bit code on NetBSD/amd64, we have to explicitly // instruct as in the base system to assemble 32-bit code. - if (getToolChain().getArchName() == "i386") + if (ToolTriple.getArch() == llvm::Triple::x86_64 && + getToolChain().getArch() == llvm::Triple::x86) CmdArgs.push_back("--32"); @@ -3579,7 +3678,8 @@ void netbsd::Assemble::ConstructJob(Compilation &C, const JobAction &JA, } const char *Exec = Args.MakeArgString(FindTargetProgramPath(getToolChain(), - "as")); + ToolTriple.getTriple(), + "as")); C.addCommand(new Command(JA, *this, Exec, CmdArgs)); } @@ -3610,7 +3710,8 @@ void netbsd::Link::ConstructJob(Compilation &C, const JobAction &JA, // When building 32-bit code on NetBSD/amd64, we have to explicitly // instruct ld in the base system to link 32-bit code. - if (getToolChain().getArchName() == "i386") { + if (ToolTriple.getArch() == llvm::Triple::x86_64 && + getToolChain().getArch() == llvm::Triple::x86) { CmdArgs.push_back("-m"); CmdArgs.push_back("elf_i386"); } @@ -3657,7 +3758,6 @@ void netbsd::Link::ConstructJob(Compilation &C, const JobAction &JA, } // FIXME: For some reason GCC passes -lgcc and -lgcc_s before adding // the default system libraries. Just mimic this for now. - CmdArgs.push_back("-lgcc"); if (Args.hasArg(options::OPT_static)) { CmdArgs.push_back("-lgcc_eh"); } else { @@ -3665,6 +3765,7 @@ void netbsd::Link::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-lgcc_s"); CmdArgs.push_back("--no-as-needed"); } + CmdArgs.push_back("-lgcc"); if (Args.hasArg(options::OPT_pthread)) CmdArgs.push_back("-lpthread"); @@ -3692,8 +3793,11 @@ void netbsd::Link::ConstructJob(Compilation &C, const JobAction &JA, "crtn.o"))); } + addProfileRT(getToolChain(), Args, CmdArgs); + const char *Exec = Args.MakeArgString(FindTargetProgramPath(getToolChain(), - "ld")); + ToolTriple.getTriple(), + "ld")); C.addCommand(new Command(JA, *this, Exec, CmdArgs)); } @@ -3855,10 +3959,10 @@ void linuxtools::Link::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-lm"); } - if (Args.hasArg(options::OPT_static)) - CmdArgs.push_back("--start-group"); - if (!Args.hasArg(options::OPT_nostdlib)) { + if (Args.hasArg(options::OPT_static)) + CmdArgs.push_back("--start-group"); + if (!D.CCCIsCXX) CmdArgs.push_back("-lgcc"); @@ -3913,6 +4017,8 @@ void linuxtools::Link::ConstructJob(Compilation &C, const JobAction &JA, } } + addProfileRT(getToolChain(), Args, CmdArgs); + if (Args.hasArg(options::OPT_use_gold_plugin)) { CmdArgs.push_back("-plugin"); std::string Plugin = ToolChain.getDriver().Dir + "/../lib/LLVMgold.so"; @@ -3995,6 +4101,8 @@ void minix::Link::ConstructJob(Compilation &C, const JobAction &JA, "/usr/gnu/lib/libend.a"))); } + addProfileRT(getToolChain(), Args, CmdArgs); + const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("/usr/gnu/bin/gld")); C.addCommand(new Command(JA, *this, Exec, CmdArgs)); @@ -4150,6 +4258,8 @@ void dragonfly::Link::ConstructJob(Compilation &C, const JobAction &JA, getToolChain().GetFilePath("crtn.o"))); } + addProfileRT(getToolChain(), Args, CmdArgs); + const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("ld")); C.addCommand(new Command(JA, *this, Exec, CmdArgs)); diff --git a/contrib/llvm/tools/clang/lib/Driver/Tools.h b/contrib/llvm/tools/clang/lib/Driver/Tools.h index 93abf75..4a5a7e4 100644 --- a/contrib/llvm/tools/clang/lib/Driver/Tools.h +++ b/contrib/llvm/tools/clang/lib/Driver/Tools.h @@ -14,6 +14,7 @@ #include "clang/Driver/Types.h" #include "clang/Driver/Util.h" +#include "llvm/ADT/Triple.h" #include "llvm/Support/Compiler.h" namespace clang { @@ -338,9 +339,12 @@ namespace freebsd { /// netbsd -- Directly call GNU Binutils assembler and linker namespace netbsd { class LLVM_LIBRARY_VISIBILITY Assemble : public Tool { + private: + const llvm::Triple ToolTriple; + public: - Assemble(const ToolChain &TC) : Tool("netbsd::Assemble", "assembler", - TC) {} + Assemble(const ToolChain &TC, const llvm::Triple &ToolTriple) + : Tool("netbsd::Assemble", "assembler", TC), ToolTriple(ToolTriple) {} virtual bool hasIntegratedCPP() const { return false; } @@ -351,8 +355,12 @@ namespace netbsd { const char *LinkingOutput) const; }; class LLVM_LIBRARY_VISIBILITY Link : public Tool { + private: + const llvm::Triple ToolTriple; + public: - Link(const ToolChain &TC) : Tool("netbsd::Link", "linker", TC) {} + Link(const ToolChain &TC, const llvm::Triple &ToolTriple) + : Tool("netbsd::Ling", "linker", TC), ToolTriple(ToolTriple) {} virtual bool hasIntegratedCPP() const { return false; } diff --git a/contrib/llvm/tools/clang/lib/Frontend/ASTConsumers.cpp b/contrib/llvm/tools/clang/lib/Frontend/ASTConsumers.cpp index ecd6ef4..28d312a 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/ASTConsumers.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/ASTConsumers.cpp @@ -173,7 +173,7 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC, break; case Decl::Function: { const FunctionDecl* FD = cast<FunctionDecl>(DC); - if (FD->isThisDeclarationADefinition()) + if (FD->doesThisDeclarationHaveABody()) Out << "[function] "; else Out << "<function> "; diff --git a/contrib/llvm/tools/clang/lib/Frontend/ASTUnit.cpp b/contrib/llvm/tools/clang/lib/Frontend/ASTUnit.cpp index 2a12448..8827116 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/ASTUnit.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/ASTUnit.cpp @@ -102,6 +102,7 @@ ASTUnit::ASTUnit(bool _MainFileIsAST) ConcurrencyCheckValue(CheckUnlocked), PreambleRebuildCounter(0), SavedMainFileBuffer(0), PreambleBuffer(0), ShouldCacheCodeCompletionResults(false), + NestedMacroInstantiations(true), CompletionCacheTopLevelHashValue(0), PreambleTopLevelHashValue(0), CurrentTopLevelHashValue(0), @@ -579,6 +580,11 @@ ASTUnit *ASTUnit::LoadFromASTFile(const std::string &Filename, Reader.reset(new ASTReader(AST->getSourceManager(), AST->getFileManager(), AST->getDiagnostics())); + + // Recover resources if we crash before exiting this method. + llvm::CrashRecoveryContextCleanupRegistrar<ASTReader> + ReaderCleanup(Reader.get()); + Reader->setListener(new ASTInfoCollector(LangInfo, HeaderInfo, TargetTriple, Predefines, Counter)); @@ -633,6 +639,11 @@ ASTUnit *ASTUnit::LoadFromASTFile(const std::string &Filename, // AST file as needed. ASTReader *ReaderPtr = Reader.get(); llvm::OwningPtr<ExternalASTSource> Source(Reader.take()); + + // Unregister the cleanup for ASTReader. It will get cleaned up + // by the ASTUnit cleanup. + ReaderCleanup.unregister(); + Context.setExternalSource(Source); // Create an AST consumer, even though it isn't used. @@ -917,6 +928,8 @@ bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) { // If the main file has been overridden due to the use of a preamble, // make that override happen and introduce the preamble. PreprocessorOptions &PreprocessorOpts = Clang->getPreprocessorOpts(); + PreprocessorOpts.DetailedRecordIncludesNestedMacroInstantiations + = NestedMacroInstantiations; std::string PriorImplicitPCHInclude; if (OverrideMainBuffer) { PreprocessorOpts.addRemappedFile(OriginalSourceFile, OverrideMainBuffer); @@ -1554,6 +1567,119 @@ ASTUnit *ASTUnit::create(CompilerInvocation *CI, return AST.take(); } +ASTUnit *ASTUnit::LoadFromCompilerInvocationAction(CompilerInvocation *CI, + llvm::IntrusiveRefCntPtr<Diagnostic> Diags, + ASTFrontendAction *Action) { + assert(CI && "A CompilerInvocation is required"); + + // Create the AST unit. + llvm::OwningPtr<ASTUnit> AST; + AST.reset(new ASTUnit(false)); + ConfigureDiags(Diags, 0, 0, *AST, /*CaptureDiagnostics*/false); + AST->Diagnostics = Diags; + AST->OnlyLocalDecls = false; + AST->CaptureDiagnostics = false; + AST->CompleteTranslationUnit = Action ? Action->usesCompleteTranslationUnit() + : true; + AST->ShouldCacheCodeCompletionResults = false; + AST->Invocation = CI; + + // Recover resources if we crash before exiting this method. + llvm::CrashRecoveryContextCleanupRegistrar<ASTUnit> + ASTUnitCleanup(AST.get()); + llvm::CrashRecoveryContextCleanupRegistrar<Diagnostic, + llvm::CrashRecoveryContextReleaseRefCleanup<Diagnostic> > + DiagCleanup(Diags.getPtr()); + + // We'll manage file buffers ourselves. + CI->getPreprocessorOpts().RetainRemappedFileBuffers = true; + CI->getFrontendOpts().DisableFree = false; + ProcessWarningOptions(AST->getDiagnostics(), CI->getDiagnosticOpts()); + + // Save the target features. + AST->TargetFeatures = CI->getTargetOpts().Features; + + // Create the compiler instance to use for building the AST. + llvm::OwningPtr<CompilerInstance> Clang(new CompilerInstance()); + + // Recover resources if we crash before exiting this method. + llvm::CrashRecoveryContextCleanupRegistrar<CompilerInstance> + CICleanup(Clang.get()); + + Clang->setInvocation(CI); + AST->OriginalSourceFile = Clang->getFrontendOpts().Inputs[0].second; + + // Set up diagnostics, capturing any diagnostics that would + // otherwise be dropped. + Clang->setDiagnostics(&AST->getDiagnostics()); + + // Create the target instance. + Clang->getTargetOpts().Features = AST->TargetFeatures; + Clang->setTarget(TargetInfo::CreateTargetInfo(Clang->getDiagnostics(), + Clang->getTargetOpts())); + if (!Clang->hasTarget()) + return 0; + + // Inform the target of the language options. + // + // FIXME: We shouldn't need to do this, the target should be immutable once + // created. This complexity should be lifted elsewhere. + Clang->getTarget().setForcedLangOptions(Clang->getLangOpts()); + + assert(Clang->getFrontendOpts().Inputs.size() == 1 && + "Invocation must have exactly one source file!"); + assert(Clang->getFrontendOpts().Inputs[0].first != IK_AST && + "FIXME: AST inputs not yet supported here!"); + assert(Clang->getFrontendOpts().Inputs[0].first != IK_LLVM_IR && + "IR inputs not supported here!"); + + // Configure the various subsystems. + AST->FileSystemOpts = Clang->getFileSystemOpts(); + AST->FileMgr = new FileManager(AST->FileSystemOpts); + AST->SourceMgr = new SourceManager(AST->getDiagnostics(), *AST->FileMgr); + AST->TheSema.reset(); + AST->Ctx = 0; + AST->PP = 0; + + // Create a file manager object to provide access to and cache the filesystem. + Clang->setFileManager(&AST->getFileManager()); + + // Create the source manager. + Clang->setSourceManager(&AST->getSourceManager()); + + ASTFrontendAction *Act = Action; + + llvm::OwningPtr<TopLevelDeclTrackerAction> TrackerAct; + if (!Act) { + TrackerAct.reset(new TopLevelDeclTrackerAction(*AST)); + Act = TrackerAct.get(); + } + + // Recover resources if we crash before exiting this method. + llvm::CrashRecoveryContextCleanupRegistrar<TopLevelDeclTrackerAction> + ActCleanup(TrackerAct.get()); + + if (!Act->BeginSourceFile(*Clang.get(), + Clang->getFrontendOpts().Inputs[0].second, + Clang->getFrontendOpts().Inputs[0].first)) + return 0; + + Act->Execute(); + + // Steal the created target, context, and preprocessor. + AST->TheSema.reset(Clang->takeSema()); + AST->Consumer.reset(Clang->takeASTConsumer()); + AST->Ctx = &Clang->getASTContext(); + AST->PP = &Clang->getPreprocessor(); + Clang->setSourceManager(0); + Clang->setFileManager(0); + AST->Target = &Clang->getTarget(); + + Act->EndSourceFile(); + + return AST.take(); +} + bool ASTUnit::LoadFromCompilerInvocation(bool PrecompilePreamble) { if (!Invocation) return true; @@ -1589,7 +1715,8 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocation(CompilerInvocation *CI, bool CaptureDiagnostics, bool PrecompilePreamble, bool CompleteTranslationUnit, - bool CacheCodeCompletionResults) { + bool CacheCodeCompletionResults, + bool NestedMacroInstantiations) { // Create the AST unit. llvm::OwningPtr<ASTUnit> AST; AST.reset(new ASTUnit(false)); @@ -1600,6 +1727,7 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocation(CompilerInvocation *CI, AST->CompleteTranslationUnit = CompleteTranslationUnit; AST->ShouldCacheCodeCompletionResults = CacheCodeCompletionResults; AST->Invocation = CI; + AST->NestedMacroInstantiations = NestedMacroInstantiations; // Recover resources if we crash before exiting this method. llvm::CrashRecoveryContextCleanupRegistrar<ASTUnit> @@ -1624,7 +1752,8 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin, bool CompleteTranslationUnit, bool CacheCodeCompletionResults, bool CXXPrecompilePreamble, - bool CXXChainedPCH) { + bool CXXChainedPCH, + bool NestedMacroInstantiations) { if (!Diags.getPtr()) { // No diagnostics engine was provided, so create our own diagnostics object // with the default options. @@ -1691,6 +1820,7 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin, AST->NumStoredDiagnosticsInPreamble = StoredDiagnostics.size(); AST->StoredDiagnostics.swap(StoredDiagnostics); AST->Invocation = CI; + AST->NestedMacroInstantiations = NestedMacroInstantiations; // Recover resources if we crash before exiting this method. llvm::CrashRecoveryContextCleanupRegistrar<ASTUnit> @@ -2142,6 +2272,9 @@ void ASTUnit::CodeComplete(llvm::StringRef File, unsigned Line, unsigned Column, PreprocessorOpts.PrecompiledPreambleBytes.second = false; } + // Disable the preprocessing record + PreprocessorOpts.DetailedRecord = false; + llvm::OwningPtr<SyntaxOnlyAction> Act; Act.reset(new SyntaxOnlyAction); if (Act->BeginSourceFile(*Clang.get(), Clang->getFrontendOpts().Inputs[0].second, diff --git a/contrib/llvm/tools/clang/lib/Frontend/CompilerInstance.cpp b/contrib/llvm/tools/clang/lib/Frontend/CompilerInstance.cpp index ace3c5a..38fcfe3 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/CompilerInstance.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/CompilerInstance.cpp @@ -227,7 +227,8 @@ CompilerInstance::createPreprocessor(Diagnostic &Diags, } if (PPOpts.DetailedRecord) - PP->createPreprocessingRecord(); + PP->createPreprocessingRecord( + PPOpts.DetailedRecordIncludesNestedMacroInstantiations); InitializePreprocessor(*PP, PPOpts, HSOpts, FEOpts); diff --git a/contrib/llvm/tools/clang/lib/Frontend/CompilerInvocation.cpp b/contrib/llvm/tools/clang/lib/Frontend/CompilerInvocation.cpp index 495c6a8..a4a656f 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/CompilerInvocation.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/CompilerInvocation.cpp @@ -277,6 +277,14 @@ static void DiagnosticOptsToArgs(const DiagnosticOptions &Opts, Res.push_back("-fdiagnostics-show-category=id"); else if (Opts.ShowCategories == 2) Res.push_back("-fdiagnostics-show-category=name"); + switch (Opts.Format) { + case DiagnosticOptions::Clang: + Res.push_back("-fdiagnostics-format=clang"); break; + case DiagnosticOptions::Msvc: + Res.push_back("-fdiagnostics-format=msvc"); break; + case DiagnosticOptions::Vi: + Res.push_back("-fdiagnostics-format=vi"); break; + } if (Opts.ErrorLimit) { Res.push_back("-ferror-limit"); Res.push_back(llvm::utostr(Opts.ErrorLimit)); @@ -664,6 +672,9 @@ static void LangOptsToArgs(const LangOptions &Opts, Res.push_back("-fobjc-gc-only"); } } + if (Opts.ObjCInferRelatedResultType) + Res.push_back("-fobjc-infer-related-result-type"); + if (Opts.AppleKext) Res.push_back("-fapple-kext"); @@ -976,6 +987,7 @@ static void ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Opts.InstrumentForProfiling = Args.hasArg(OPT_pg); Opts.EmitGcovArcs = Args.hasArg(OPT_femit_coverage_data); Opts.EmitGcovNotes = Args.hasArg(OPT_femit_coverage_notes); + Opts.CoverageFile = Args.getLastArgValue(OPT_coverage_file); if (Arg *A = Args.getLastArg(OPT_fobjc_dispatch_method_EQ)) { llvm::StringRef Name = A->getValue(Args); @@ -1012,7 +1024,9 @@ static void ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args, Opts.PedanticErrors = Args.hasArg(OPT_pedantic_errors); Opts.ShowCarets = !Args.hasArg(OPT_fno_caret_diagnostics); Opts.ShowColors = Args.hasArg(OPT_fcolor_diagnostics); - Opts.ShowColumn = !Args.hasArg(OPT_fno_show_column); + Opts.ShowColumn = Args.hasFlag(OPT_fshow_column, + OPT_fno_show_column, + /*Default=*/true); Opts.ShowFixits = !Args.hasArg(OPT_fno_diagnostics_fixit_info); Opts.ShowLocation = !Args.hasArg(OPT_fno_show_source_location); Opts.ShowNames = Args.hasArg(OPT_fdiagnostics_show_name); @@ -1049,6 +1063,19 @@ static void ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args, << Args.getLastArg(OPT_fdiagnostics_show_category)->getAsString(Args) << ShowCategory; + llvm::StringRef Format = + Args.getLastArgValue(OPT_fdiagnostics_format, "clang"); + if (Format == "clang") + Opts.Format = DiagnosticOptions::Clang; + else if (Format == "msvc") + Opts.Format = DiagnosticOptions::Msvc; + else if (Format == "vi") + Opts.Format = DiagnosticOptions::Vi; + else + Diags.Report(diag::err_drv_invalid_value) + << Args.getLastArg(OPT_fdiagnostics_format)->getAsString(Args) + << Format; + Opts.ShowSourceRanges = Args.hasArg(OPT_fdiagnostics_print_source_range_info); Opts.ShowParseableFixits = Args.hasArg(OPT_fdiagnostics_parseable_fixits); Opts.VerifyDiagnostics = Args.hasArg(OPT_verify); @@ -1399,6 +1426,40 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, if (LangStd == LangStandard::lang_unspecified) Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << A->getValue(Args); + else { + // Valid standard, check to make sure language and standard are compatable. + const LangStandard &Std = LangStandard::getLangStandardForKind(LangStd); + switch (IK) { + case IK_C: + case IK_ObjC: + case IK_PreprocessedC: + case IK_PreprocessedObjC: + if (!(Std.isC89() || Std.isC99())) + Diags.Report(diag::err_drv_argument_not_allowed_with) + << A->getAsString(Args) << "C/ObjC"; + break; + case IK_CXX: + case IK_ObjCXX: + case IK_PreprocessedCXX: + case IK_PreprocessedObjCXX: + if (!Std.isCPlusPlus()) + Diags.Report(diag::err_drv_argument_not_allowed_with) + << A->getAsString(Args) << "C++/ObjC++"; + break; + case IK_OpenCL: + if (!Std.isC99()) + Diags.Report(diag::err_drv_argument_not_allowed_with) + << A->getAsString(Args) << "OpenCL"; + break; + case IK_CUDA: + if (!Std.isCPlusPlus()) + Diags.Report(diag::err_drv_argument_not_allowed_with) + << A->getAsString(Args) << "CUDA"; + break; + default: + break; + } + } } if (const Arg *A = Args.getLastArg(OPT_cl_std_EQ)) { @@ -1421,11 +1482,17 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, if (Args.hasArg(OPT_fno_operator_names)) Opts.CXXOperatorNames = 0; + if (Args.hasArg(OPT_fgnu89_inline)) + Opts.GNUInline = 1; + if (Args.hasArg(OPT_fobjc_gc_only)) Opts.setGCMode(LangOptions::GCOnly); else if (Args.hasArg(OPT_fobjc_gc)) Opts.setGCMode(LangOptions::HybridGC); + if (Args.hasArg(OPT_fobjc_infer_related_result_type)) + Opts.ObjCInferRelatedResultType = 1; + if (Args.hasArg(OPT_fapple_kext)) { if (!Opts.CPlusPlus) Diags.Report(diag::warn_c_kext); diff --git a/contrib/llvm/tools/clang/lib/Frontend/CreateInvocationFromCommandLine.cpp b/contrib/llvm/tools/clang/lib/Frontend/CreateInvocationFromCommandLine.cpp index 0005f91..42b648a 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/CreateInvocationFromCommandLine.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/CreateInvocationFromCommandLine.cpp @@ -65,7 +65,7 @@ clang::createInvocationFromCommandLine(llvm::ArrayRef<const char *> ArgList, // We expect to get back exactly one command job, if we didn't something // failed. const driver::JobList &Jobs = C->getJobs(); - if (Jobs.size() != 1 || !isa<driver::Command>(Jobs.begin())) { + if (Jobs.size() != 1 || !isa<driver::Command>(*Jobs.begin())) { llvm::SmallString<256> Msg; llvm::raw_svector_ostream OS(Msg); C->PrintJob(OS, C->getJobs(), "; ", true); diff --git a/contrib/llvm/tools/clang/lib/Frontend/DiagChecker.cpp b/contrib/llvm/tools/clang/lib/Frontend/DiagChecker.cpp deleted file mode 100644 index 66d7ed7..0000000 --- a/contrib/llvm/tools/clang/lib/Frontend/DiagChecker.cpp +++ /dev/null @@ -1,301 +0,0 @@ -//===--- DiagChecker.cpp - Diagnostic Checking Functions ------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Process the input files and check that the diagnostic messages are expected. -// -//===----------------------------------------------------------------------===// - -#include "clang/Frontend/Utils.h" -#include "clang/Frontend/TextDiagnosticBuffer.h" -#include "clang/Parse/ParseAST.h" -#include "clang/AST/ASTConsumer.h" -#include "clang/Basic/SourceManager.h" -#include "clang/Lex/Preprocessor.h" -#include "llvm/Support/raw_ostream.h" -using namespace clang; - -typedef TextDiagnosticBuffer::DiagList DiagList; -typedef TextDiagnosticBuffer::const_iterator const_diag_iterator; - -static void EmitError(Preprocessor &PP, SourceLocation Pos, const char *String){ - unsigned ID = PP.getDiagnostics().getCustomDiagID(Diagnostic::Error, String); - PP.Diag(Pos, ID); -} - - -// USING THE DIAGNOSTIC CHECKER: -// -// Indicating that a line expects an error or a warning is simple. Put a comment -// on the line that has the diagnostic, use "expected-{error,warning}" to tag -// if it's an expected error or warning, and place the expected text between {{ -// and }} markers. The full text doesn't have to be included, only enough to -// ensure that the correct diagnostic was emitted. -// -// Here's an example: -// -// int A = B; // expected-error {{use of undeclared identifier 'B'}} -// -// You can place as many diagnostics on one line as you wish. To make the code -// more readable, you can use slash-newline to separate out the diagnostics. -// -// The simple syntax above allows each specification to match exactly one error. -// You can use the extended syntax to customize this. The extended syntax is -// "expected-<type> <n> {{diag text}}", where <type> is one of "error", -// "warning" or "note", and <n> is a positive integer. This allows the -// diagnostic to appear as many times as specified. Example: -// -// void f(); // expected-note 2 {{previous declaration is here}} -// - -/// FindDiagnostics - Go through the comment and see if it indicates expected -/// diagnostics. If so, then put them in a diagnostic list. -/// -static void FindDiagnostics(const char *CommentStart, unsigned CommentLen, - DiagList &ExpectedDiags, - Preprocessor &PP, SourceLocation Pos, - const char *ExpectedStr) { - const char *CommentEnd = CommentStart+CommentLen; - unsigned ExpectedStrLen = strlen(ExpectedStr); - - // Find all expected-foo diagnostics in the string and add them to - // ExpectedDiags. - while (CommentStart != CommentEnd) { - CommentStart = std::find(CommentStart, CommentEnd, 'e'); - if (unsigned(CommentEnd-CommentStart) < ExpectedStrLen) return; - - // If this isn't expected-foo, ignore it. - if (memcmp(CommentStart, ExpectedStr, ExpectedStrLen)) { - ++CommentStart; - continue; - } - - CommentStart += ExpectedStrLen; - - // Skip whitespace. - while (CommentStart != CommentEnd && - isspace(CommentStart[0])) - ++CommentStart; - - // Default, if we find the '{' now, is 1 time. - int Times = 1; - int Temp = 0; - // In extended syntax, there could be a digit now. - while (CommentStart != CommentEnd && - CommentStart[0] >= '0' && CommentStart[0] <= '9') { - Temp *= 10; - Temp += CommentStart[0] - '0'; - ++CommentStart; - } - if (Temp > 0) - Times = Temp; - - // Skip whitespace again. - while (CommentStart != CommentEnd && - isspace(CommentStart[0])) - ++CommentStart; - - // We should have a {{ now. - if (CommentEnd-CommentStart < 2 || - CommentStart[0] != '{' || CommentStart[1] != '{') { - if (std::find(CommentStart, CommentEnd, '{') != CommentEnd) - EmitError(PP, Pos, "bogus characters before '{{' in expected string"); - else - EmitError(PP, Pos, "cannot find start ('{{') of expected string"); - return; - } - CommentStart += 2; - - // Find the }}. - const char *ExpectedEnd = CommentStart; - while (1) { - ExpectedEnd = std::find(ExpectedEnd, CommentEnd, '}'); - if (CommentEnd-ExpectedEnd < 2) { - EmitError(PP, Pos, "cannot find end ('}}') of expected string"); - return; - } - - if (ExpectedEnd[1] == '}') - break; - - ++ExpectedEnd; // Skip over singular }'s - } - - std::string Msg(CommentStart, ExpectedEnd); - std::string::size_type FindPos; - while ((FindPos = Msg.find("\\n")) != std::string::npos) - Msg.replace(FindPos, 2, "\n"); - // Add is possibly multiple times. - for (int i = 0; i < Times; ++i) - ExpectedDiags.push_back(std::make_pair(Pos, Msg)); - - CommentStart = ExpectedEnd; - } -} - -/// FindExpectedDiags - Lex the main source file to find all of the -// expected errors and warnings. -static void FindExpectedDiags(Preprocessor &PP, - DiagList &ExpectedErrors, - DiagList &ExpectedWarnings, - DiagList &ExpectedNotes) { - // Create a raw lexer to pull all the comments out of the main file. We don't - // want to look in #include'd headers for expected-error strings. - FileID FID = PP.getSourceManager().getMainFileID(); - - // Create a lexer to lex all the tokens of the main file in raw mode. - const llvm::MemoryBuffer *FromFile = PP.getSourceManager().getBuffer(FID); - Lexer RawLex(FID, FromFile, PP.getSourceManager(), PP.getLangOptions()); - - // Return comments as tokens, this is how we find expected diagnostics. - RawLex.SetCommentRetentionState(true); - - Token Tok; - Tok.setKind(tok::comment); - while (Tok.isNot(tok::eof)) { - RawLex.Lex(Tok); - if (!Tok.is(tok::comment)) continue; - - std::string Comment = PP.getSpelling(Tok); - if (Comment.empty()) continue; - - - // Find all expected errors. - FindDiagnostics(&Comment[0], Comment.size(), ExpectedErrors, PP, - Tok.getLocation(), "expected-error"); - - // Find all expected warnings. - FindDiagnostics(&Comment[0], Comment.size(), ExpectedWarnings, PP, - Tok.getLocation(), "expected-warning"); - - // Find all expected notes. - FindDiagnostics(&Comment[0], Comment.size(), ExpectedNotes, PP, - Tok.getLocation(), "expected-note"); - }; -} - -/// PrintProblem - This takes a diagnostic map of the delta between expected and -/// seen diagnostics. If there's anything in it, then something unexpected -/// happened. Print the map out in a nice format and return "true". If the map -/// is empty and we're not going to print things, then return "false". -/// -static bool PrintProblem(SourceManager &SourceMgr, - const_diag_iterator diag_begin, - const_diag_iterator diag_end, - const char *Msg) { - if (diag_begin == diag_end) return false; - - llvm::errs() << Msg << "\n"; - for (const_diag_iterator I = diag_begin, E = diag_end; I != E; ++I) - llvm::errs() << " Line " << SourceMgr.getInstantiationLineNumber(I->first) - << " " << I->second << "\n"; - - return true; -} - -/// CompareDiagLists - Compare two diagnostic lists and return the difference -/// between them. -/// -static bool CompareDiagLists(SourceManager &SourceMgr, - const_diag_iterator d1_begin, - const_diag_iterator d1_end, - const_diag_iterator d2_begin, - const_diag_iterator d2_end, - const char *MsgLeftOnly, - const char *MsgRightOnly) { - DiagList LeftOnly; - DiagList Left(d1_begin, d1_end); - DiagList Right(d2_begin, d2_end); - - for (const_diag_iterator I = Left.begin(), E = Left.end(); I != E; ++I) { - unsigned LineNo1 = SourceMgr.getInstantiationLineNumber(I->first); - const std::string &Diag1 = I->second; - - DiagList::iterator II, IE; - for (II = Right.begin(), IE = Right.end(); II != IE; ++II) { - unsigned LineNo2 = SourceMgr.getInstantiationLineNumber(II->first); - if (LineNo1 != LineNo2) continue; - - const std::string &Diag2 = II->second; - if (Diag2.find(Diag1) != std::string::npos || - Diag1.find(Diag2) != std::string::npos) { - break; - } - } - if (II == IE) { - // Not found. - LeftOnly.push_back(*I); - } else { - // Found. The same cannot be found twice. - Right.erase(II); - } - } - // Now all that's left in Right are those that were not matched. - - return PrintProblem(SourceMgr, LeftOnly.begin(), LeftOnly.end(), MsgLeftOnly) - | PrintProblem(SourceMgr, Right.begin(), Right.end(), MsgRightOnly); -} - -/// CheckResults - This compares the expected results to those that -/// were actually reported. It emits any discrepencies. Return "true" if there -/// were problems. Return "false" otherwise. -/// -static bool CheckResults(Preprocessor &PP, - const DiagList &ExpectedErrors, - const DiagList &ExpectedWarnings, - const DiagList &ExpectedNotes) { - const DiagnosticClient *DiagClient = PP.getDiagnostics().getClient(); - assert(DiagClient != 0 && - "DiagChecker requires a valid TextDiagnosticBuffer"); - const TextDiagnosticBuffer &Diags = - static_cast<const TextDiagnosticBuffer&>(*DiagClient); - SourceManager &SourceMgr = PP.getSourceManager(); - - // We want to capture the delta between what was expected and what was - // seen. - // - // Expected \ Seen - set expected but not seen - // Seen \ Expected - set seen but not expected - bool HadProblem = false; - - // See if there are error mismatches. - HadProblem |= CompareDiagLists(SourceMgr, - ExpectedErrors.begin(), ExpectedErrors.end(), - Diags.err_begin(), Diags.err_end(), - "Errors expected but not seen:", - "Errors seen but not expected:"); - - // See if there are warning mismatches. - HadProblem |= CompareDiagLists(SourceMgr, - ExpectedWarnings.begin(), - ExpectedWarnings.end(), - Diags.warn_begin(), Diags.warn_end(), - "Warnings expected but not seen:", - "Warnings seen but not expected:"); - - // See if there are note mismatches. - HadProblem |= CompareDiagLists(SourceMgr, - ExpectedNotes.begin(), - ExpectedNotes.end(), - Diags.note_begin(), Diags.note_end(), - "Notes expected but not seen:", - "Notes seen but not expected:"); - - return HadProblem; -} - - -/// CheckDiagnostics - Gather the expected diagnostics and check them. -bool clang::CheckDiagnostics(Preprocessor &PP) { - // Gather the set of expected diagnostics. - DiagList ExpectedErrors, ExpectedWarnings, ExpectedNotes; - FindExpectedDiags(PP, ExpectedErrors, ExpectedWarnings, ExpectedNotes); - - // Check that the expected diagnostics occurred. - return CheckResults(PP, ExpectedErrors, ExpectedWarnings, ExpectedNotes); -} diff --git a/contrib/llvm/tools/clang/lib/Frontend/InitHeaderSearch.cpp b/contrib/llvm/tools/clang/lib/Frontend/InitHeaderSearch.cpp index 3795c65..2e5ad17 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/InitHeaderSearch.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/InitHeaderSearch.cpp @@ -567,6 +567,19 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple, AddPath(CLANG_PREFIX "/usr/include/clang/" CLANG_VERSION_STRING, System, false, false, false); break; + case llvm::Triple::Linux: + // Generic Debian multiarch support: + if (triple.getArch() == llvm::Triple::x86_64) { + AddPath("/usr/include/x86_64-linux-gnu", System, false, false, false); + AddPath("/usr/include/i686-linux-gnu/64", System, false, false, false); + AddPath("/usr/include/i486-linux-gnu/64", System, false, false, false); + } else if (triple.getArch() == llvm::Triple::x86) { + AddPath("/usr/include/x86_64-linux-gnu/32", System, false, false, false); + AddPath("/usr/include/i686-linux-gnu", System, false, false, false); + AddPath("/usr/include/i486-linux-gnu", System, false, false, false); + } else if (triple.getArch() == llvm::Triple::arm) { + AddPath("/usr/include/arm-linux-gnueabi", System, false, false, false); + } default: break; } @@ -659,6 +672,27 @@ AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple) { // Debian based distros. // Note: these distros symlink /usr/include/c++/X.Y.Z -> X.Y //===------------------------------------------------------------------===// + + // Ubuntu 11.11 "Oneiric Ocelot" -- gcc-4.6.0 + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.6", + "x86_64-linux-gnu", "32", "", triple); + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.6", + "i686-linux-gnu", "", "64", triple); + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.6", + "i486-linux-gnu", "", "64", triple); + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.6", + "arm-linux-gnueabi", "", "", triple); + + // Ubuntu 11.04 "Natty Narwhal" -- gcc-4.5.2 + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.5", + "x86_64-linux-gnu", "32", "", triple); + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.5", + "i686-linux-gnu", "", "64", triple); + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.5", + "i486-linux-gnu", "", "64", triple); + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.5", + "arm-linux-gnueabi", "", "", triple); + // Ubuntu 10.10 "Maverick Meerkat" -- gcc-4.4.5 AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4", "i686-linux-gnu", "", "64", triple); @@ -742,6 +776,13 @@ AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple) { "x86_64-redhat-linux", "", "", triple); AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.1.2", "i386-redhat-linux", "", "", triple); + + // RHEL 5 + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.1.1", + "x86_64-redhat-linux", "32", "", triple); + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.1.1", + "i386-redhat-linux", "", "", triple); + //===------------------------------------------------------------------===// @@ -769,6 +810,11 @@ AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple) { AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.5", "x86_64-suse-linux", "", "", triple); + // openSUSE 12.1 + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.6", + "i586-suse-linux", "", "", triple); + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.6", + "x86_64-suse-linux", "", "", triple); // Arch Linux 2008-06-24 AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3.1", "i686-pc-linux-gnu", "", "", triple); @@ -997,6 +1043,8 @@ void InitHeaderSearch::Realize(const LangOptions &Lang) { if (it->first == Angled) SearchList.push_back(it->second); } + RemoveDuplicates(SearchList, quoted, Verbose); + unsigned angled = SearchList.size(); for (path_iterator it = IncludePath.begin(), ie = IncludePath.end(); it != ie; ++it) { @@ -1010,10 +1058,10 @@ void InitHeaderSearch::Realize(const LangOptions &Lang) { SearchList.push_back(it->second); } - RemoveDuplicates(SearchList, quoted, Verbose); + RemoveDuplicates(SearchList, angled, Verbose); bool DontSearchCurDir = false; // TODO: set to true if -I- is set? - Headers.SetSearchPaths(SearchList, quoted, DontSearchCurDir); + Headers.SetSearchPaths(SearchList, quoted, angled, DontSearchCurDir); // If verbose, print the list of directories that will be searched. if (Verbose) { diff --git a/contrib/llvm/tools/clang/lib/Frontend/InitPreprocessor.cpp b/contrib/llvm/tools/clang/lib/Frontend/InitPreprocessor.cpp index abe251d..147a8df0 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/InitPreprocessor.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/InitPreprocessor.cpp @@ -221,6 +221,40 @@ static void DefineExactWidthIntType(TargetInfo::IntType Ty, ConstSuffix); } +static void InitializeStandardPredefinedMacros(const TargetInfo &TI, + const LangOptions &LangOpts, + const FrontendOptions &FEOpts, + MacroBuilder &Builder) { + if (!LangOpts.Microsoft && !LangOpts.TraditionalCPP) + Builder.defineMacro("__STDC__"); + if (LangOpts.Freestanding) + Builder.defineMacro("__STDC_HOSTED__", "0"); + else + Builder.defineMacro("__STDC_HOSTED__"); + + if (!LangOpts.CPlusPlus) { + if (LangOpts.C99) + Builder.defineMacro("__STDC_VERSION__", "199901L"); + else if (!LangOpts.GNUMode && LangOpts.Digraphs) + Builder.defineMacro("__STDC_VERSION__", "199409L"); + } else { + if (LangOpts.GNUMode) + Builder.defineMacro("__cplusplus"); + else + // C++ [cpp.predefined]p1: + // The name_ _cplusplus is defined to the value 199711L when compiling a + // C++ translation unit. + Builder.defineMacro("__cplusplus", "199711L"); + } + + if (LangOpts.ObjC1) + Builder.defineMacro("__OBJC__"); + + // Not "standard" per se, but available even with the -undef flag. + if (LangOpts.AsmPreprocessor) + Builder.defineMacro("__ASSEMBLER__"); +} + static void InitializePredefinedMacros(const TargetInfo &TI, const LangOptions &LangOpts, const FrontendOptions &FEOpts, @@ -256,20 +290,6 @@ static void InitializePredefinedMacros(const TargetInfo &TI, // Initialize language-specific preprocessor defines. - // These should all be defined in the preprocessor according to the - // current language configuration. - if (!LangOpts.Microsoft && !LangOpts.TraditionalCPP) - Builder.defineMacro("__STDC__"); - if (LangOpts.AsmPreprocessor) - Builder.defineMacro("__ASSEMBLER__"); - - if (!LangOpts.CPlusPlus) { - if (LangOpts.C99) - Builder.defineMacro("__STDC_VERSION__", "199901L"); - else if (!LangOpts.GNUMode && LangOpts.Digraphs) - Builder.defineMacro("__STDC_VERSION__", "199409L"); - } - // Standard conforming mode? if (!LangOpts.GNUMode) Builder.defineMacro("__STRICT_ANSI__"); @@ -277,13 +297,7 @@ static void InitializePredefinedMacros(const TargetInfo &TI, if (LangOpts.CPlusPlus0x) Builder.defineMacro("__GXX_EXPERIMENTAL_CXX0X__"); - if (LangOpts.Freestanding) - Builder.defineMacro("__STDC_HOSTED__", "0"); - else - Builder.defineMacro("__STDC_HOSTED__"); - if (LangOpts.ObjC1) { - Builder.defineMacro("__OBJC__"); if (LangOpts.ObjCNonFragileABI) { Builder.defineMacro("__OBJC2__"); Builder.defineMacro("OBJC_ZEROCOST_EXCEPTIONS"); @@ -324,13 +338,6 @@ static void InitializePredefinedMacros(const TargetInfo &TI, if (LangOpts.CPlusPlus) { Builder.defineMacro("__GNUG__", "4"); Builder.defineMacro("__GXX_WEAK__"); - if (LangOpts.GNUMode) - Builder.defineMacro("__cplusplus"); - else - // C++ [cpp.predefined]p1: - // The name_ _cplusplusis defined to the value 199711L when compiling a - // C++ translation unit. - Builder.defineMacro("__cplusplus", "199711L"); Builder.defineMacro("__private_extern__", "extern"); } @@ -343,6 +350,8 @@ static void InitializePredefinedMacros(const TargetInfo &TI, // Since we define wchar_t in C++ mode. Builder.defineMacro("_WCHAR_T_DEFINED"); Builder.defineMacro("_NATIVE_WCHAR_T_DEFINED"); + // FIXME: Support Microsoft's __identifier extension in the lexer. + Builder.append("#define __identifier(x) x"); Builder.append("class type_info;"); } @@ -570,6 +579,12 @@ void clang::InitializePreprocessor(Preprocessor &PP, InitializePredefinedMacros(PP.getTargetInfo(), PP.getLangOptions(), FEOpts, Builder); + // Even with predefines off, some macros are still predefined. + // These should all be defined in the preprocessor according to the + // current language configuration. + InitializeStandardPredefinedMacros(PP.getTargetInfo(), PP.getLangOptions(), + FEOpts, Builder); + // Add on the predefines from the driver. Wrap in a #line directive to report // that they come from the command line. if (!PP.getLangOptions().AsmPreprocessor) diff --git a/contrib/llvm/tools/clang/lib/Frontend/LogDiagnosticPrinter.cpp b/contrib/llvm/tools/clang/lib/Frontend/LogDiagnosticPrinter.cpp index 954bad4..78eb1b2 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/LogDiagnosticPrinter.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/LogDiagnosticPrinter.cpp @@ -99,7 +99,7 @@ void LogDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level, DiagnosticClient::HandleDiagnostic(Level, Info); // Initialize the main file name, if we haven't already fetched it. - if (MainFilename.empty()) { + if (MainFilename.empty() && Info.hasSourceManager()) { const SourceManager &SM = Info.getSourceManager(); FileID FID = SM.getMainFileID(); if (!FID.isInvalid()) { @@ -122,7 +122,7 @@ void LogDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level, // Set the location information. DE.Filename = ""; DE.Line = DE.Column = 0; - if (Info.getLocation().isValid()) { + if (Info.getLocation().isValid() && Info.hasSourceManager()) { const SourceManager &SM = Info.getSourceManager(); PresumedLoc PLoc = SM.getPresumedLoc(Info.getLocation()); diff --git a/contrib/llvm/tools/clang/lib/Frontend/TextDiagnosticPrinter.cpp b/contrib/llvm/tools/clang/lib/Frontend/TextDiagnosticPrinter.cpp index 47c942c..1c47bf7 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/TextDiagnosticPrinter.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/TextDiagnosticPrinter.cpp @@ -343,7 +343,7 @@ void TextDiagnosticPrinter::EmitCaretDiagnostic(Diagnostic::Level Level, // "included from" lines. if (LastWarningLoc != PLoc.getIncludeLoc()) { LastWarningLoc = PLoc.getIncludeLoc(); - PrintIncludeStack(Level, LastWarningLoc, SM); + PrintIncludeStack(Diagnostic::Note, LastWarningLoc, SM); } if (DiagOpts->ShowLocation) { @@ -819,16 +819,28 @@ void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level, if (DiagOpts->ShowColors) OS.changeColor(savedColor, true); - // Emit a Visual Studio compatible line number syntax. - if (LangOpts && LangOpts->Microsoft) { - OS << PLoc.getFilename() << '(' << LineNo << ')'; - OS << " : "; - } else { - OS << PLoc.getFilename() << ':' << LineNo << ':'; - if (DiagOpts->ShowColumn) - if (unsigned ColNo = PLoc.getColumn()) - OS << ColNo << ':'; + OS << PLoc.getFilename(); + switch (DiagOpts->Format) { + case DiagnosticOptions::Clang: OS << ':' << LineNo; break; + case DiagnosticOptions::Msvc: OS << '(' << LineNo; break; + case DiagnosticOptions::Vi: OS << " +" << LineNo; break; + } + if (DiagOpts->ShowColumn) + if (unsigned ColNo = PLoc.getColumn()) { + if (DiagOpts->Format == DiagnosticOptions::Msvc) { + OS << ','; + ColNo--; + } else + OS << ':'; + OS << ColNo; + } + switch (DiagOpts->Format) { + case DiagnosticOptions::Clang: + case DiagnosticOptions::Vi: OS << ':'; break; + case DiagnosticOptions::Msvc: OS << ") : "; break; } + + if (DiagOpts->ShowSourceRanges && Info.getNumRanges()) { FileID CaretFileID = SM.getFileID(SM.getInstantiationLoc(Info.getLocation())); @@ -927,8 +939,8 @@ void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level, OptionName += "-Werror"; } - if (const char * - Opt = DiagnosticIDs::getWarningOptionForDiag(Info.getID())) { + llvm::StringRef Opt = DiagnosticIDs::getWarningOptionForDiag(Info.getID()); + if (!Opt.empty()) { if (!OptionName.empty()) OptionName += ','; OptionName += "-W"; diff --git a/contrib/llvm/tools/clang/lib/Frontend/Warnings.cpp b/contrib/llvm/tools/clang/lib/Frontend/Warnings.cpp index 8cc5616..f12b484 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/Warnings.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/Warnings.cpp @@ -55,17 +55,14 @@ void clang::ProcessWarningOptions(Diagnostic &Diags, Diags.setExtensionHandlingBehavior(Diagnostic::Ext_Ignore); for (unsigned i = 0, e = Opts.Warnings.size(); i != e; ++i) { - const std::string &Opt = Opts.Warnings[i]; - const char *OptStart = &Opt[0]; - const char *OptEnd = OptStart+Opt.size(); - assert(*OptEnd == 0 && "Expect null termination for lower-bound search"); + llvm::StringRef Opt = Opts.Warnings[i]; // Check to see if this warning starts with "no-", if so, this is a negative // form of the option. bool isPositive = true; - if (OptEnd-OptStart > 3 && memcmp(OptStart, "no-", 3) == 0) { + if (Opt.startswith("no-")) { isPositive = false; - OptStart += 3; + Opt = Opt.substr(3); } // Figure out how this option affects the warning. If -Wfoo, map the @@ -74,49 +71,47 @@ void clang::ProcessWarningOptions(Diagnostic &Diags, // -Wsystem-headers is a special case, not driven by the option table. It // cannot be controlled with -Werror. - if (OptEnd-OptStart == 14 && memcmp(OptStart, "system-headers", 14) == 0) { + if (Opt == "system-headers") { Diags.setSuppressSystemWarnings(!isPositive); continue; } // -Werror/-Wno-error is a special case, not controlled by the option table. // It also has the "specifier" form of -Werror=foo and -Werror-foo. - if (OptEnd-OptStart >= 5 && memcmp(OptStart, "error", 5) == 0) { - const char *Specifier = 0; - if (OptEnd-OptStart != 5) { // Specifier must be present. - if ((OptStart[5] != '=' && OptStart[5] != '-') || - OptEnd-OptStart == 6) { + if (Opt.startswith("error")) { + llvm::StringRef Specifier; + if (Opt.size() > 5) { // Specifier must be present. + if ((Opt[5] != '=' && Opt[5] != '-') || Opt.size() == 6) { Diags.Report(diag::warn_unknown_warning_specifier) - << "-Werror" << ("-W" + Opt); + << "-Werror" << ("-W" + Opt.str()); continue; } - Specifier = OptStart+6; + Specifier = Opt.substr(6); } - if (Specifier == 0) { + if (Specifier.empty()) { Diags.setWarningsAsErrors(isPositive); continue; } // -Werror=foo maps foo to Error, -Wno-error=foo maps it to Warning. Mapping = isPositive ? diag::MAP_ERROR : diag::MAP_WARNING_NO_WERROR; - OptStart = Specifier; + Opt = Specifier; } // -Wfatal-errors is yet another special case. - if (OptEnd-OptStart >= 12 && memcmp(OptStart, "fatal-errors", 12) == 0) { - const char* Specifier = 0; - if (OptEnd-OptStart != 12) { - if ((OptStart[12] != '=' && OptStart[12] != '-') || - OptEnd-OptStart == 13) { + if (Opt.startswith("fatal-errors")) { + llvm::StringRef Specifier; + if (Opt.size() != 12) { + if ((Opt[12] != '=' && Opt[12] != '-') || Opt.size() == 13) { Diags.Report(diag::warn_unknown_warning_specifier) - << "-Wfatal-errors" << ("-W" + Opt); + << "-Wfatal-errors" << ("-W" + Opt.str()); continue; } - Specifier = OptStart + 13; + Specifier = Opt.substr(13); } - if (Specifier == 0) { + if (Specifier.empty()) { Diags.setErrorsAsFatal(isPositive); continue; } @@ -124,10 +119,12 @@ void clang::ProcessWarningOptions(Diagnostic &Diags, // -Wfatal-errors=foo maps foo to Fatal, -Wno-fatal-errors=foo // maps it to Error. Mapping = isPositive ? diag::MAP_FATAL : diag::MAP_ERROR_NO_WFATAL; - OptStart = Specifier; + Opt = Specifier; } - if (Diags.setDiagnosticGroupMapping(OptStart, Mapping)) - Diags.Report(diag::warn_unknown_warning_option) << ("-W" + Opt); + if (Diags.setDiagnosticGroupMapping(Opt, Mapping)) + Diags.Report(isPositive ? diag::warn_unknown_warning_option : + diag::warn_unknown_negative_warning_option) + << ("-W" + Opt.str()); } } diff --git a/contrib/llvm/tools/clang/lib/Headers/emmintrin.h b/contrib/llvm/tools/clang/lib/Headers/emmintrin.h index 0c1d730..ee12d3c 100644 --- a/contrib/llvm/tools/clang/lib/Headers/emmintrin.h +++ b/contrib/llvm/tools/clang/lib/Headers/emmintrin.h @@ -466,7 +466,10 @@ _mm_loadr_pd(double const *dp) static __inline__ __m128d __attribute__((__always_inline__, __nodebug__)) _mm_loadu_pd(double const *dp) { - return (__m128d){ dp[0], dp[1] }; + struct __loadu_pd { + __m128d v; + } __attribute__((packed, may_alias)); + return ((struct __loadu_pd*)dp)->v; } static __inline__ __m128d __attribute__((__always_inline__, __nodebug__)) @@ -478,13 +481,13 @@ _mm_load_sd(double const *dp) static __inline__ __m128d __attribute__((__always_inline__, __nodebug__)) _mm_loadh_pd(__m128d a, double const *dp) { - return __builtin_shufflevector(a, *(__m128d *)dp, 0, 2); + return (__m128d){ a[0], *dp }; } static __inline__ __m128d __attribute__((__always_inline__, __nodebug__)) _mm_loadl_pd(__m128d a, double const *dp) { - return __builtin_shufflevector(a, *(__m128d *)dp, 2, 1); + return (__m128d){ *dp, a[1] }; } static __inline__ __m128d __attribute__((__always_inline__, __nodebug__)) @@ -1011,7 +1014,10 @@ _mm_load_si128(__m128i const *p) static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_loadu_si128(__m128i const *p) { - return (__m128i)__builtin_ia32_loaddqu((char const *)p); + struct __loadu_si128 { + __m128i v; + } __attribute__((packed, may_alias)); + return ((struct __loadu_si128*)p)->v; } static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) diff --git a/contrib/llvm/tools/clang/lib/Headers/mmintrin.h b/contrib/llvm/tools/clang/lib/Headers/mmintrin.h index fefb42f..986870a 100644 --- a/contrib/llvm/tools/clang/lib/Headers/mmintrin.h +++ b/contrib/llvm/tools/clang/lib/Headers/mmintrin.h @@ -421,20 +421,20 @@ _mm_set1_pi8(char __b) } static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) -_mm_setr_pi32(int __i1, int __i0) +_mm_setr_pi32(int __i0, int __i1) { return _mm_set_pi32(__i1, __i0); } static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) -_mm_setr_pi16(short __w3, short __w2, short __w1, short __w0) +_mm_setr_pi16(short __w0, short __w1, short __w2, short __w3) { return _mm_set_pi16(__w3, __w2, __w1, __w0); } static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) -_mm_setr_pi8(char __b7, char __b6, char __b5, char __b4, char __b3, char __b2, - char __b1, char __b0) +_mm_setr_pi8(char __b0, char __b1, char __b2, char __b3, char __b4, char __b5, + char __b6, char __b7) { return _mm_set_pi8(__b7, __b6, __b5, __b4, __b3, __b2, __b1, __b0); } diff --git a/contrib/llvm/tools/clang/lib/Headers/xmmintrin.h b/contrib/llvm/tools/clang/lib/Headers/xmmintrin.h index 00760ed..50f275d 100644 --- a/contrib/llvm/tools/clang/lib/Headers/xmmintrin.h +++ b/contrib/llvm/tools/clang/lib/Headers/xmmintrin.h @@ -539,7 +539,10 @@ _mm_load_ps(const float *p) static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_loadu_ps(const float *p) { - return (__m128){ p[0], p[1], p[2], p[3] }; + struct __loadu_ps { + __m128 v; + } __attribute__((packed, may_alias)); + return ((struct __loadu_ps*)p)->v; } static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) diff --git a/contrib/llvm/tools/clang/lib/Index/CallGraph.cpp b/contrib/llvm/tools/clang/lib/Index/CallGraph.cpp index bf3f5a8..94790b8 100644 --- a/contrib/llvm/tools/clang/lib/Index/CallGraph.cpp +++ b/contrib/llvm/tools/clang/lib/Index/CallGraph.cpp @@ -74,7 +74,7 @@ void CallGraph::addTU(ASTContext& Ctx) { I != E; ++I) { if (FunctionDecl *FD = dyn_cast<FunctionDecl>(*I)) { - if (FD->isThisDeclarationADefinition()) { + if (FD->doesThisDeclarationHaveABody()) { // Set caller's ASTContext. Entity Ent = Entity::get(FD, Prog); CallGraphNode *Node = getOrInsertFunction(Ent); diff --git a/contrib/llvm/tools/clang/lib/Index/Indexer.cpp b/contrib/llvm/tools/clang/lib/Index/Indexer.cpp index 7f21c4f..ebba43c 100644 --- a/contrib/llvm/tools/clang/lib/Index/Indexer.cpp +++ b/contrib/llvm/tools/clang/lib/Index/Indexer.cpp @@ -39,7 +39,7 @@ public: Decl *D = Ent.getDecl(TU->getASTContext()); if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) - if (FD->isThisDeclarationADefinition()) + if (FD->doesThisDeclarationHaveABody()) DefMap[Ent] = std::make_pair(FD, TU); } }; diff --git a/contrib/llvm/tools/clang/lib/Lex/HeaderSearch.cpp b/contrib/llvm/tools/clang/lib/Lex/HeaderSearch.cpp index 372078c..bb43881 100644 --- a/contrib/llvm/tools/clang/lib/Lex/HeaderSearch.cpp +++ b/contrib/llvm/tools/clang/lib/Lex/HeaderSearch.cpp @@ -37,6 +37,7 @@ ExternalHeaderFileInfoSource::~ExternalHeaderFileInfoSource() {} HeaderSearch::HeaderSearch(FileManager &FM) : FileMgr(FM), FrameworkMap(64) { + AngledDirIdx = 0; SystemDirIdx = 0; NoCurDirSearch = false; @@ -317,7 +318,7 @@ const FileEntry *HeaderSearch::LookupFile( CurDir = 0; // If this is a system #include, ignore the user #include locs. - unsigned i = isAngled ? SystemDirIdx : 0; + unsigned i = isAngled ? AngledDirIdx : 0; // If this is a #include_next request, start searching after the directory the // file was found in. @@ -482,6 +483,21 @@ HeaderFileInfo &HeaderSearch::getFileInfo(const FileEntry *FE) { return HFI; } +bool HeaderSearch::isFileMultipleIncludeGuarded(const FileEntry *File) { + // Check if we've ever seen this file as a header. + if (File->getUID() >= FileInfo.size()) + return false; + + // Resolve header file info from the external source, if needed. + HeaderFileInfo &HFI = FileInfo[File->getUID()]; + if (ExternalSource && !HFI.Resolved) { + HFI = ExternalSource->GetHeaderFileInfo(File); + HFI.Resolved = true; + } + + return HFI.isPragmaOnce || HFI.ControllingMacro || HFI.ControllingMacroID; +} + void HeaderSearch::setHeaderFileInfoForUID(HeaderFileInfo HFI, unsigned UID) { if (UID >= FileInfo.size()) FileInfo.resize(UID+1); diff --git a/contrib/llvm/tools/clang/lib/Lex/Lexer.cpp b/contrib/llvm/tools/clang/lib/Lex/Lexer.cpp index 16cc4f8..3b1149c 100644 --- a/contrib/llvm/tools/clang/lib/Lex/Lexer.cpp +++ b/contrib/llvm/tools/clang/lib/Lex/Lexer.cpp @@ -76,7 +76,8 @@ void Lexer::InitLexer(const char *BufStart, const char *BufPtr, // skip the UTF-8 BOM if it's present. if (BufferStart == BufferPtr) { // Determine the size of the BOM. - size_t BOMLength = llvm::StringSwitch<size_t>(BufferStart) + llvm::StringRef Buf(BufferStart, BufferEnd - BufferStart); + size_t BOMLength = llvm::StringSwitch<size_t>(Buf) .StartsWith("\xEF\xBB\xBF", 3) // UTF-8 BOM .Default(0); diff --git a/contrib/llvm/tools/clang/lib/Lex/LiteralSupport.cpp b/contrib/llvm/tools/clang/lib/Lex/LiteralSupport.cpp index 37e7bf4..2c96c4d 100644 --- a/contrib/llvm/tools/clang/lib/Lex/LiteralSupport.cpp +++ b/contrib/llvm/tools/clang/lib/Lex/LiteralSupport.cpp @@ -840,16 +840,27 @@ StringLiteralParser:: StringLiteralParser(const Token *StringToks, unsigned NumStringToks, Preprocessor &PP, bool Complain) : SM(PP.getSourceManager()), Features(PP.getLangOptions()), - Target(PP.getTargetInfo()), Diags(Complain ? &PP.getDiagnostics() : 0) { + Target(PP.getTargetInfo()), Diags(Complain ? &PP.getDiagnostics() : 0), + MaxTokenLength(0), SizeBound(0), wchar_tByteWidth(0), + ResultPtr(ResultBuf.data()), hadError(false), AnyWide(false), Pascal(false) { init(StringToks, NumStringToks); } void StringLiteralParser::init(const Token *StringToks, unsigned NumStringToks){ + // The literal token may have come from an invalid source location (e.g. due + // to a PCH error), in which case the token length will be 0. + if (NumStringToks == 0 || StringToks[0].getLength() < 2) { + hadError = true; + return; + } + // Scan all of the string portions, remember the max individual token length, // computing a bound on the concatenated string length, and see whether any // piece is a wide-string. If any of the string portions is a wide-string // literal, the result is a wide-string literal [C99 6.4.5p4]. + assert(NumStringToks && "expected at least one token"); MaxTokenLength = StringToks[0].getLength(); + assert(StringToks[0].getLength() >= 2 && "literal token is invalid!"); SizeBound = StringToks[0].getLength()-2; // -2 for "". AnyWide = StringToks[0].is(tok::wide_string_literal); @@ -858,8 +869,14 @@ void StringLiteralParser::init(const Token *StringToks, unsigned NumStringToks){ // Implement Translation Phase #6: concatenation of string literals /// (C99 5.1.1.2p1). The common case is only one string fragment. for (unsigned i = 1; i != NumStringToks; ++i) { + if (StringToks[i].getLength() < 2) { + hadError = true; + return; + } + // The string could be shorter than this if it needs cleaning, but this is a // reasonable bound, which is all we need. + assert(StringToks[i].getLength() >= 2 && "literal token is invalid!"); SizeBound += StringToks[i].getLength()-2; // -2 for "". // Remember maximum string piece length. diff --git a/contrib/llvm/tools/clang/lib/Lex/MacroInfo.cpp b/contrib/llvm/tools/clang/lib/Lex/MacroInfo.cpp index c819011..66d87a1 100644 --- a/contrib/llvm/tools/clang/lib/Lex/MacroInfo.cpp +++ b/contrib/llvm/tools/clang/lib/Lex/MacroInfo.cpp @@ -42,6 +42,7 @@ MacroInfo::MacroInfo(const MacroInfo &MI, llvm::BumpPtrAllocator &PPAllocator) { IsDisabled = MI.IsDisabled; IsUsed = MI.IsUsed; IsAllowRedefinitionsWithoutWarning = MI.IsAllowRedefinitionsWithoutWarning; + IsWarnIfUnused = MI.IsWarnIfUnused; ArgumentList = 0; NumArguments = 0; setArgumentList(MI.ArgumentList, MI.NumArguments, PPAllocator); diff --git a/contrib/llvm/tools/clang/lib/Lex/PPDirectives.cpp b/contrib/llvm/tools/clang/lib/Lex/PPDirectives.cpp index af3fa6e..66e44bb 100644 --- a/contrib/llvm/tools/clang/lib/Lex/PPDirectives.cpp +++ b/contrib/llvm/tools/clang/lib/Lex/PPDirectives.cpp @@ -323,7 +323,6 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation IfTokenLoc, // #else directive in a skipping conditional. If not in some other // skipping conditional, and if #else hasn't already been seen, enter it // as a non-skipping conditional. - DiscardUntilEndOfDirective(); // C99 6.10p4. PPConditionalInfo &CondInfo = CurPPLexer->peekConditionalLevel(); // If this is a #else with a #else before it, report the error. @@ -339,7 +338,10 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation IfTokenLoc, // entered, enter the #else block now. if (!CondInfo.WasSkipping && !CondInfo.FoundNonSkip) { CondInfo.FoundNonSkip = true; + CheckEndOfDirective("else"); break; + } else { + DiscardUntilEndOfDirective(); // C99 6.10p4. } } else if (Sub == "lif") { // "elif". PPConditionalInfo &CondInfo = CurPPLexer->peekConditionalLevel(); diff --git a/contrib/llvm/tools/clang/lib/Lex/PPMacroExpansion.cpp b/contrib/llvm/tools/clang/lib/Lex/PPMacroExpansion.cpp index d6e0d3a..01cd75f 100644 --- a/contrib/llvm/tools/clang/lib/Lex/PPMacroExpansion.cpp +++ b/contrib/llvm/tools/clang/lib/Lex/PPMacroExpansion.cpp @@ -85,6 +85,7 @@ void Preprocessor::RegisterBuiltinMacros() { // Clang Extensions. Ident__has_feature = RegisterBuiltinMacro(*this, "__has_feature"); + Ident__has_extension = RegisterBuiltinMacro(*this, "__has_extension"); Ident__has_builtin = RegisterBuiltinMacro(*this, "__has_builtin"); Ident__has_attribute = RegisterBuiltinMacro(*this, "__has_attribute"); Ident__has_include = RegisterBuiltinMacro(*this, "__has_include"); @@ -525,8 +526,8 @@ static void ComputeDATE_TIME(SourceLocation &DATELoc, SourceLocation &TIMELoc, } -/// HasFeature - Return true if we recognize and implement the specified feature -/// specified by the identifier. +/// HasFeature - Return true if we recognize and implement the feature +/// specified by the identifier as a standard language feature. static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) { const LangOptions &LangOpts = PP.getLangOptions(); @@ -550,13 +551,17 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) { .Case("cxx_exceptions", LangOpts.Exceptions) .Case("cxx_rtti", LangOpts.RTTI) .Case("enumerator_attributes", true) - .Case("generic_selections", true) .Case("objc_nonfragile_abi", LangOpts.ObjCNonFragileABI) .Case("objc_weak_class", LangOpts.ObjCNonFragileABI) .Case("ownership_holds", true) .Case("ownership_returns", true) .Case("ownership_takes", true) + // C1X features + .Case("c_generic_selections", LangOpts.C1X) + .Case("c_static_assert", LangOpts.C1X) // C++0x features + .Case("cxx_access_control_sfinae", LangOpts.CPlusPlus0x) + .Case("cxx_alias_templates", LangOpts.CPlusPlus0x) .Case("cxx_attributes", LangOpts.CPlusPlus0x) .Case("cxx_auto_type", LangOpts.CPlusPlus0x) .Case("cxx_decltype", LangOpts.CPlusPlus0x) @@ -566,7 +571,7 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) { .Case("cxx_inline_namespaces", LangOpts.CPlusPlus0x) //.Case("cxx_lambdas", false) .Case("cxx_noexcept", LangOpts.CPlusPlus0x) - //.Case("cxx_nullptr", false) + .Case("cxx_nullptr", LangOpts.CPlusPlus0x) .Case("cxx_override_control", LangOpts.CPlusPlus0x) .Case("cxx_range_for", LangOpts.CPlusPlus0x) .Case("cxx_reference_qualified_functions", LangOpts.CPlusPlus0x) @@ -591,14 +596,45 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) { .Case("is_empty", LangOpts.CPlusPlus) .Case("is_enum", LangOpts.CPlusPlus) .Case("is_literal", LangOpts.CPlusPlus) + .Case("is_standard_layout", LangOpts.CPlusPlus) .Case("is_pod", LangOpts.CPlusPlus) .Case("is_polymorphic", LangOpts.CPlusPlus) .Case("is_trivial", LangOpts.CPlusPlus) + .Case("is_trivially_copyable", LangOpts.CPlusPlus) .Case("is_union", LangOpts.CPlusPlus) .Case("tls", PP.getTargetInfo().isTLSSupported()) .Default(false); } +/// HasExtension - Return true if we recognize and implement the feature +/// specified by the identifier, either as an extension or a standard language +/// feature. +static bool HasExtension(const Preprocessor &PP, const IdentifierInfo *II) { + if (HasFeature(PP, II)) + return true; + + // If the use of an extension results in an error diagnostic, extensions are + // effectively unavailable, so just return false here. + if (PP.getDiagnostics().getExtensionHandlingBehavior()==Diagnostic::Ext_Error) + return false; + + const LangOptions &LangOpts = PP.getLangOptions(); + + // Because we inherit the feature list from HasFeature, this string switch + // must be less restrictive than HasFeature's. + return llvm::StringSwitch<bool>(II->getName()) + // C1X features supported by other languages as extensions. + .Case("c_generic_selections", true) + .Case("c_static_assert", true) + // C++0x features supported by other languages as extensions. + .Case("cxx_deleted_functions", LangOpts.CPlusPlus) + .Case("cxx_inline_namespaces", LangOpts.CPlusPlus) + .Case("cxx_override_control", LangOpts.CPlusPlus) + .Case("cxx_reference_qualified_functions", LangOpts.CPlusPlus) + .Case("cxx_rvalue_references", LangOpts.CPlusPlus) + .Default(false); +} + /// HasAttribute - Return true if we recognize and implement the attribute /// specified by the given identifier. static bool HasAttribute(const IdentifierInfo *II) { @@ -847,10 +883,11 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) { // __COUNTER__ expands to a simple numeric value. OS << CounterValue++; Tok.setKind(tok::numeric_constant); - } else if (II == Ident__has_feature || - II == Ident__has_builtin || + } else if (II == Ident__has_feature || + II == Ident__has_extension || + II == Ident__has_builtin || II == Ident__has_attribute) { - // The argument to these two builtins should be a parenthesized identifier. + // The argument to these builtins should be a parenthesized identifier. SourceLocation StartLoc = Tok.getLocation(); bool IsValid = false; @@ -879,6 +916,8 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) { Value = FeatureII->getBuiltinID() != 0; } else if (II == Ident__has_attribute) Value = HasAttribute(FeatureII); + else if (II == Ident__has_extension) + Value = HasExtension(*this, FeatureII); else { assert(II == Ident__has_feature && "Must be feature check"); Value = HasFeature(*this, FeatureII); diff --git a/contrib/llvm/tools/clang/lib/Lex/Pragma.cpp b/contrib/llvm/tools/clang/lib/Lex/Pragma.cpp index 0c18091..23855d4 100644 --- a/contrib/llvm/tools/clang/lib/Lex/Pragma.cpp +++ b/contrib/llvm/tools/clang/lib/Lex/Pragma.cpp @@ -330,16 +330,16 @@ void Preprocessor::HandlePragmaSystemHeader(Token &SysHeaderTok) { unsigned FilenameID = SourceMgr.getLineTableFilenameID(PLoc.getFilename(), FilenameLen); + // Notify the client, if desired, that we are in a new source file. + if (Callbacks) + Callbacks->FileChanged(SysHeaderTok.getLocation(), + PPCallbacks::SystemHeaderPragma, SrcMgr::C_System); + // Emit a line marker. This will change any source locations from this point // forward to realize they are in a system header. // Create a line note with this information. SourceMgr.AddLineNote(SysHeaderTok.getLocation(), PLoc.getLine(), FilenameID, false, false, true, false); - - // Notify the client, if desired, that we are in a new source file. - if (Callbacks) - Callbacks->FileChanged(SysHeaderTok.getLocation(), - PPCallbacks::SystemHeaderPragma, SrcMgr::C_System); } /// HandlePragmaDependency - Handle #pragma GCC dependency "foo" blah. @@ -824,9 +824,17 @@ struct PragmaDebugHandler : public PragmaHandler { } } +// Disable MSVC warning about runtime stack overflow. +#ifdef _MSC_VER + #pragma warning(disable : 4717) +#endif void DebugOverflowStack() { DebugOverflowStack(); } +#ifdef _MSC_VER + #pragma warning(default : 4717) +#endif + }; /// PragmaDiagnosticHandler - e.g. '#pragma GCC diagnostic ignored "-Wformat"' @@ -898,8 +906,7 @@ public: return; } - std::string WarningName(Literal.GetString(), - Literal.GetString()+Literal.GetStringLength()); + llvm::StringRef WarningName(Literal.GetString(), Literal.GetStringLength()); if (WarningName.size() < 3 || WarningName[0] != '-' || WarningName[1] != 'W') { @@ -908,7 +915,7 @@ public: return; } - if (PP.getDiagnostics().setDiagnosticGroupMapping(WarningName.c_str()+2, + if (PP.getDiagnostics().setDiagnosticGroupMapping(WarningName.substr(2), Map, DiagLoc)) PP.Diag(StrToks[0].getLocation(), diag::warn_pragma_diagnostic_unknown_warning) << WarningName; diff --git a/contrib/llvm/tools/clang/lib/Lex/PreprocessingRecord.cpp b/contrib/llvm/tools/clang/lib/Lex/PreprocessingRecord.cpp index 9555611..0c8d948 100644 --- a/contrib/llvm/tools/clang/lib/Lex/PreprocessingRecord.cpp +++ b/contrib/llvm/tools/clang/lib/Lex/PreprocessingRecord.cpp @@ -45,8 +45,9 @@ void PreprocessingRecord::MaybeLoadPreallocatedEntities() const { ExternalSource->ReadPreprocessedEntities(); } -PreprocessingRecord::PreprocessingRecord() - : ExternalSource(0), NumPreallocatedEntities(0), +PreprocessingRecord::PreprocessingRecord(bool IncludeNestedMacroInstantiations) + : IncludeNestedMacroInstantiations(IncludeNestedMacroInstantiations), + ExternalSource(0), NumPreallocatedEntities(0), LoadedPreallocatedEntities(false) { } @@ -120,6 +121,9 @@ MacroDefinition *PreprocessingRecord::findMacroDefinition(const MacroInfo *MI) { } void PreprocessingRecord::MacroExpands(const Token &Id, const MacroInfo* MI) { + if (!IncludeNestedMacroInstantiations && Id.getLocation().isMacroID()) + return; + if (MacroDefinition *Def = findMacroDefinition(MI)) PreprocessedEntities.push_back( new (*this) MacroInstantiation(Id.getIdentifierInfo(), diff --git a/contrib/llvm/tools/clang/lib/Lex/Preprocessor.cpp b/contrib/llvm/tools/clang/lib/Lex/Preprocessor.cpp index 31fd667..fdc18f8 100644 --- a/contrib/llvm/tools/clang/lib/Lex/Preprocessor.cpp +++ b/contrib/llvm/tools/clang/lib/Lex/Preprocessor.cpp @@ -527,10 +527,11 @@ CommentHandler::~CommentHandler() { } CodeCompletionHandler::~CodeCompletionHandler() { } -void Preprocessor::createPreprocessingRecord() { +void Preprocessor::createPreprocessingRecord( + bool IncludeNestedMacroInstantiations) { if (Record) return; - Record = new PreprocessingRecord; + Record = new PreprocessingRecord(IncludeNestedMacroInstantiations); addPPCallbacks(Record); } diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseCXXInlineMethods.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseCXXInlineMethods.cpp index 87e2f34..f5c6998 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParseCXXInlineMethods.cpp +++ b/contrib/llvm/tools/clang/lib/Parse/ParseCXXInlineMethods.cpp @@ -23,10 +23,11 @@ using namespace clang; /// and store its tokens for parsing after the C++ class is complete. Decl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, ParsingDeclarator &D, const ParsedTemplateInfo &TemplateInfo, - const VirtSpecifiers& VS) { + const VirtSpecifiers& VS, ExprResult& Init) { assert(D.isFunctionDeclarator() && "This isn't a function declarator!"); - assert((Tok.is(tok::l_brace) || Tok.is(tok::colon) || Tok.is(tok::kw_try)) && - "Current token not a '{', ':' or 'try'!"); + assert((Tok.is(tok::l_brace) || Tok.is(tok::colon) || Tok.is(tok::kw_try) || + Tok.is(tok::equal)) && + "Current token not a '{', ':', '=', or 'try'!"); MultiTemplateParamsArg TemplateParams(Actions, TemplateInfo.TemplateParams ? TemplateInfo.TemplateParams->data() : 0, @@ -40,13 +41,49 @@ Decl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, ParsingDeclarator &D, else { // FIXME: pass template information through FnD = Actions.ActOnCXXMemberDeclarator(getCurScope(), AS, D, move(TemplateParams), 0, - VS, 0, /*IsDefinition*/true); + VS, Init.release(), + /*HasInit=*/false, + /*IsDefinition*/true); } HandleMemberFunctionDefaultArgs(D, FnD); D.complete(FnD); + if (Tok.is(tok::equal)) { + ConsumeToken(); + + bool Delete = false; + SourceLocation KWLoc; + if (Tok.is(tok::kw_delete)) { + if (!getLang().CPlusPlus0x) + Diag(Tok, diag::warn_deleted_function_accepted_as_extension); + + KWLoc = ConsumeToken(); + Actions.SetDeclDeleted(FnD, KWLoc); + Delete = true; + } else if (Tok.is(tok::kw_default)) { + if (!getLang().CPlusPlus0x) + Diag(Tok, diag::warn_defaulted_function_accepted_as_extension); + + KWLoc = ConsumeToken(); + Actions.SetDeclDefaulted(FnD, KWLoc); + } else { + llvm_unreachable("function definition after = not 'delete' or 'default'"); + } + + if (Tok.is(tok::comma)) { + Diag(KWLoc, diag::err_default_delete_in_multiple_declaration) + << Delete; + SkipUntil(tok::semi); + } else { + ExpectAndConsume(tok::semi, diag::err_expected_semi_after, + Delete ? "delete" : "default", tok::semi); + } + + return FnD; + } + // In delayed template parsing mode, if we are within a class template // or if we are about to parse function member template then consume // the tokens and store them for parsing at the end of the translation unit. @@ -130,8 +167,50 @@ Decl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, ParsingDeclarator &D, return FnD; } +/// ParseCXXNonStaticMemberInitializer - We parsed and verified that the +/// specified Declarator is a well formed C++ non-static data member +/// declaration. Now lex its initializer and store its tokens for parsing +/// after the class is complete. +void Parser::ParseCXXNonStaticMemberInitializer(Decl *VarD) { + assert((Tok.is(tok::l_brace) || Tok.is(tok::equal)) && + "Current token not a '{' or '='!"); + + LateParsedMemberInitializer *MI = + new LateParsedMemberInitializer(this, VarD); + getCurrentClass().LateParsedDeclarations.push_back(MI); + CachedTokens &Toks = MI->Toks; + + tok::TokenKind kind = Tok.getKind(); + if (kind == tok::equal) { + Toks.push_back(Tok); + ConsumeAnyToken(); + } + + if (kind == tok::l_brace) { + // Begin by storing the '{' token. + Toks.push_back(Tok); + ConsumeBrace(); + + // Consume everything up to (and including) the matching right brace. + ConsumeAndStoreUntil(tok::r_brace, Toks, /*StopAtSemi=*/true); + } else { + // Consume everything up to (but excluding) the comma or semicolon. + ConsumeAndStoreUntil(tok::comma, Toks, /*StopAtSemi=*/true, + /*ConsumeFinalToken=*/false); + } + + // Store an artificial EOF token to ensure that we don't run off the end of + // the initializer when we come to parse it. + Token Eof; + Eof.startToken(); + Eof.setKind(tok::eof); + Eof.setLocation(Tok.getLocation()); + Toks.push_back(Eof); +} + Parser::LateParsedDeclaration::~LateParsedDeclaration() {} void Parser::LateParsedDeclaration::ParseLexedMethodDeclarations() {} +void Parser::LateParsedDeclaration::ParseLexedMemberInitializers() {} void Parser::LateParsedDeclaration::ParseLexedMethodDefs() {} Parser::LateParsedClass::LateParsedClass(Parser *P, ParsingClass *C) @@ -145,6 +224,10 @@ void Parser::LateParsedClass::ParseLexedMethodDeclarations() { Self->ParseLexedMethodDeclarations(*Class); } +void Parser::LateParsedClass::ParseLexedMemberInitializers() { + Self->ParseLexedMemberInitializers(*Class); +} + void Parser::LateParsedClass::ParseLexedMethodDefs() { Self->ParseLexedMethodDefs(*Class); } @@ -157,6 +240,10 @@ void Parser::LexedMethod::ParseLexedMethodDefs() { Self->ParseLexedMethodDef(*this); } +void Parser::LateParsedMemberInitializer::ParseLexedMemberInitializers() { + Self->ParseLexedMemberInitializer(*this); +} + /// ParseLexedMethodDeclarations - We finished parsing the member /// specification of a top (non-nested) C++ class. Now go over the /// stack of method declarations with some parts for which parsing was @@ -328,8 +415,70 @@ void Parser::ParseLexedMethodDef(LexedMethod &LM) { origLoc)) while (Tok.getLocation() != origLoc && Tok.isNot(tok::eof)) ConsumeAnyToken(); + } +} + +/// ParseLexedMemberInitializers - We finished parsing the member specification +/// of a top (non-nested) C++ class. Now go over the stack of lexed data member +/// initializers that were collected during its parsing and parse them all. +void Parser::ParseLexedMemberInitializers(ParsingClass &Class) { + bool HasTemplateScope = !Class.TopLevelClass && Class.TemplateScope; + ParseScope ClassTemplateScope(this, Scope::TemplateParamScope, + HasTemplateScope); + if (HasTemplateScope) + Actions.ActOnReenterTemplateScope(getCurScope(), Class.TagOrTemplate); + // Set or update the scope flags to include Scope::ThisScope. + bool AlreadyHasClassScope = Class.TopLevelClass; + unsigned ScopeFlags = Scope::ClassScope|Scope::DeclScope|Scope::ThisScope; + ParseScope ClassScope(this, ScopeFlags, !AlreadyHasClassScope); + ParseScopeFlags ClassScopeFlags(this, ScopeFlags, AlreadyHasClassScope); + + if (!AlreadyHasClassScope) + Actions.ActOnStartDelayedMemberDeclarations(getCurScope(), + Class.TagOrTemplate); + + for (size_t i = 0; i < Class.LateParsedDeclarations.size(); ++i) { + Class.LateParsedDeclarations[i]->ParseLexedMemberInitializers(); } + + if (!AlreadyHasClassScope) + Actions.ActOnFinishDelayedMemberDeclarations(getCurScope(), + Class.TagOrTemplate); + + Actions.ActOnFinishDelayedMemberInitializers(Class.TagOrTemplate); +} + +void Parser::ParseLexedMemberInitializer(LateParsedMemberInitializer &MI) { + if (MI.Field->isInvalidDecl()) + return; + + // Append the current token at the end of the new token stream so that it + // doesn't get lost. + MI.Toks.push_back(Tok); + PP.EnterTokenStream(MI.Toks.data(), MI.Toks.size(), true, false); + + // Consume the previously pushed token. + ConsumeAnyToken(); + + SourceLocation EqualLoc; + ExprResult Init = ParseCXXMemberInitializer(/*IsFunction=*/false, EqualLoc); + + Actions.ActOnCXXInClassMemberInitializer(MI.Field, EqualLoc, Init.release()); + + // The next token should be our artificial terminating EOF token. + if (Tok.isNot(tok::eof)) { + SourceLocation EndLoc = PP.getLocForEndOfToken(PrevTokLocation); + if (!EndLoc.isValid()) + EndLoc = Tok.getLocation(); + // No fixit; we can't recover as if there were a semicolon here. + Diag(EndLoc, diag::err_expected_semi_decl_list); + + // Consume tokens until we hit the artificial EOF. + while (Tok.isNot(tok::eof)) + ConsumeAnyToken(); + } + ConsumeAnyToken(); } /// ConsumeAndStoreUntil - Consume and store the token at the passed token diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseDecl.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseDecl.cpp index a20e90b..ad3fcfe 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParseDecl.cpp +++ b/contrib/llvm/tools/clang/lib/Parse/ParseDecl.cpp @@ -253,9 +253,17 @@ void Parser::ParseMicrosoftDeclSpec(ParsedAttributes &attrs) { SkipUntil(tok::r_paren, true); // skip until ) or ; return; } + while (Tok.getIdentifierInfo()) { IdentifierInfo *AttrName = Tok.getIdentifierInfo(); SourceLocation AttrNameLoc = ConsumeToken(); + + // FIXME: Remove this when we have proper __declspec(property()) support. + // Just skip everything inside property(). + if (AttrName->getName() == "property") { + ConsumeParen(); + SkipUntil(tok::r_paren); + } if (Tok.is(tok::l_paren)) { ConsumeParen(); // FIXME: This doesn't parse __declspec(property(get=get_func_name)) @@ -806,8 +814,10 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, // analyzed. if (FRI && Tok.is(tok::colon)) { FRI->ColonLoc = ConsumeToken(); - // FIXME: handle braced-init-list here. - FRI->RangeExpr = ParseExpression(); + if (Tok.is(tok::l_brace)) + FRI->RangeExpr = ParseBraceInitializer(); + else + FRI->RangeExpr = ParseExpression(); Decl *ThisDecl = Actions.ActOnDeclarator(getCurScope(), D); Actions.ActOnCXXForRangeDecl(ThisDecl); Actions.FinalizeDeclaration(ThisDecl); @@ -906,6 +916,7 @@ bool Parser::ParseAttributesAfterDeclarator(Declarator &D) { /// [C++] '(' expression-list ')' /// [C++0x] '=' 'default' [TODO] /// [C++0x] '=' 'delete' +/// [C++0x] braced-init-list /// /// According to the standard grammar, =default and =delete are function /// definitions, but that definitely doesn't fit with the parser here. @@ -960,12 +971,17 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D, diag::err_invalid_equalequal_after_declarator)) { ConsumeToken(); if (Tok.is(tok::kw_delete)) { - SourceLocation DelLoc = ConsumeToken(); - - if (!getLang().CPlusPlus0x) - Diag(DelLoc, diag::warn_deleted_function_accepted_as_extension); - - Actions.SetDeclDeleted(ThisDecl, DelLoc); + if (D.isFunctionDeclarator()) + Diag(ConsumeToken(), diag::err_default_delete_in_multiple_declaration) + << 1 /* delete */; + else + Diag(ConsumeToken(), diag::err_deleted_non_function); + } else if (Tok.is(tok::kw_default)) { + if (D.isFunctionDeclarator()) + Diag(Tok, diag::err_default_delete_in_multiple_declaration) + << 1 /* delete */; + else + Diag(ConsumeToken(), diag::err_default_special_members); } else { if (getLang().CPlusPlus && D.getCXXScopeSpec().isSet()) { EnterScope(0); @@ -1028,6 +1044,26 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D, RParenLoc, TypeContainsAuto); } + } else if (getLang().CPlusPlus0x && Tok.is(tok::l_brace)) { + // Parse C++0x braced-init-list. + if (D.getCXXScopeSpec().isSet()) { + EnterScope(0); + Actions.ActOnCXXEnterDeclInitializer(getCurScope(), ThisDecl); + } + + ExprResult Init(ParseBraceInitializer()); + + if (D.getCXXScopeSpec().isSet()) { + Actions.ActOnCXXExitDeclInitializer(getCurScope(), ThisDecl); + ExitScope(); + } + + if (Init.isInvalid()) { + Actions.ActOnInitializerError(ThisDecl); + } else + Actions.AddInitializerToDecl(ThisDecl, Init.take(), + /*DirectInit=*/true, TypeContainsAuto); + } else { Actions.ActOnUninitializedDecl(ThisDecl, TypeContainsAuto); } @@ -1846,6 +1882,9 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, ParseDecltypeSpecifier(DS); continue; + case tok::kw___underlying_type: + ParseUnderlyingTypeSpecifier(DS); + // OpenCL qualifiers: case tok::kw_private: if (!getLang().OpenCL) @@ -2116,6 +2155,11 @@ bool Parser::ParseOptionalTypeSpecifier(DeclSpec &DS, bool& isInvalid, ParseDecltypeSpecifier(DS); return true; + // C++0x type traits support. + case tok::kw___underlying_type: + ParseUnderlyingTypeSpecifier(DS); + return true; + // OpenCL qualifiers: case tok::kw_private: if (!getLang().OpenCL) diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseDeclCXX.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseDeclCXX.cpp index 8c0aa1b..51aa010 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParseDeclCXX.cpp +++ b/contrib/llvm/tools/clang/lib/Parse/ParseDeclCXX.cpp @@ -60,12 +60,20 @@ Decl *Parser::ParseNamespace(unsigned Context, SourceLocation IdentLoc; IdentifierInfo *Ident = 0; + std::vector<SourceLocation> ExtraIdentLoc; + std::vector<IdentifierInfo*> ExtraIdent; + std::vector<SourceLocation> ExtraNamespaceLoc; Token attrTok; if (Tok.is(tok::identifier)) { Ident = Tok.getIdentifierInfo(); IdentLoc = ConsumeToken(); // eat the identifier. + while (Tok.is(tok::coloncolon) && NextToken().is(tok::identifier)) { + ExtraNamespaceLoc.push_back(ConsumeToken()); + ExtraIdent.push_back(Tok.getIdentifierInfo()); + ExtraIdentLoc.push_back(ConsumeToken()); + } } // Read label attributes, if present. @@ -85,7 +93,12 @@ Decl *Parser::ParseNamespace(unsigned Context, return ParseNamespaceAlias(NamespaceLoc, IdentLoc, Ident, DeclEnd); } + if (Tok.isNot(tok::l_brace)) { + if (!ExtraIdent.empty()) { + Diag(ExtraNamespaceLoc[0], diag::err_nested_namespaces_with_double_colon) + << SourceRange(ExtraNamespaceLoc.front(), ExtraIdentLoc.back()); + } Diag(Tok, Ident ? diag::err_expected_lbrace : diag::err_expected_ident_lbrace); return 0; @@ -96,11 +109,44 @@ Decl *Parser::ParseNamespace(unsigned Context, if (getCurScope()->isClassScope() || getCurScope()->isTemplateParamScope() || getCurScope()->isInObjcMethodScope() || getCurScope()->getBlockParent() || getCurScope()->getFnParent()) { + if (!ExtraIdent.empty()) { + Diag(ExtraNamespaceLoc[0], diag::err_nested_namespaces_with_double_colon) + << SourceRange(ExtraNamespaceLoc.front(), ExtraIdentLoc.back()); + } Diag(LBrace, diag::err_namespace_nonnamespace_scope); SkipUntil(tok::r_brace, false); return 0; } + if (!ExtraIdent.empty()) { + TentativeParsingAction TPA(*this); + SkipUntil(tok::r_brace, /*StopAtSemi*/false, /*DontConsume*/true); + Token rBraceToken = Tok; + TPA.Revert(); + + if (!rBraceToken.is(tok::r_brace)) { + Diag(ExtraNamespaceLoc[0], diag::err_nested_namespaces_with_double_colon) + << SourceRange(ExtraNamespaceLoc.front(), ExtraIdentLoc.back()); + } else { + std::string NamespaceFix; + for (std::vector<IdentifierInfo*>::iterator I = ExtraIdent.begin(), + E = ExtraIdent.end(); I != E; ++I) { + NamespaceFix += " { namespace "; + NamespaceFix += (*I)->getName(); + } + + std::string RBraces; + for (unsigned i = 0, e = ExtraIdent.size(); i != e; ++i) + RBraces += "} "; + + Diag(ExtraNamespaceLoc[0], diag::err_nested_namespaces_with_double_colon) + << FixItHint::CreateReplacement(SourceRange(ExtraNamespaceLoc.front(), + ExtraIdentLoc.back()), + NamespaceFix) + << FixItHint::CreateInsertion(rBraceToken.getLocation(), RBraces); + } + } + // If we're still good, complain about inline namespaces in non-C++0x now. if (!getLang().CPlusPlus0x && InlineLoc.isValid()) Diag(InlineLoc, diag::ext_inline_namespace); @@ -115,23 +161,56 @@ Decl *Parser::ParseNamespace(unsigned Context, PrettyDeclStackTraceEntry CrashInfo(Actions, NamespcDecl, NamespaceLoc, "parsing namespace"); - while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { - ParsedAttributesWithRange attrs(AttrFactory); - MaybeParseCXX0XAttributes(attrs); - MaybeParseMicrosoftAttributes(attrs); - ParseExternalDeclaration(attrs); - } + SourceLocation RBraceLoc; + // Parse the contents of the namespace. This includes parsing recovery on + // any improperly nested namespaces. + ParseInnerNamespace(ExtraIdentLoc, ExtraIdent, ExtraNamespaceLoc, 0, + InlineLoc, LBrace, attrs, RBraceLoc); // Leave the namespace scope. NamespaceScope.Exit(); - SourceLocation RBraceLoc = MatchRHSPunctuation(tok::r_brace, LBrace); Actions.ActOnFinishNamespaceDef(NamespcDecl, RBraceLoc); DeclEnd = RBraceLoc; return NamespcDecl; } +/// ParseInnerNamespace - Parse the contents of a namespace. +void Parser::ParseInnerNamespace(std::vector<SourceLocation>& IdentLoc, + std::vector<IdentifierInfo*>& Ident, + std::vector<SourceLocation>& NamespaceLoc, + unsigned int index, SourceLocation& InlineLoc, + SourceLocation& LBrace, + ParsedAttributes& attrs, + SourceLocation& RBraceLoc) { + if (index == Ident.size()) { + while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { + ParsedAttributesWithRange attrs(AttrFactory); + MaybeParseCXX0XAttributes(attrs); + MaybeParseMicrosoftAttributes(attrs); + ParseExternalDeclaration(attrs); + } + RBraceLoc = MatchRHSPunctuation(tok::r_brace, LBrace); + + return; + } + + // Parse improperly nested namespaces. + ParseScope NamespaceScope(this, Scope::DeclScope); + Decl *NamespcDecl = + Actions.ActOnStartNamespaceDef(getCurScope(), SourceLocation(), + NamespaceLoc[index], IdentLoc[index], + Ident[index], LBrace, attrs.getList()); + + ParseInnerNamespace(IdentLoc, Ident, NamespaceLoc, ++index, InlineLoc, + LBrace, attrs, RBraceLoc); + + NamespaceScope.Exit(); + + Actions.ActOnFinishNamespaceDef(NamespcDecl, RBraceLoc); +} + /// ParseNamespaceAlias - Parse the part after the '=' in a namespace /// alias definition. /// @@ -387,13 +466,35 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context, bool IsAliasDecl = Tok.is(tok::equal); TypeResult TypeAlias; if (IsAliasDecl) { - // TODO: Do we want to support attributes somewhere in an alias declaration? - // Can't follow GCC since it doesn't support them yet! + // TODO: Attribute support. C++0x attributes may appear before the equals. + // Where can GNU attributes appear? ConsumeToken(); if (!getLang().CPlusPlus0x) Diag(Tok.getLocation(), diag::ext_alias_declaration); + // Type alias templates cannot be specialized. + int SpecKind = -1; + if (TemplateInfo.Kind == ParsedTemplateInfo::Template && + Name.getKind() == UnqualifiedId::IK_TemplateId) + SpecKind = 0; + if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitSpecialization) + SpecKind = 1; + if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation) + SpecKind = 2; + if (SpecKind != -1) { + SourceRange Range; + if (SpecKind == 0) + Range = SourceRange(Name.TemplateId->LAngleLoc, + Name.TemplateId->RAngleLoc); + else + Range = TemplateInfo.getSourceRange(); + Diag(Range.getBegin(), diag::err_alias_declaration_specialization) + << SpecKind << Range; + SkipUntil(tok::semi); + return 0; + } + // Name must be an identifier. if (Name.getKind() != UnqualifiedId::IK_Identifier) { Diag(Name.StartLocation, diag::err_alias_declaration_not_identifier); @@ -408,7 +509,9 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context, Diag(SS.getBeginLoc(), diag::err_alias_declaration_not_identifier) << FixItHint::CreateRemoval(SS.getRange()); - TypeAlias = ParseTypeName(0, Declarator::AliasDeclContext); + TypeAlias = ParseTypeName(0, TemplateInfo.Kind ? + Declarator::AliasTemplateContext : + Declarator::AliasDeclContext); } else // Parse (optional) attributes (most likely GNU strong-using extension). MaybeParseGNUAttributes(attrs); @@ -421,9 +524,9 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context, tok::semi); // Diagnose an attempt to declare a templated using-declaration. - // TODO: in C++0x, alias-declarations can be templates: + // In C++0x, alias-declarations can be templates: // template <...> using id = type; - if (TemplateInfo.Kind) { + if (TemplateInfo.Kind && !IsAliasDecl) { SourceRange R = TemplateInfo.getSourceRange(); Diag(UsingLoc, diag::err_templated_using_declaration) << R << FixItHint::CreateRemoval(R); @@ -434,9 +537,14 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context, return 0; } - if (IsAliasDecl) - return Actions.ActOnAliasDeclaration(getCurScope(), AS, UsingLoc, Name, - TypeAlias); + if (IsAliasDecl) { + TemplateParameterLists *TemplateParams = TemplateInfo.TemplateParams; + MultiTemplateParamsArg TemplateParamsArg(Actions, + TemplateParams ? TemplateParams->data() : 0, + TemplateParams ? TemplateParams->size() : 0); + return Actions.ActOnAliasDeclaration(getCurScope(), AS, TemplateParamsArg, + UsingLoc, Name, TypeAlias); + } return Actions.ActOnUsingDeclaration(getCurScope(), AS, true, UsingLoc, SS, Name, attrs.getList(), @@ -543,6 +651,42 @@ void Parser::ParseDecltypeSpecifier(DeclSpec &DS) { Diag(StartLoc, DiagID) << PrevSpec; } +void Parser::ParseUnderlyingTypeSpecifier(DeclSpec &DS) { + assert(Tok.is(tok::kw___underlying_type) && + "Not an underlying type specifier"); + + SourceLocation StartLoc = ConsumeToken(); + SourceLocation LParenLoc = Tok.getLocation(); + + if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after, + "__underlying_type")) { + SkipUntil(tok::r_paren); + return; + } + + TypeResult Result = ParseTypeName(); + if (Result.isInvalid()) { + SkipUntil(tok::r_paren); + return; + } + + // Match the ')' + SourceLocation RParenLoc; + if (Tok.is(tok::r_paren)) + RParenLoc = ConsumeParen(); + else + MatchRHSPunctuation(tok::r_paren, LParenLoc); + + if (RParenLoc.isInvalid()) + return; + + const char *PrevSpec = 0; + unsigned DiagID; + if (DS.SetTypeSpecType(DeclSpec::TST_underlyingType, StartLoc, PrevSpec, + DiagID, Result.release())) + Diag(StartLoc, DiagID) << PrevSpec; +} + /// ParseClassName - Parse a C++ class-name, which names a class. Note /// that we only check that the result names a type; semantic analysis /// will need to verify that the type names a class. The result is @@ -1409,6 +1553,7 @@ bool Parser::isCXX0XFinalKeyword() const { /// member-declarator: /// declarator virt-specifier-seq[opt] pure-specifier[opt] /// declarator constant-initializer[opt] +/// [C++11] declarator brace-or-equal-initializer[opt] /// identifier[opt] ':' constant-expression /// /// virt-specifier-seq: @@ -1515,8 +1660,6 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, MaybeParseMicrosoftAttributes(attrs); if (Tok.is(tok::kw_using)) { - // FIXME: Check for template aliases - ProhibitAttributes(attrs); // Eat 'using'. @@ -1527,7 +1670,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, SkipUntil(tok::semi, true, true); } else { SourceLocation DeclEnd; - // Otherwise, it must be using-declaration. + // Otherwise, it must be a using-declaration or an alias-declaration. ParseUsingDeclaration(Declarator::MemberContext, TemplateInfo, UsingLoc, DeclEnd, AS); } @@ -1547,13 +1690,14 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, if (Tok.is(tok::semi)) { ConsumeToken(); Decl *TheDecl = - Actions.ParsedFreeStandingDeclSpec(getCurScope(), AS, DS); + Actions.ParsedFreeStandingDeclSpec(getCurScope(), AS, DS, TemplateParams); DS.complete(TheDecl); return; } ParsingDeclarator DeclaratorInfo(*this, DS, Declarator::MemberContext); VirtSpecifiers VS; + ExprResult Init; if (Tok.isNot(tok::colon)) { // Don't parse FOO:BAR as if it were a typo for FOO::BAR. @@ -1575,10 +1719,36 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, // If attributes exist after the declarator, but before an '{', parse them. MaybeParseGNUAttributes(DeclaratorInfo); + // MSVC permits pure specifier on inline functions declared at class scope. + // Hence check for =0 before checking for function definition. + if (getLang().Microsoft && Tok.is(tok::equal) && + DeclaratorInfo.isFunctionDeclarator() && + NextToken().is(tok::numeric_constant)) { + ConsumeToken(); + Init = ParseInitializer(); + if (Init.isInvalid()) + SkipUntil(tok::comma, true, true); + } + + bool IsDefinition = false; // function-definition: - if (Tok.is(tok::l_brace) - || (DeclaratorInfo.isFunctionDeclarator() && - (Tok.is(tok::colon) || Tok.is(tok::kw_try)))) { + // + // In C++11, a non-function declarator followed by an open brace is a + // braced-init-list for an in-class member initialization, not an + // erroneous function definition. + if (Tok.is(tok::l_brace) && !getLang().CPlusPlus0x) { + IsDefinition = true; + } else if (DeclaratorInfo.isFunctionDeclarator()) { + if (Tok.is(tok::l_brace) || Tok.is(tok::colon) || Tok.is(tok::kw_try)) { + IsDefinition = true; + } else if (Tok.is(tok::equal)) { + const Token &KW = NextToken(); + if (KW.is(tok::kw_default) || KW.is(tok::kw_delete)) + IsDefinition = true; + } + } + + if (IsDefinition) { if (!DeclaratorInfo.isFunctionDeclarator()) { Diag(Tok, diag::err_func_def_no_params); ConsumeBrace(); @@ -1604,10 +1774,12 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, return; } - ParseCXXInlineMethodDef(AS, DeclaratorInfo, TemplateInfo, VS); - // Consume the optional ';' - if (Tok.is(tok::semi)) + ParseCXXInlineMethodDef(AS, DeclaratorInfo, TemplateInfo, VS, Init); + + // Consume the ';' - it's optional unless we have a delete or default + if (Tok.is(tok::semi)) { ConsumeToken(); + } return; } @@ -1619,13 +1791,11 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, llvm::SmallVector<Decl *, 8> DeclsInGroup; ExprResult BitfieldSize; - ExprResult Init; - bool Deleted = false; while (1) { // member-declarator: // declarator pure-specifier[opt] - // declarator constant-initializer[opt] + // declarator brace-or-equal-initializer[opt] // identifier[opt] ':' constant-expression if (Tok.is(tok::colon)) { ConsumeToken(); @@ -1634,31 +1804,6 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, SkipUntil(tok::comma, true, true); } - ParseOptionalCXX0XVirtSpecifierSeq(VS); - - // pure-specifier: - // '= 0' - // - // constant-initializer: - // '=' constant-expression - // - // defaulted/deleted function-definition: - // '=' 'default' [TODO] - // '=' 'delete' - if (Tok.is(tok::equal)) { - ConsumeToken(); - if (Tok.is(tok::kw_delete)) { - if (!getLang().CPlusPlus0x) - Diag(Tok, diag::warn_deleted_function_accepted_as_extension); - ConsumeToken(); - Deleted = true; - } else { - Init = ParseInitializer(); - if (Init.isInvalid()) - SkipUntil(tok::comma, true, true); - } - } - // If a simple-asm-expr is present, parse it. if (Tok.is(tok::kw_asm)) { SourceLocation Loc; @@ -1673,6 +1818,30 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, // If attributes exist after the declarator, parse them. MaybeParseGNUAttributes(DeclaratorInfo); + // FIXME: When g++ adds support for this, we'll need to check whether it + // goes before or after the GNU attributes and __asm__. + ParseOptionalCXX0XVirtSpecifierSeq(VS); + + bool HasDeferredInitializer = false; + if (Tok.is(tok::equal) || Tok.is(tok::l_brace)) { + if (BitfieldSize.get()) { + Diag(Tok, diag::err_bitfield_member_init); + SkipUntil(tok::comma, true, true); + } else { + HasDeferredInitializer = !DeclaratorInfo.isFunctionDeclarator() && + DeclaratorInfo.getDeclSpec().getStorageClassSpec() + != DeclSpec::SCS_static; + + if (!HasDeferredInitializer) { + SourceLocation EqualLoc; + Init = ParseCXXMemberInitializer( + DeclaratorInfo.isFunctionDeclarator(), EqualLoc); + if (Init.isInvalid()) + SkipUntil(tok::comma, true, true); + } + } + } + // NOTE: If Sema is the Action module and declarator is an instance field, // this call will *not* return the created decl; It will return null. // See Sema::ActOnCXXMemberDeclarator for details. @@ -1689,8 +1858,8 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, move(TemplateParams), BitfieldSize.release(), VS, Init.release(), - /*IsDefinition*/Deleted, - Deleted); + HasDeferredInitializer, + /*IsDefinition*/ false); } if (ThisDecl) DeclsInGroup.push_back(ThisDecl); @@ -1703,6 +1872,24 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, DeclaratorInfo.complete(ThisDecl); + if (HasDeferredInitializer) { + if (!getLang().CPlusPlus0x) + Diag(Tok, diag::warn_nonstatic_member_init_accepted_as_extension); + + if (DeclaratorInfo.isArrayOfUnknownBound()) { + // C++0x [dcl.array]p3: An array bound may also be omitted when the + // declarator is followed by an initializer. + // + // A brace-or-equal-initializer for a member-declarator is not an + // initializer in the gramamr, so this is ill-formed. + Diag(Tok, diag::err_incomplete_array_member_init); + SkipUntil(tok::comma, true, true); + // Avoid later warnings about a class member of incomplete type. + ThisDecl->setInvalidDecl(); + } else + ParseCXXNonStaticMemberInitializer(ThisDecl); + } + // If we don't have a comma, it is either the end of the list (a ';') // or an error, bail out. if (Tok.isNot(tok::comma)) @@ -1716,7 +1903,6 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, VS.clear(); BitfieldSize = 0; Init = 0; - Deleted = false; // Attributes are only allowed on the second declarator. MaybeParseGNUAttributes(DeclaratorInfo); @@ -1737,6 +1923,66 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, DeclsInGroup.size()); } +/// ParseCXXMemberInitializer - Parse the brace-or-equal-initializer or +/// pure-specifier. Also detect and reject any attempted defaulted/deleted +/// function definition. The location of the '=', if any, will be placed in +/// EqualLoc. +/// +/// pure-specifier: +/// '= 0' +/// +/// brace-or-equal-initializer: +/// '=' initializer-expression +/// braced-init-list [TODO] +/// +/// initializer-clause: +/// assignment-expression +/// braced-init-list [TODO] +/// +/// defaulted/deleted function-definition: +/// '=' 'default' +/// '=' 'delete' +/// +/// Prior to C++0x, the assignment-expression in an initializer-clause must +/// be a constant-expression. +ExprResult Parser::ParseCXXMemberInitializer(bool IsFunction, + SourceLocation &EqualLoc) { + assert((Tok.is(tok::equal) || Tok.is(tok::l_brace)) + && "Data member initializer not starting with '=' or '{'"); + + if (Tok.is(tok::equal)) { + EqualLoc = ConsumeToken(); + if (Tok.is(tok::kw_delete)) { + // In principle, an initializer of '= delete p;' is legal, but it will + // never type-check. It's better to diagnose it as an ill-formed expression + // than as an ill-formed deleted non-function member. + // An initializer of '= delete p, foo' will never be parsed, because + // a top-level comma always ends the initializer expression. + const Token &Next = NextToken(); + if (IsFunction || Next.is(tok::semi) || Next.is(tok::comma) || + Next.is(tok::eof)) { + if (IsFunction) + Diag(ConsumeToken(), diag::err_default_delete_in_multiple_declaration) + << 1 /* delete */; + else + Diag(ConsumeToken(), diag::err_deleted_non_function); + return ExprResult(); + } + } else if (Tok.is(tok::kw_default)) { + Diag(ConsumeToken(), diag::err_default_special_members); + if (IsFunction) + Diag(Tok, diag::err_default_delete_in_multiple_declaration) + << 0 /* default */; + else + Diag(ConsumeToken(), diag::err_default_special_members); + return ExprResult(); + } + + return ParseInitializer(); + } else + return ExprError(Diag(Tok, diag::err_generalized_initializer_lists)); +} + /// ParseCXXMemberSpecification - Parse the class definition. /// /// member-specification: @@ -1839,6 +2085,12 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { // Each iteration of this loop reads one member-declaration. + if (getLang().Microsoft && (Tok.is(tok::kw___if_exists) || + Tok.is(tok::kw___if_not_exists))) { + ParseMicrosoftIfExistsClassDeclaration((DeclSpec::TST)TagType, CurAS); + continue; + } + // Check for extraneous top-level semicolon. if (Tok.is(tok::semi)) { Diag(Tok, diag::ext_extra_struct_semi) @@ -1882,19 +2134,20 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, LBraceLoc, RBraceLoc, attrs.getList()); - // C++ 9.2p2: Within the class member-specification, the class is regarded as - // complete within function bodies, default arguments, - // exception-specifications, and constructor ctor-initializers (including - // such things in nested classes). + // C++0x [class.mem]p2: Within the class member-specification, the class is + // regarded as complete within function bodies, default arguments, exception- + // specifications, and brace-or-equal-initializers for non-static data + // members (including such things in nested classes). // - // FIXME: Only function bodies and constructor ctor-initializers are - // parsed correctly, fix the rest. + // FIXME: Only function bodies and brace-or-equal-initializers are currently + // handled. Fix the others! if (TagDecl && NonNestedClass) { // We are not inside a nested class. This class and its nested classes // are complete and we can parse the delayed portions of method // declarations and the lexed inline method definitions. SourceLocation SavedPrevTokLocation = PrevTokLocation; ParseLexedMethodDeclarations(getCurrentClass()); + ParseLexedMemberInitializers(getCurrentClass()); ParseLexedMethodDefs(getCurrentClass()); PrevTokLocation = SavedPrevTokLocation; } @@ -1982,6 +2235,7 @@ void Parser::ParseConstructorInitializer(Decl *ConstructorDecl) { /// /// [C++] mem-initializer: /// mem-initializer-id '(' expression-list[opt] ')' +/// [C++0x] mem-initializer-id braced-init-list /// /// [C++] mem-initializer-id: /// '::'[opt] nested-name-specifier[opt] class-name @@ -2012,31 +2266,37 @@ Parser::MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) { SourceLocation IdLoc = ConsumeToken(); // Parse the '('. - if (Tok.isNot(tok::l_paren)) { - Diag(Tok, diag::err_expected_lparen); + if (getLang().CPlusPlus0x && Tok.is(tok::l_brace)) { + // FIXME: Do something with the braced-init-list. + ParseBraceInitializer(); return true; - } - SourceLocation LParenLoc = ConsumeParen(); + } else if(Tok.is(tok::l_paren)) { + SourceLocation LParenLoc = ConsumeParen(); - // Parse the optional expression-list. - ExprVector ArgExprs(Actions); - CommaLocsTy CommaLocs; - if (Tok.isNot(tok::r_paren) && ParseExpressionList(ArgExprs, CommaLocs)) { - SkipUntil(tok::r_paren); - return true; - } + // Parse the optional expression-list. + ExprVector ArgExprs(Actions); + CommaLocsTy CommaLocs; + if (Tok.isNot(tok::r_paren) && ParseExpressionList(ArgExprs, CommaLocs)) { + SkipUntil(tok::r_paren); + return true; + } - SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc); + SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc); - SourceLocation EllipsisLoc; - if (Tok.is(tok::ellipsis)) - EllipsisLoc = ConsumeToken(); - - return Actions.ActOnMemInitializer(ConstructorDecl, getCurScope(), SS, II, - TemplateTypeTy, IdLoc, - LParenLoc, ArgExprs.take(), - ArgExprs.size(), RParenLoc, - EllipsisLoc); + SourceLocation EllipsisLoc; + if (Tok.is(tok::ellipsis)) + EllipsisLoc = ConsumeToken(); + + return Actions.ActOnMemInitializer(ConstructorDecl, getCurScope(), SS, II, + TemplateTypeTy, IdLoc, + LParenLoc, ArgExprs.take(), + ArgExprs.size(), RParenLoc, + EllipsisLoc); + } + + Diag(Tok, getLang().CPlusPlus0x ? diag::err_expected_lparen_or_lbrace + : diag::err_expected_lparen); + return true; } /// \brief Parse a C++ exception-specification if present (C++0x [except.spec]). @@ -2438,3 +2698,64 @@ void Parser::ParseMicrosoftAttributes(ParsedAttributes &attrs, ExpectAndConsume(tok::r_square, diag::err_expected_rsquare); } } + +void Parser::ParseMicrosoftIfExistsClassDeclaration(DeclSpec::TST TagType, + AccessSpecifier& CurAS) { + bool Result; + if (ParseMicrosoftIfExistsCondition(Result)) + return; + + if (Tok.isNot(tok::l_brace)) { + Diag(Tok, diag::err_expected_lbrace); + return; + } + ConsumeBrace(); + + // Condition is false skip all inside the {}. + if (!Result) { + SkipUntil(tok::r_brace, false); + return; + } + + // Condition is true, parse the declaration. + while (Tok.isNot(tok::r_brace)) { + + // __if_exists, __if_not_exists can nest. + if ((Tok.is(tok::kw___if_exists) || Tok.is(tok::kw___if_not_exists))) { + ParseMicrosoftIfExistsClassDeclaration((DeclSpec::TST)TagType, CurAS); + continue; + } + + // Check for extraneous top-level semicolon. + if (Tok.is(tok::semi)) { + Diag(Tok, diag::ext_extra_struct_semi) + << DeclSpec::getSpecifierName((DeclSpec::TST)TagType) + << FixItHint::CreateRemoval(Tok.getLocation()); + ConsumeToken(); + continue; + } + + AccessSpecifier AS = getAccessSpecifierIfPresent(); + if (AS != AS_none) { + // Current token is a C++ access specifier. + CurAS = AS; + SourceLocation ASLoc = Tok.getLocation(); + ConsumeToken(); + if (Tok.is(tok::colon)) + Actions.ActOnAccessSpecifier(AS, ASLoc, Tok.getLocation()); + else + Diag(Tok, diag::err_expected_colon); + ConsumeToken(); + continue; + } + + // Parse all the comma separated declarators. + ParseCXXClassMemberDeclaration(CurAS); + } + + if (Tok.isNot(tok::r_brace)) { + Diag(Tok, diag::err_expected_rbrace); + return; + } + ConsumeBrace(); +} diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseExpr.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseExpr.cpp index 91fe1e1..4e94ed9 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParseExpr.cpp +++ b/contrib/llvm/tools/clang/lib/Parse/ParseExpr.cpp @@ -480,7 +480,9 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, /// [OBJC] '@encode' '(' type-name ')' /// [OBJC] objc-string-literal /// [C++] simple-type-specifier '(' expression-list[opt] ')' [C++ 5.2.3] +/// [C++0x] simple-type-specifier braced-init-list [C++ 5.2.3] /// [C++] typename-specifier '(' expression-list[opt] ')' [C++ 5.2.3] +/// [C++0x] typename-specifier braced-init-list [C++ 5.2.3] /// [C++] 'const_cast' '<' type-name '>' '(' expression ')' [C++ 5.2p1] /// [C++] 'dynamic_cast' '<' type-name '>' '(' expression ')' [C++ 5.2p1] /// [C++] 'reinterpret_cast' '<' type-name '>' '(' expression ')' [C++ 5.2p1] @@ -566,6 +568,9 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, /// '__is_trivial' /// '__is_union' /// +/// [Clang] unary-type-trait: +/// '__trivially_copyable' +/// /// binary-type-trait: /// [GNU] '__is_base_of' /// [MS] '__is_convertible_to' @@ -782,6 +787,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, case tok::kw___builtin_va_arg: case tok::kw___builtin_offsetof: case tok::kw___builtin_choose_expr: + case tok::kw___builtin_astype: // primary-expression: [OCL] as_type() return ParseBuiltinPrimaryExpression(); case tok::kw___null: return Actions.ActOnGNUNullExpr(ConsumeToken()); @@ -919,15 +925,18 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, if (SavedKind == tok::kw_typename) { // postfix-expression: typename-specifier '(' expression-list[opt] ')' + // typename-specifier braced-init-list if (TryAnnotateTypeOrScopeToken()) return ExprError(); } // postfix-expression: simple-type-specifier '(' expression-list[opt] ')' + // simple-type-specifier braced-init-list // DeclSpec DS(AttrFactory); ParseCXXSimpleTypeSpecifier(DS); - if (Tok.isNot(tok::l_paren)) + if (Tok.isNot(tok::l_paren) && + (!getLang().CPlusPlus0x || Tok.isNot(tok::l_brace))) return ExprError(Diag(Tok, diag::err_expected_lparen_after_type) << DS.getSourceRange()); @@ -1060,6 +1069,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, case tok::kw___is_pod: case tok::kw___is_polymorphic: case tok::kw___is_trivial: + case tok::kw___is_trivially_copyable: case tok::kw___is_union: case tok::kw___has_trivial_constructor: case tok::kw___has_trivial_copy: @@ -1117,6 +1127,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, /// postfix-expression: [C99 6.5.2] /// primary-expression /// postfix-expression '[' expression ']' +/// postfix-expression '[' braced-init-list ']' /// postfix-expression '(' argument-expression-list[opt] ')' /// postfix-expression '.' identifier /// postfix-expression '->' identifier @@ -1172,7 +1183,11 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { return move(LHS); Loc = ConsumeBracket(); - ExprResult Idx(ParseExpression()); + ExprResult Idx; + if (getLang().CPlusPlus0x && Tok.is(tok::l_brace)) + Idx = ParseBraceInitializer(); + else + Idx = ParseExpression(); SourceLocation RLoc = Tok.getLocation(); @@ -1529,6 +1544,7 @@ ExprResult Parser::ParseUnaryExprOrTypeTraitExpression() { /// [GNU] '__builtin_choose_expr' '(' assign-expr ',' assign-expr ',' /// assign-expr ')' /// [GNU] '__builtin_types_compatible_p' '(' type-name ',' type-name ')' +/// [OCL] '__builtin_astype' '(' type-name expr ')' /// /// [GNU] offsetof-member-designator: /// [GNU] identifier @@ -1673,7 +1689,35 @@ ExprResult Parser::ParseBuiltinPrimaryExpression() { Expr2.take(), ConsumeParen()); break; } + case tok::kw___builtin_astype: { + // The first argument is an expression to be converted, followed by a comma. + ExprResult Expr(ParseAssignmentExpression()); + if (Expr.isInvalid()) { + SkipUntil(tok::r_paren); + return ExprError(); + } + + if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "", + tok::r_paren)) + return ExprError(); + + // Second argument is the type to bitcast to. + TypeResult DestTy = ParseTypeName(); + if (DestTy.isInvalid()) + return ExprError(); + + // Attempt to consume the r-paren. + if (Tok.isNot(tok::r_paren)) { + Diag(Tok, diag::err_expected_rparen); + SkipUntil(tok::r_paren); + return ExprError(); + } + + Res = Actions.ActOnAsTypeExpr(Expr.take(), DestTy.get(), StartLoc, + ConsumeParen()); + break; } +} if (Res.isInvalid()) return ExprError(); @@ -1987,8 +2031,19 @@ ExprResult Parser::ParseGenericSelectionExpression() { /// argument-expression-list , assignment-expression /// /// [C++] expression-list: -/// [C++] assignment-expression ...[opt] -/// [C++] expression-list , assignment-expression ...[opt] +/// [C++] assignment-expression +/// [C++] expression-list , assignment-expression +/// +/// [C++0x] expression-list: +/// [C++0x] initializer-list +/// +/// [C++0x] initializer-list +/// [C++0x] initializer-clause ...[opt] +/// [C++0x] initializer-list , initializer-clause ...[opt] +/// +/// [C++0x] initializer-clause: +/// [C++0x] assignment-expression +/// [C++0x] braced-init-list /// bool Parser::ParseExpressionList(llvm::SmallVectorImpl<Expr*> &Exprs, llvm::SmallVectorImpl<SourceLocation> &CommaLocs, @@ -2005,8 +2060,13 @@ bool Parser::ParseExpressionList(llvm::SmallVectorImpl<Expr*> &Exprs, Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Expression); ConsumeCodeCompletionToken(); } - - ExprResult Expr(ParseAssignmentExpression()); + + ExprResult Expr; + if (getLang().CPlusPlus0x && Tok.is(tok::l_brace)) + Expr = ParseBraceInitializer(); + else + Expr = ParseAssignmentExpression(); + if (Tok.is(tok::ellipsis)) Expr = Actions.ActOnPackExpansion(Expr.get(), ConsumeToken()); if (Expr.isInvalid()) diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseExprCXX.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseExprCXX.cpp index 8bf6f63..eab7114 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParseExprCXX.cpp +++ b/contrib/llvm/tools/clang/lib/Parse/ParseExprCXX.cpp @@ -280,8 +280,11 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, : TemplateId->TemplateNameLoc; SS.SetInvalid(SourceRange(StartLoc, CCLoc)); } - - TemplateId->Destroy(); + + // If we are caching tokens we will process the TemplateId again, + // otherwise destroy it. + if (!PP.isBacktrackEnabled()) + TemplateId->Destroy(); continue; } @@ -806,42 +809,55 @@ ExprResult Parser::ParseCXXThis() { /// Can be interpreted either as function-style casting ("int(x)") /// or class type construction ("ClassType(x,y,z)") /// or creation of a value-initialized type ("int()"). +/// See [C++ 5.2.3]. /// /// postfix-expression: [C++ 5.2p1] -/// simple-type-specifier '(' expression-list[opt] ')' [C++ 5.2.3] -/// typename-specifier '(' expression-list[opt] ')' [TODO] +/// simple-type-specifier '(' expression-list[opt] ')' +/// [C++0x] simple-type-specifier braced-init-list +/// typename-specifier '(' expression-list[opt] ')' +/// [C++0x] typename-specifier braced-init-list /// ExprResult Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) { Declarator DeclaratorInfo(DS, Declarator::TypeNameContext); ParsedType TypeRep = Actions.ActOnTypeName(getCurScope(), DeclaratorInfo).get(); - assert(Tok.is(tok::l_paren) && "Expected '('!"); - GreaterThanIsOperatorScope G(GreaterThanIsOperator, true); + assert((Tok.is(tok::l_paren) || + (getLang().CPlusPlus0x && Tok.is(tok::l_brace))) + && "Expected '(' or '{'!"); - SourceLocation LParenLoc = ConsumeParen(); + if (Tok.is(tok::l_brace)) { - ExprVector Exprs(Actions); - CommaLocsTy CommaLocs; + // FIXME: Convert to a proper type construct expression. + return ParseBraceInitializer(); - if (Tok.isNot(tok::r_paren)) { - if (ParseExpressionList(Exprs, CommaLocs)) { - SkipUntil(tok::r_paren); - return ExprError(); + } else { + GreaterThanIsOperatorScope G(GreaterThanIsOperator, true); + + SourceLocation LParenLoc = ConsumeParen(); + + ExprVector Exprs(Actions); + CommaLocsTy CommaLocs; + + if (Tok.isNot(tok::r_paren)) { + if (ParseExpressionList(Exprs, CommaLocs)) { + SkipUntil(tok::r_paren); + return ExprError(); + } } - } - // Match the ')'. - SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc); + // Match the ')'. + SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc); - // TypeRep could be null, if it references an invalid typedef. - if (!TypeRep) - return ExprError(); + // TypeRep could be null, if it references an invalid typedef. + if (!TypeRep) + return ExprError(); - assert((Exprs.size() == 0 || Exprs.size()-1 == CommaLocs.size())&& - "Unexpected number of commas!"); - return Actions.ActOnCXXTypeConstructExpr(TypeRep, LParenLoc, move_arg(Exprs), - RParenLoc); + assert((Exprs.size() == 0 || Exprs.size()-1 == CommaLocs.size())&& + "Unexpected number of commas!"); + return Actions.ActOnCXXTypeConstructExpr(TypeRep, LParenLoc, move_arg(Exprs), + RParenLoc); + } } /// ParseCXXCondition - if/switch/while condition expression. @@ -959,6 +975,7 @@ bool Parser::isCXXSimpleTypeSpecifier() const { case tok::kw_bool: case tok::kw_decltype: case tok::kw_typeof: + case tok::kw___underlying_type: return true; default: @@ -1723,7 +1740,7 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext, /// /// new-initializer: /// '(' expression-list[opt] ')' -/// [C++0x] braced-init-list [TODO] +/// [C++0x] braced-init-list /// ExprResult Parser::ParseCXXNewExpression(bool UseGlobal, SourceLocation Start) { @@ -1812,6 +1829,9 @@ Parser::ParseCXXNewExpression(bool UseGlobal, SourceLocation Start) { SkipUntil(tok::semi, /*StopAtSemi=*/true, /*DontConsume=*/true); return ExprError(); } + } else if (Tok.is(tok::l_brace)) { + // FIXME: Have to communicate the init-list to ActOnCXXNew. + ParseBraceInitializer(); } return Actions.ActOnCXXNew(Start, UseGlobal, PlacementLParen, @@ -1921,7 +1941,8 @@ static UnaryTypeTrait UnaryTypeTraitFromTokKind(tok::TokenKind kind) { case tok::kw___has_nothrow_constructor: return UTT_HasNothrowConstructor; case tok::kw___has_nothrow_copy: return UTT_HasNothrowCopy; case tok::kw___has_trivial_assign: return UTT_HasTrivialAssign; - case tok::kw___has_trivial_constructor: return UTT_HasTrivialConstructor; + case tok::kw___has_trivial_constructor: + return UTT_HasTrivialDefaultConstructor; case tok::kw___has_trivial_copy: return UTT_HasTrivialCopy; case tok::kw___has_trivial_destructor: return UTT_HasTrivialDestructor; case tok::kw___has_virtual_destructor: return UTT_HasVirtualDestructor; @@ -1954,6 +1975,7 @@ static UnaryTypeTrait UnaryTypeTraitFromTokKind(tok::TokenKind kind) { case tok::kw___is_signed: return UTT_IsSigned; case tok::kw___is_standard_layout: return UTT_IsStandardLayout; case tok::kw___is_trivial: return UTT_IsTrivial; + case tok::kw___is_trivially_copyable: return UTT_IsTriviallyCopyable; case tok::kw___is_union: return UTT_IsUnion; case tok::kw___is_unsigned: return UTT_IsUnsigned; case tok::kw___is_void: return UTT_IsVoid; diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseObjc.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseObjc.cpp index fdbedc5..a8c18c0 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParseObjc.cpp +++ b/contrib/llvm/tools/clang/lib/Parse/ParseObjc.cpp @@ -874,8 +874,8 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc, Selector Sel = PP.getSelectorTable().getNullarySelector(SelIdent); Decl *Result = Actions.ActOnMethodDeclaration(getCurScope(), mLoc, Tok.getLocation(), - mType, IDecl, DSRet, ReturnType, Sel, - 0, + mType, IDecl, DSRet, ReturnType, + selLoc, Sel, 0, CParamInfo.data(), CParamInfo.size(), methodAttrs.getList(), MethodImplKind, false, MethodDefinition); @@ -1000,8 +1000,8 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc, &KeyIdents[0]); Decl *Result = Actions.ActOnMethodDeclaration(getCurScope(), mLoc, Tok.getLocation(), - mType, IDecl, DSRet, ReturnType, Sel, - &ArgInfos[0], + mType, IDecl, DSRet, ReturnType, + selLoc, Sel, &ArgInfos[0], CParamInfo.data(), CParamInfo.size(), methodAttrs.getList(), MethodImplKind, isVariadic, MethodDefinition); diff --git a/contrib/llvm/tools/clang/lib/Parse/ParsePragma.cpp b/contrib/llvm/tools/clang/lib/Parse/ParsePragma.cpp index 46225c8..c30ab75 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParsePragma.cpp +++ b/contrib/llvm/tools/clang/lib/Parse/ParsePragma.cpp @@ -295,7 +295,6 @@ void PragmaUnusedHandler::HandlePragma(Preprocessor &PP, PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_lparen) << "unused"; return; } - SourceLocation LParenLoc = Tok.getLocation(); // Lex the declaration reference(s). llvm::SmallVector<Token, 5> Identifiers; diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseStmt.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseStmt.cpp index f0ab531..6cc8b57 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParseStmt.cpp +++ b/contrib/llvm/tools/clang/lib/Parse/ParseStmt.cpp @@ -741,6 +741,12 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) { continue; } + if (getLang().Microsoft && (Tok.is(tok::kw___if_exists) || + Tok.is(tok::kw___if_not_exists))) { + ParseMicrosoftIfExistsStatement(Stmts); + continue; + } + StmtResult R; if (Tok.isNot(tok::kw___extension__)) { R = ParseStatementOrDeclaration(Stmts, false); @@ -2000,3 +2006,34 @@ StmtResult Parser::ParseCXXCatchBlock() { return Actions.ActOnCXXCatchBlock(CatchLoc, ExceptionDecl, Block.take()); } + +void Parser::ParseMicrosoftIfExistsStatement(StmtVector &Stmts) { + bool Result; + if (ParseMicrosoftIfExistsCondition(Result)) + return; + + if (Tok.isNot(tok::l_brace)) { + Diag(Tok, diag::err_expected_lbrace); + return; + } + ConsumeBrace(); + + // Condition is false skip all inside the {}. + if (!Result) { + SkipUntil(tok::r_brace, false); + return; + } + + // Condition is true, parse the statements. + while (Tok.isNot(tok::r_brace)) { + StmtResult R = ParseStatementOrDeclaration(Stmts, false); + if (R.isUsable()) + Stmts.push_back(R.release()); + } + + if (Tok.isNot(tok::r_brace)) { + Diag(Tok, diag::err_expected_rbrace); + return; + } + ConsumeBrace(); +} diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseTemplate.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseTemplate.cpp index 12e38da..aa89d75 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParseTemplate.cpp +++ b/contrib/llvm/tools/clang/lib/Parse/ParseTemplate.cpp @@ -905,10 +905,10 @@ ParsedTemplateArgument Parser::ParseTemplateTemplateArgument() { // C++0x [temp.arg.template]p1: // A template-argument for a template template-parameter shall be the name - // of a class template or a template alias, expressed as id-expression. + // of a class template or an alias template, expressed as id-expression. // - // We parse an id-expression that refers to a class template or template - // alias. The grammar we parse is: + // We parse an id-expression that refers to a class template or alias + // template. The grammar we parse is: // // nested-name-specifier[opt] template[opt] identifier ...[opt] // @@ -969,7 +969,7 @@ ParsedTemplateArgument Parser::ParseTemplateTemplateArgument() { MemberOfUnknownSpecialization); if (TNK == TNK_Dependent_template_name || TNK == TNK_Type_template) { // We have an id-expression that refers to a class template or - // (C++0x) template alias. + // (C++0x) alias template. Result = ParsedTemplateArgument(SS, Template, Name.StartLocation); } } diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseTentative.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseTentative.cpp index 1c4e2b3..78d2c90 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParseTentative.cpp +++ b/contrib/llvm/tools/clang/lib/Parse/ParseTentative.cpp @@ -664,6 +664,7 @@ Parser::isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind) { case tok::kw___is_pod: case tok::kw___is_polymorphic: case tok::kw___is_trivial: + case tok::kw___is_trivially_copyable: case tok::kw___is_union: case tok::kw___uuidof: return TPResult::True(); @@ -693,6 +694,7 @@ Parser::isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind) { case tok::kw_char16_t: case tok::kw_char32_t: case tok::kw_decltype: + case tok::kw___underlying_type: case tok::kw_thread_local: case tok::kw__Decimal32: case tok::kw__Decimal64: @@ -1011,6 +1013,10 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() { case tok::kw_decltype: return TPResult::True(); + // C++0x type traits support + case tok::kw___underlying_type: + return TPResult::True(); + default: return TPResult::False(); } diff --git a/contrib/llvm/tools/clang/lib/Parse/Parser.cpp b/contrib/llvm/tools/clang/lib/Parse/Parser.cpp index 4d08699..f19472c 100644 --- a/contrib/llvm/tools/clang/lib/Parse/Parser.cpp +++ b/contrib/llvm/tools/clang/lib/Parse/Parser.cpp @@ -20,6 +20,7 @@ #include "RAIIObjectsForParser.h" #include "ParsePragma.h" #include "clang/AST/DeclTemplate.h" +#include "clang/AST/ASTConsumer.h" using namespace clang; Parser::Parser(Preprocessor &pp, Sema &actions) @@ -350,7 +351,23 @@ void Parser::ExitScope() { ScopeCache[NumCachedScopes++] = OldScope; } +/// Set the flags for the current scope to ScopeFlags. If ManageFlags is false, +/// this object does nothing. +Parser::ParseScopeFlags::ParseScopeFlags(Parser *Self, unsigned ScopeFlags, + bool ManageFlags) + : CurScope(ManageFlags ? Self->getCurScope() : 0) { + if (CurScope) { + OldFlags = CurScope->getFlags(); + CurScope->setFlags(ScopeFlags); + } +} +/// Restore the flags for the current scope to what they were before this +/// object overrode them. +Parser::ParseScopeFlags::~ParseScopeFlags() { + if (CurScope) + CurScope->setFlags(OldFlags); +} //===----------------------------------------------------------------------===// @@ -653,6 +670,11 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs, // FIXME: Detect C++ linkage specifications here? goto dont_know; + case tok::kw___if_exists: + case tok::kw___if_not_exists: + ParseMicrosoftIfExistsExternalDeclaration(); + return DeclGroupPtrTy(); + default: dont_know: // We can't tell whether this is a function-definition or declaration yet. @@ -671,7 +693,14 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs, /// \brief Determine whether the current token, if it occurs after a /// declarator, continues a declaration or declaration list. -bool Parser::isDeclarationAfterDeclarator() const { +bool Parser::isDeclarationAfterDeclarator() { + // Check for '= delete' or '= default' + if (getLang().CPlusPlus && Tok.is(tok::equal)) { + const Token &KW = NextToken(); + if (KW.is(tok::kw_default) || KW.is(tok::kw_delete)) + return false; + } + return Tok.is(tok::equal) || // int X()= -> not a function def Tok.is(tok::comma) || // int X(), -> not a function def Tok.is(tok::semi) || // int X(); -> not a function def @@ -692,6 +721,11 @@ bool Parser::isStartOfFunctionDefinition(const ParsingDeclarator &Declarator) { if (!getLang().CPlusPlus && Declarator.getFunctionTypeInfo().isKNRPrototype()) return isDeclarationSpecifier(); + + if (getLang().CPlusPlus && Tok.is(tok::equal)) { + const Token &KW = NextToken(); + return KW.is(tok::kw_default) || KW.is(tok::kw_delete); + } return Tok.is(tok::colon) || // X() : Base() {} (used for ctors) Tok.is(tok::kw_try); // X() try { ... } @@ -814,11 +848,13 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D, if (FTI.isKNRPrototype()) ParseKNRParamDeclarations(D); + // We should have either an opening brace or, in a C++ constructor, // we may have a colon. if (Tok.isNot(tok::l_brace) && (!getLang().CPlusPlus || - (Tok.isNot(tok::colon) && Tok.isNot(tok::kw_try)))) { + (Tok.isNot(tok::colon) && Tok.isNot(tok::kw_try) && + Tok.isNot(tok::equal)))) { Diag(Tok, diag::err_expected_fn_body); // Skip over garbage, until we get to '{'. Don't eat the '{'. @@ -866,7 +902,6 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D, return DP; } - // Enter a scope for the function body. ParseScope BodyScope(this, Scope::FnScope|Scope::DeclScope); @@ -887,6 +922,43 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D, // safe because we're always the sole owner. D.getMutableDeclSpec().abort(); + if (Tok.is(tok::equal)) { + assert(getLang().CPlusPlus && "Only C++ function definitions have '='"); + ConsumeToken(); + + Actions.ActOnFinishFunctionBody(Res, 0, false); + + bool Delete = false; + SourceLocation KWLoc; + if (Tok.is(tok::kw_delete)) { + if (!getLang().CPlusPlus0x) + Diag(Tok, diag::warn_deleted_function_accepted_as_extension); + + KWLoc = ConsumeToken(); + Actions.SetDeclDeleted(Res, KWLoc); + Delete = true; + } else if (Tok.is(tok::kw_default)) { + if (!getLang().CPlusPlus0x) + Diag(Tok, diag::warn_defaulted_function_accepted_as_extension); + + KWLoc = ConsumeToken(); + Actions.SetDeclDefaulted(Res, KWLoc); + } else { + llvm_unreachable("function definition after = not 'delete' or 'default'"); + } + + if (Tok.is(tok::comma)) { + Diag(KWLoc, diag::err_default_delete_in_multiple_declaration) + << Delete; + SkipUntil(tok::semi); + } else { + ExpectAndConsume(tok::semi, diag::err_expected_semi_after, + Delete ? "delete" : "default", tok::semi); + } + + return Res; + } + if (Tok.is(tok::kw_try)) return ParseFunctionTryBlock(Res, BodyScope); @@ -1374,3 +1446,80 @@ void Parser::CodeCompleteMacroArgument(IdentifierInfo *Macro, void Parser::CodeCompleteNaturalLanguage() { Actions.CodeCompleteNaturalLanguage(); } + +bool Parser::ParseMicrosoftIfExistsCondition(bool& Result) { + assert((Tok.is(tok::kw___if_exists) || Tok.is(tok::kw___if_not_exists)) && + "Expected '__if_exists' or '__if_not_exists'"); + Token Condition = Tok; + SourceLocation IfExistsLoc = ConsumeToken(); + + SourceLocation LParenLoc = Tok.getLocation(); + if (Tok.isNot(tok::l_paren)) { + Diag(Tok, diag::err_expected_lparen_after) << IfExistsLoc; + SkipUntil(tok::semi); + return true; + } + ConsumeParen(); // eat the '('. + + // Parse nested-name-specifier. + CXXScopeSpec SS; + ParseOptionalCXXScopeSpecifier(SS, ParsedType(), false); + + // Check nested-name specifier. + if (SS.isInvalid()) { + SkipUntil(tok::semi); + return true; + } + + // Parse the unqualified-id. + UnqualifiedId Name; + if (ParseUnqualifiedId(SS, false, true, true, ParsedType(), Name)) { + SkipUntil(tok::semi); + return true; + } + + if (MatchRHSPunctuation(tok::r_paren, LParenLoc).isInvalid()) + return true; + + // Check if the symbol exists. + bool Exist = Actions.CheckMicrosoftIfExistsSymbol(SS, Name); + + Result = ((Condition.is(tok::kw___if_exists) && Exist) || + (Condition.is(tok::kw___if_not_exists) && !Exist)); + + return false; +} + +void Parser::ParseMicrosoftIfExistsExternalDeclaration() { + bool Result; + if (ParseMicrosoftIfExistsCondition(Result)) + return; + + if (Tok.isNot(tok::l_brace)) { + Diag(Tok, diag::err_expected_lbrace); + return; + } + ConsumeBrace(); + + // Condition is false skip all inside the {}. + if (!Result) { + SkipUntil(tok::r_brace, false); + return; + } + + // Condition is true, parse the declaration. + while (Tok.isNot(tok::r_brace)) { + ParsedAttributesWithRange attrs(AttrFactory); + MaybeParseCXX0XAttributes(attrs); + MaybeParseMicrosoftAttributes(attrs); + DeclGroupPtrTy Result = ParseExternalDeclaration(attrs); + if (Result && !getCurScope()->getParent()) + Actions.getASTConsumer().HandleTopLevelDecl(Result.get()); + } + + if (Tok.isNot(tok::r_brace)) { + Diag(Tok, diag::err_expected_rbrace); + return; + } + ConsumeBrace(); +} diff --git a/contrib/llvm/tools/clang/lib/Rewrite/RewriteObjC.cpp b/contrib/llvm/tools/clang/lib/Rewrite/RewriteObjC.cpp index d6e34ef..8cdb55a 100644 --- a/contrib/llvm/tools/clang/lib/Rewrite/RewriteObjC.cpp +++ b/contrib/llvm/tools/clang/lib/Rewrite/RewriteObjC.cpp @@ -2695,7 +2695,8 @@ QualType RewriteObjC::getSuperStructType() { SourceLocation(), 0, FieldTypes[i], 0, /*BitWidth=*/0, - /*Mutable=*/false)); + /*Mutable=*/false, + /*HasInit=*/false)); } SuperStructDecl->completeDefinition(); @@ -2727,7 +2728,8 @@ QualType RewriteObjC::getConstantStringStructType() { SourceLocation(), 0, FieldTypes[i], 0, /*BitWidth=*/0, - /*Mutable=*/true)); + /*Mutable=*/true, + /*HasInit=*/false)); } ConstantStringDecl->completeDefinition(); @@ -4709,7 +4711,8 @@ Stmt *RewriteObjC::SynthesizeBlockCall(CallExpr *Exp, const Expr *BlockExp) { SourceLocation(), &Context->Idents.get("FuncPtr"), Context->VoidPtrTy, 0, - /*BitWidth=*/0, /*Mutable=*/true); + /*BitWidth=*/0, /*Mutable=*/true, + /*HasInit=*/false); MemberExpr *ME = new (Context) MemberExpr(PE, true, FD, SourceLocation(), FD->getType(), VK_LValue, OK_Ordinary); @@ -4763,7 +4766,8 @@ Stmt *RewriteObjC::RewriteBlockDeclRefExpr(Expr *DeclRefExp) { SourceLocation(), &Context->Idents.get("__forwarding"), Context->VoidPtrTy, 0, - /*BitWidth=*/0, /*Mutable=*/true); + /*BitWidth=*/0, /*Mutable=*/true, + /*HasInit=*/false); MemberExpr *ME = new (Context) MemberExpr(DeclRefExp, isArrow, FD, SourceLocation(), FD->getType(), VK_LValue, @@ -4773,7 +4777,8 @@ Stmt *RewriteObjC::RewriteBlockDeclRefExpr(Expr *DeclRefExp) { FD = FieldDecl::Create(*Context, 0, SourceLocation(), SourceLocation(), &Context->Idents.get(Name), Context->VoidPtrTy, 0, - /*BitWidth=*/0, /*Mutable=*/true); + /*BitWidth=*/0, /*Mutable=*/true, + /*HasInit=*/false); ME = new (Context) MemberExpr(ME, true, FD, SourceLocation(), DeclRefExp->getType(), VK_LValue, OK_Ordinary); diff --git a/contrib/llvm/tools/clang/lib/Sema/AnalysisBasedWarnings.cpp b/contrib/llvm/tools/clang/lib/Sema/AnalysisBasedWarnings.cpp index e482172..9efae61 100644 --- a/contrib/llvm/tools/clang/lib/Sema/AnalysisBasedWarnings.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/AnalysisBasedWarnings.cpp @@ -196,7 +196,12 @@ static ControlFlowKind CheckFallThrough(AnalysisContext &AC) { continue; } Expr *CEE = C->getCallee()->IgnoreParenCasts(); - if (getFunctionExtInfo(CEE->getType()).getNoReturn()) { + QualType calleeType = CEE->getType(); + if (calleeType == AC.getASTContext().BoundMemberTy) { + calleeType = Expr::findBoundMemberType(CEE); + assert(!calleeType.isNull() && "analyzing unresolved call?"); + } + if (getFunctionExtInfo(calleeType).getNoReturn()) { NoReturnEdge = true; HasFakeEdge = true; } else if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(CEE)) { diff --git a/contrib/llvm/tools/clang/lib/Sema/DeclSpec.cpp b/contrib/llvm/tools/clang/lib/Sema/DeclSpec.cpp index 0f20d10..5be16e7 100644 --- a/contrib/llvm/tools/clang/lib/Sema/DeclSpec.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/DeclSpec.cpp @@ -309,6 +309,7 @@ const char *DeclSpec::getSpecifierName(DeclSpec::TST T) { case DeclSpec::TST_typeofExpr: return "typeof"; case DeclSpec::TST_auto: return "auto"; case DeclSpec::TST_decltype: return "(decltype)"; + case DeclSpec::TST_underlyingType: return "__underlying_type"; case DeclSpec::TST_unknown_anytype: return "__unknown_anytype"; case DeclSpec::TST_error: return "(error)"; } diff --git a/contrib/llvm/tools/clang/lib/Sema/JumpDiagnostics.cpp b/contrib/llvm/tools/clang/lib/Sema/JumpDiagnostics.cpp index 867d78f..ae154aa 100644 --- a/contrib/llvm/tools/clang/lib/Sema/JumpDiagnostics.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/JumpDiagnostics.cpp @@ -15,6 +15,7 @@ #include "clang/Sema/SemaInternal.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/Expr.h" +#include "clang/AST/ExprCXX.h" #include "clang/AST/StmtObjC.h" #include "clang/AST/StmtCXX.h" #include "llvm/ADT/BitVector.h" @@ -126,18 +127,45 @@ static std::pair<unsigned,unsigned> InDiag = diag::note_protected_by_cleanup; OutDiag = diag::note_exits_cleanup; } else if (isCPlusPlus) { - // FIXME: In C++0x, we have to check more conditions than "did we - // just give it an initializer?". See 6.7p3. - if (VD->hasLocalStorage() && VD->hasInit()) - InDiag = diag::note_protected_by_variable_init; - - CanQualType T = VD->getType()->getCanonicalTypeUnqualified(); + if (!VD->hasLocalStorage()) + return std::make_pair(InDiag, OutDiag); + + ASTContext &Context = D->getASTContext(); + QualType T = Context.getBaseElementType(VD->getType()); if (!T->isDependentType()) { - while (CanQual<ArrayType> AT = T->getAs<ArrayType>()) - T = AT->getElementType(); - if (CanQual<RecordType> RT = T->getAs<RecordType>()) - if (!cast<CXXRecordDecl>(RT->getDecl())->hasTrivialDestructor()) - OutDiag = diag::note_exits_dtor; + // C++0x [stmt.dcl]p3: + // A program that jumps from a point where a variable with automatic + // storage duration is not in scope to a point where it is in scope + // is ill-formed unless the variable has scalar type, class type with + // a trivial default constructor and a trivial destructor, a + // cv-qualified version of one of these types, or an array of one of + // the preceding types and is declared without an initializer (8.5). + // Check whether this is a C++ class. + CXXRecordDecl *Record = T->getAsCXXRecordDecl(); + + if (const Expr *Init = VD->getInit()) { + bool CallsTrivialConstructor = false; + if (Record) { + // FIXME: With generalized initializer lists, this may + // classify "X x{};" as having no initializer. + if (const CXXConstructExpr *Construct + = dyn_cast<CXXConstructExpr>(Init)) + if (const CXXConstructorDecl *Constructor + = Construct->getConstructor()) + if ((Context.getLangOptions().CPlusPlus0x + ? Record->hasTrivialDefaultConstructor() + : Record->isPOD()) && + Constructor->isDefaultConstructor()) + CallsTrivialConstructor = true; + } + + if (!CallsTrivialConstructor) + InDiag = diag::note_protected_by_variable_init; + } + + // Note whether we have a class with a non-trivial destructor. + if (Record && !Record->hasTrivialDestructor()) + OutDiag = diag::note_exits_dtor; } } diff --git a/contrib/llvm/tools/clang/lib/Sema/Sema.cpp b/contrib/llvm/tools/clang/lib/Sema/Sema.cpp index 7707fb1..8297b31 100644 --- a/contrib/llvm/tools/clang/lib/Sema/Sema.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/Sema.cpp @@ -31,6 +31,7 @@ #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/Expr.h" +#include "clang/AST/ExprCXX.h" #include "clang/AST/StmtCXX.h" #include "clang/Lex/Preprocessor.h" #include "clang/Basic/PartialDiagnostic.h" @@ -377,30 +378,22 @@ void Sema::ActOnEndOfTranslationUnit() { } } - bool SomethingChanged; - do { - SomethingChanged = false; - - // If DefinedUsedVTables ends up marking any virtual member functions it - // might lead to more pending template instantiations, which we then need - // to instantiate. - if (DefineUsedVTables()) - SomethingChanged = true; - - // C++: Perform implicit template instantiations. - // - // FIXME: When we perform these implicit instantiations, we do not - // carefully keep track of the point of instantiation (C++ [temp.point]). - // This means that name lookup that occurs within the template - // instantiation will always happen at the end of the translation unit, - // so it will find some names that should not be found. Although this is - // common behavior for C++ compilers, it is technically wrong. In the - // future, we either need to be able to filter the results of name lookup - // or we need to perform template instantiations earlier. - if (PerformPendingInstantiations()) - SomethingChanged = true; - - } while (SomethingChanged); + // If DefinedUsedVTables ends up marking any virtual member functions it + // might lead to more pending template instantiations, which we then need + // to instantiate. + DefineUsedVTables(); + + // C++: Perform implicit template instantiations. + // + // FIXME: When we perform these implicit instantiations, we do not + // carefully keep track of the point of instantiation (C++ [temp.point]). + // This means that name lookup that occurs within the template + // instantiation will always happen at the end of the translation unit, + // so it will find some names that should not be found. Although this is + // common behavior for C++ compilers, it is technically wrong. In the + // future, we either need to be able to filter the results of name lookup + // or we need to perform template instantiations earlier. + PerformPendingInstantiations(); } // Remove file scoped decls that turned out to be used. @@ -473,6 +466,12 @@ void Sema::ActOnEndOfTranslationUnit() { } + if (LangOpts.CPlusPlus0x && + Diags.getDiagnosticLevel(diag::warn_delegating_ctor_cycle, + SourceLocation()) + != Diagnostic::Ignored) + CheckDelegatingCtorCycles(); + // If there were errors, disable 'unused' warnings since they will mostly be // noise. if (!Diags.hasErrorOccurred()) { @@ -570,9 +569,12 @@ Sema::SemaDiagnosticBuilder::~SemaDiagnosticBuilder() { break; case DiagnosticIDs::SFINAE_AccessControl: - // Unless access checking is specifically called out as a SFINAE - // error, report this diagnostic. - if (!SemaRef.AccessCheckingSFINAE) + // Per C++ Core Issue 1170, access control is part of SFINAE. + // Additionally, the AccessCheckingSFINAE flag can be used to temporary + // make access control a part of SFINAE for the purposes of checking + // type traits. + if (!SemaRef.AccessCheckingSFINAE && + !SemaRef.getLangOptions().CPlusPlus0x) break; case DiagnosticIDs::SFINAE_SubstitutionFailure: @@ -763,3 +765,101 @@ void PrettyDeclStackTraceEntry::print(llvm::raw_ostream &OS) const { OS << '\n'; } + +/// \brief Figure out if an expression could be turned into a call. +/// +/// Use this when trying to recover from an error where the programmer may have +/// written just the name of a function instead of actually calling it. +/// +/// \param E - The expression to examine. +/// \param ZeroArgCallReturnTy - If the expression can be turned into a call +/// with no arguments, this parameter is set to the type returned by such a +/// call; otherwise, it is set to an empty QualType. +/// \param NonTemplateOverloads - If the expression is an overloaded function +/// name, this parameter is populated with the decls of the various overloads. +bool Sema::isExprCallable(const Expr &E, QualType &ZeroArgCallReturnTy, + UnresolvedSetImpl &NonTemplateOverloads) { + ZeroArgCallReturnTy = QualType(); + NonTemplateOverloads.clear(); + if (const OverloadExpr *Overloads = dyn_cast<OverloadExpr>(&E)) { + for (OverloadExpr::decls_iterator it = Overloads->decls_begin(), + DeclsEnd = Overloads->decls_end(); it != DeclsEnd; ++it) { + // Our overload set may include TemplateDecls, which we'll ignore for our + // present purpose. + if (const FunctionDecl *OverloadDecl = dyn_cast<FunctionDecl>(*it)) { + NonTemplateOverloads.addDecl(*it); + if (OverloadDecl->getMinRequiredArguments() == 0) + ZeroArgCallReturnTy = OverloadDecl->getResultType(); + } + } + return true; + } + + if (const DeclRefExpr *DeclRef = dyn_cast<DeclRefExpr>(&E)) { + if (const FunctionDecl *Fun = dyn_cast<FunctionDecl>(DeclRef->getDecl())) { + if (Fun->getMinRequiredArguments() == 0) + ZeroArgCallReturnTy = Fun->getResultType(); + return true; + } + } + + // We don't have an expression that's convenient to get a FunctionDecl from, + // but we can at least check if the type is "function of 0 arguments". + QualType ExprTy = E.getType(); + const FunctionType *FunTy = NULL; + QualType PointeeTy = ExprTy->getPointeeType(); + if (!PointeeTy.isNull()) + FunTy = PointeeTy->getAs<FunctionType>(); + if (!FunTy) + FunTy = ExprTy->getAs<FunctionType>(); + if (!FunTy && ExprTy == Context.BoundMemberTy) { + // Look for the bound-member type. If it's still overloaded, give up, + // although we probably should have fallen into the OverloadExpr case above + // if we actually have an overloaded bound member. + QualType BoundMemberTy = Expr::findBoundMemberType(&E); + if (!BoundMemberTy.isNull()) + FunTy = BoundMemberTy->castAs<FunctionType>(); + } + + if (const FunctionProtoType *FPT = + dyn_cast_or_null<FunctionProtoType>(FunTy)) { + if (FPT->getNumArgs() == 0) + ZeroArgCallReturnTy = FunTy->getResultType(); + return true; + } + return false; +} + +/// \brief Give notes for a set of overloads. +/// +/// A companion to isExprCallable. In cases when the name that the programmer +/// wrote was an overloaded function, we may be able to make some guesses about +/// plausible overloads based on their return types; such guesses can be handed +/// off to this method to be emitted as notes. +/// +/// \param Overloads - The overloads to note. +/// \param FinalNoteLoc - If we've suppressed printing some overloads due to +/// -fshow-overloads=best, this is the location to attach to the note about too +/// many candidates. Typically this will be the location of the original +/// ill-formed expression. +void Sema::NoteOverloads(const UnresolvedSetImpl &Overloads, + const SourceLocation FinalNoteLoc) { + int ShownOverloads = 0; + int SuppressedOverloads = 0; + for (UnresolvedSetImpl::iterator It = Overloads.begin(), + DeclsEnd = Overloads.end(); It != DeclsEnd; ++It) { + // FIXME: Magic number for max shown overloads stolen from + // OverloadCandidateSet::NoteCandidates. + if (ShownOverloads >= 4 && + Diags.getShowOverloads() == Diagnostic::Ovl_Best) { + ++SuppressedOverloads; + continue; + } + Diag(cast<FunctionDecl>(*It)->getSourceRange().getBegin(), + diag::note_member_ref_possible_intended_overload); + ++ShownOverloads; + } + if (SuppressedOverloads) + Diag(FinalNoteLoc, diag::note_ovl_too_many_candidates) + << SuppressedOverloads; +} diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaAccess.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaAccess.cpp index 411d424..a26737e 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaAccess.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaAccess.cpp @@ -146,8 +146,10 @@ struct AccessTarget : public AccessedEntity { MemberNonce _, CXXRecordDecl *NamingClass, DeclAccessPair FoundDecl, - QualType BaseObjectType) - : AccessedEntity(Context, Member, NamingClass, FoundDecl, BaseObjectType) { + QualType BaseObjectType, + bool IsUsingDecl = false) + : AccessedEntity(Context, Member, NamingClass, FoundDecl, BaseObjectType), + IsUsingDeclaration(IsUsingDecl) { initialize(); } @@ -216,6 +218,7 @@ private: DeclaringClass = DeclaringClass->getCanonicalDecl(); } + bool IsUsingDeclaration : 1; bool HasInstanceContext : 1; mutable bool CalculatedInstanceContext : 1; mutable const CXXRecordDecl *InstanceContext; @@ -445,8 +448,8 @@ static AccessResult MatchesFriend(Sema &S, continue; // If the template names don't match, it can't be a dependent - // match. This isn't true in C++0x because of template aliases. - if (!S.LangOpts.CPlusPlus0x && CTD->getDeclName() != Friend->getDeclName()) + // match. + if (CTD->getDeclName() != Friend->getDeclName()) continue; // If the class's context can't instantiate to the friend's @@ -1129,6 +1132,44 @@ static void DiagnoseBadAccess(Sema &S, SourceLocation Loc, DiagnoseAccessPath(S, EC, Entity); } +/// MSVC has a bug where if during an using declaration name lookup, +/// the declaration found is unaccessible (private) and that declaration +/// was bring into scope via another using declaration whose target +/// declaration is accessible (public) then no error is generated. +/// Example: +/// class A { +/// public: +/// int f(); +/// }; +/// class B : public A { +/// private: +/// using A::f; +/// }; +/// class C : public B { +/// private: +/// using B::f; +/// }; +/// +/// Here, B::f is private so this should fail in Standard C++, but +/// because B::f refers to A::f which is public MSVC accepts it. +static bool IsMicrosoftUsingDeclarationAccessBug(Sema& S, + SourceLocation AccessLoc, + AccessTarget &Entity) { + if (UsingShadowDecl *Shadow = + dyn_cast<UsingShadowDecl>(Entity.getTargetDecl())) { + const NamedDecl *OrigDecl = Entity.getTargetDecl()->getUnderlyingDecl(); + if (Entity.getTargetDecl()->getAccess() == AS_private && + (OrigDecl->getAccess() == AS_public || + OrigDecl->getAccess() == AS_protected)) { + S.Diag(AccessLoc, diag::war_ms_using_declaration_inaccessible) + << Shadow->getUsingDecl()->getQualifiedNameAsString() + << OrigDecl->getQualifiedNameAsString(); + return true; + } + } + return false; +} + /// Determines whether the accessed entity is accessible. Public members /// have been weeded out by this point. static AccessResult IsAccessible(Sema &S, @@ -1232,6 +1273,10 @@ static AccessResult CheckEffectiveAccess(Sema &S, AccessTarget &Entity) { assert(Entity.getAccess() != AS_public && "called for public access!"); + if (S.getLangOptions().Microsoft && + IsMicrosoftUsingDeclarationAccessBug(S, Loc, Entity)) + return AR_accessible; + switch (IsAccessible(S, EC, Entity)) { case AR_dependent: DelayDependentAccess(S, EC, Loc, Entity); @@ -1415,30 +1460,48 @@ Sema::AccessResult Sema::CheckConstructorAccess(SourceLocation UseLoc, AccessTarget AccessEntity(Context, AccessTarget::Member, NamingClass, DeclAccessPair::make(Constructor, Access), QualType()); + PartialDiagnostic PD(PDiag()); switch (Entity.getKind()) { default: - AccessEntity.setDiag(IsCopyBindingRefToTemp - ? diag::ext_rvalue_to_reference_access_ctor - : diag::err_access_ctor); + PD = PDiag(IsCopyBindingRefToTemp + ? diag::ext_rvalue_to_reference_access_ctor + : diag::err_access_ctor); + break; case InitializedEntity::EK_Base: - AccessEntity.setDiag(PDiag(diag::err_access_base) - << Entity.isInheritedVirtualBase() - << Entity.getBaseSpecifier()->getType() - << getSpecialMember(Constructor)); + PD = PDiag(diag::err_access_base_ctor); + PD << Entity.isInheritedVirtualBase() + << Entity.getBaseSpecifier()->getType() << getSpecialMember(Constructor); break; case InitializedEntity::EK_Member: { const FieldDecl *Field = cast<FieldDecl>(Entity.getDecl()); - AccessEntity.setDiag(PDiag(diag::err_access_field) - << Field->getType() - << getSpecialMember(Constructor)); + PD = PDiag(diag::err_access_field_ctor); + PD << Field->getType() << getSpecialMember(Constructor); break; } } + return CheckConstructorAccess(UseLoc, Constructor, Access, PD); +} + +/// Checks access to a constructor. +Sema::AccessResult Sema::CheckConstructorAccess(SourceLocation UseLoc, + CXXConstructorDecl *Constructor, + AccessSpecifier Access, + PartialDiagnostic PD) { + if (!getLangOptions().AccessControl || + Access == AS_public) + return AR_accessible; + + CXXRecordDecl *NamingClass = Constructor->getParent(); + AccessTarget AccessEntity(Context, AccessTarget::Member, NamingClass, + DeclAccessPair::make(Constructor, Access), + QualType()); + AccessEntity.setDiag(PD); + return CheckAccess(*this, UseLoc, AccessEntity); } @@ -1465,7 +1528,8 @@ Sema::AccessResult Sema::CheckDirectMemberAccess(SourceLocation UseLoc, Sema::AccessResult Sema::CheckAllocationAccess(SourceLocation OpLoc, SourceRange PlacementRange, CXXRecordDecl *NamingClass, - DeclAccessPair Found) { + DeclAccessPair Found, + bool Diagnose) { if (!getLangOptions().AccessControl || !NamingClass || Found.getAccess() == AS_public) @@ -1473,8 +1537,9 @@ Sema::AccessResult Sema::CheckAllocationAccess(SourceLocation OpLoc, AccessTarget Entity(Context, AccessTarget::Member, NamingClass, Found, QualType()); - Entity.setDiag(diag::err_access) - << PlacementRange; + if (Diagnose) + Entity.setDiag(diag::err_access) + << PlacementRange; return CheckAccess(*this, OpLoc, Entity); } @@ -1573,9 +1638,8 @@ void Sema::CheckLookupAccess(const LookupResult &R) { if (I.getAccess() != AS_public) { AccessTarget Entity(Context, AccessedEntity::Member, R.getNamingClass(), I.getPair(), - R.getBaseObjectType()); + R.getBaseObjectType(), R.isUsingDeclaration()); Entity.setDiag(diag::err_access); - CheckAccess(*this, R.getNameLoc(), Entity); } } diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaCXXCast.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaCXXCast.cpp index ed54f0f..e46ad5b 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaCXXCast.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaCXXCast.cpp @@ -252,8 +252,7 @@ static bool tryDiagnoseOverloadedCast(Sema &S, CastType CT, (CT == CT_CStyle || CT == CT_Functional)); InitializationSequence sequence(S, entity, initKind, &src, 1); - assert(sequence.getKind() == InitializationSequence::FailedSequence && - "initialization succeeded on second try?"); + assert(sequence.Failed() && "initialization succeeded on second try?"); switch (sequence.getFailureKind()) { default: return false; @@ -1195,8 +1194,7 @@ TryStaticImplicitCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, // On the other hand, if we're checking a C-style cast, we've still got // the reinterpret_cast way. - if (InitSeq.getKind() == InitializationSequence::FailedSequence && - (CStyle || !DestType->isReferenceType())) + if (InitSeq.Failed() && (CStyle || !DestType->isReferenceType())) return TC_NotApplicable; ExprResult Result @@ -1288,6 +1286,62 @@ static TryCastResult TryConstCast(Sema &Self, Expr *SrcExpr, QualType DestType, return TC_Success; } +// Checks for undefined behavior in reinterpret_cast. +// The cases that is checked for is: +// *reinterpret_cast<T*>(&a) +// reinterpret_cast<T&>(a) +// where accessing 'a' as type 'T' will result in undefined behavior. +void Sema::CheckCompatibleReinterpretCast(QualType SrcType, QualType DestType, + bool IsDereference, + SourceRange Range) { + unsigned DiagID = IsDereference ? + diag::warn_pointer_indirection_from_incompatible_type : + diag::warn_undefined_reinterpret_cast; + + if (Diags.getDiagnosticLevel(DiagID, Range.getBegin()) == + Diagnostic::Ignored) { + return; + } + + QualType SrcTy, DestTy; + if (IsDereference) { + if (!SrcType->getAs<PointerType>() || !DestType->getAs<PointerType>()) { + return; + } + SrcTy = SrcType->getPointeeType(); + DestTy = DestType->getPointeeType(); + } else { + if (!DestType->getAs<ReferenceType>()) { + return; + } + SrcTy = SrcType; + DestTy = DestType->getPointeeType(); + } + + // Cast is compatible if the types are the same. + if (Context.hasSameUnqualifiedType(DestTy, SrcTy)) { + return; + } + // or one of the types is a char or void type + if (DestTy->isAnyCharacterType() || DestTy->isVoidType() || + SrcTy->isAnyCharacterType() || SrcTy->isVoidType()) { + return; + } + // or one of the types is a tag type. + if (SrcTy->getAs<TagType>() || DestTy->getAs<TagType>()) { + return; + } + + // FIXME: Scoped enums? + if ((SrcTy->isUnsignedIntegerType() && DestTy->isSignedIntegerType()) || + (SrcTy->isSignedIntegerType() && DestTy->isUnsignedIntegerType())) { + if (Context.getTypeSize(DestTy) == Context.getTypeSize(SrcTy)) { + return; + } + } + + Diag(Range.getBegin(), DiagID) << SrcType << DestType << Range; +} static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, bool CStyle, @@ -1324,6 +1378,11 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr, return TC_NotApplicable; } + if (!CStyle) { + Self.CheckCompatibleReinterpretCast(SrcType, DestType, + /*isDereference=*/false, OpRange); + } + // C++ 5.2.10p10: [...] a reference cast reinterpret_cast<T&>(x) has the // same effect as the conversion *reinterpret_cast<T*>(&x) with the // built-in & and * operators. @@ -1454,9 +1513,11 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr, if (DestType->isIntegralType(Self.Context)) { assert(srcIsPtr && "One type must be a pointer"); // C++ 5.2.10p4: A pointer can be explicitly converted to any integral - // type large enough to hold it. - if (Self.Context.getTypeSize(SrcType) > - Self.Context.getTypeSize(DestType)) { + // type large enough to hold it; except in Microsoft mode, where the + // integral type size doesn't matter. + if ((Self.Context.getTypeSize(SrcType) > + Self.Context.getTypeSize(DestType)) && + !Self.getLangOptions().Microsoft) { msg = diag::err_bad_reinterpret_cast_small_int; return TC_Failed; } diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaCXXScopeSpec.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaCXXScopeSpec.cpp index 7049f6b..61d9e93 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaCXXScopeSpec.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaCXXScopeSpec.cpp @@ -94,9 +94,13 @@ DeclContext *Sema::computeDeclContext(const CXXScopeSpec &SS, if (EnteringContext) { const Type *NNSType = NNS->getAsType(); if (!NNSType) { - // do nothing, fall out - } else if (const TemplateSpecializationType *SpecType - = NNSType->getAs<TemplateSpecializationType>()) { + return 0; + } + + // Look through type alias templates, per C++0x [temp.dep.type]p1. + NNSType = Context.getCanonicalType(NNSType); + if (const TemplateSpecializationType *SpecType + = NNSType->getAs<TemplateSpecializationType>()) { // We are entering the context of the nested name specifier, so try to // match the nested name specifier to either a primary class template // or a class template partial specialization. @@ -382,7 +386,7 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S, isDependent = ObjectType->isDependentType(); } else if (SS.isSet()) { // This nested-name-specifier occurs after another nested-name-specifier, - // so long into the context associated with the prior nested-name-specifier. + // so look into the context associated with the prior nested-name-specifier. LookupCtx = computeDeclContext(SS, EnteringContext); isDependent = isDependentScopeSpecifier(SS); Found.setContextRange(SS.getRange()); @@ -419,7 +423,7 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S, // class-name or namespace-name. [...] // // Qualified name lookup into a class will not find a namespace-name, - // so we do not need to diagnoste that case specifically. However, + // so we do not need to diagnose that case specifically. However, // this qualified name lookup may find nothing. In that case, perform // unqualified name lookup in the given scope (if available) or // reconstruct the result from when name lookup was performed at template @@ -546,25 +550,33 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S, InjectedClassNameTypeLoc InjectedTL = TLB.push<InjectedClassNameTypeLoc>(T); InjectedTL.setNameLoc(IdentifierLoc); - } else if (isa<RecordDecl>(SD)) { + } else if (isa<RecordType>(T)) { RecordTypeLoc RecordTL = TLB.push<RecordTypeLoc>(T); RecordTL.setNameLoc(IdentifierLoc); - } else if (isa<TypedefNameDecl>(SD)) { + } else if (isa<TypedefType>(T)) { TypedefTypeLoc TypedefTL = TLB.push<TypedefTypeLoc>(T); TypedefTL.setNameLoc(IdentifierLoc); - } else if (isa<EnumDecl>(SD)) { + } else if (isa<EnumType>(T)) { EnumTypeLoc EnumTL = TLB.push<EnumTypeLoc>(T); EnumTL.setNameLoc(IdentifierLoc); - } else if (isa<TemplateTypeParmDecl>(SD)) { + } else if (isa<TemplateTypeParmType>(T)) { TemplateTypeParmTypeLoc TemplateTypeTL = TLB.push<TemplateTypeParmTypeLoc>(T); TemplateTypeTL.setNameLoc(IdentifierLoc); - } else { - assert(isa<UnresolvedUsingTypenameDecl>(SD) && - "Unhandled TypeDecl node in nested-name-specifier"); + } else if (isa<UnresolvedUsingType>(T)) { UnresolvedUsingTypeLoc UnresolvedTL = TLB.push<UnresolvedUsingTypeLoc>(T); UnresolvedTL.setNameLoc(IdentifierLoc); + } else if (isa<SubstTemplateTypeParmType>(T)) { + SubstTemplateTypeParmTypeLoc TL + = TLB.push<SubstTemplateTypeParmTypeLoc>(T); + TL.setNameLoc(IdentifierLoc); + } else if (isa<SubstTemplateTypeParmPackType>(T)) { + SubstTemplateTypeParmPackTypeLoc TL + = TLB.push<SubstTemplateTypeParmPackTypeLoc>(T); + TL.setNameLoc(IdentifierLoc); + } else { + llvm_unreachable("Unhandled TypeDecl node in nested-name-specifier"); } SS.Extend(Context, SourceLocation(), TLB.getTypeLocInContext(Context, T), @@ -704,8 +716,13 @@ bool Sema::ActOnCXXNestedNameSpecifier(Scope *S, if (T.isNull()) return true; - // FIXME: Template aliases will need to check the resulting type to make - // sure that it's either dependent or a tag type. + // Alias template specializations can produce types which are not valid + // nested name specifiers. + if (!T->isDependentType() && !T->getAs<TagType>()) { + Diag(TemplateNameLoc, diag::err_nested_name_spec_non_tag) << T; + NoteAllFoundTemplates(Template.get()); + return true; + } // Provide source-location information for the template specialization // type. diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaChecking.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaChecking.cpp index 5b645df..7e22b33 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaChecking.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaChecking.cpp @@ -318,9 +318,13 @@ bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall) { TheCall->getCallee()->getLocStart()); } - // Memset handling - if (FnInfo->isStr("memset")) - CheckMemsetArguments(TheCall); + // Memset/memcpy/memmove handling + if (FDecl->getLinkage() == ExternalLinkage && + (!getLangOptions().CPlusPlus || FDecl->isExternC())) { + if (FnInfo->isStr("memset") || FnInfo->isStr("memcpy") || + FnInfo->isStr("memmove")) + CheckMemsetcpymoveArguments(TheCall, FnInfo); + } return false; } @@ -1832,49 +1836,59 @@ void Sema::CheckFormatString(const StringLiteral *FExpr, //===--- CHECK: Standard memory functions ---------------------------------===// +/// \brief Determine whether the given type is a dynamic class type (e.g., +/// whether it has a vtable). +static bool isDynamicClassType(QualType T) { + if (CXXRecordDecl *Record = T->getAsCXXRecordDecl()) + if (CXXRecordDecl *Definition = Record->getDefinition()) + if (Definition->isDynamicClass()) + return true; + + return false; +} + /// \brief Check for dangerous or invalid arguments to memset(). /// -/// This issues warnings on known problematic or dangerous or unspecified -/// arguments to the standard 'memset' function call. +/// This issues warnings on known problematic, dangerous or unspecified +/// arguments to the standard 'memset', 'memcpy', and 'memmove' function calls. /// /// \param Call The call expression to diagnose. -void Sema::CheckMemsetArguments(const CallExpr *Call) { +void Sema::CheckMemsetcpymoveArguments(const CallExpr *Call, + const IdentifierInfo *FnName) { // It is possible to have a non-standard definition of memset. Validate // we have the proper number of arguments, and if not, abort further // checking. if (Call->getNumArgs() != 3) return; - const Expr *Dest = Call->getArg(0)->IgnoreParenImpCasts(); - - // The type checking for this warning is moderately expensive, only do it - // when enabled. - if (getDiagnostics().getDiagnosticLevel(diag::warn_non_pod_memset, - Dest->getExprLoc()) == - Diagnostic::Ignored) - return; - - QualType DestTy = Dest->getType(); - if (const PointerType *DestPtrTy = DestTy->getAs<PointerType>()) { - QualType PointeeTy = DestPtrTy->getPointeeType(); - if (PointeeTy->isVoidType()) - return; - - // Check the C++11 POD definition regardless of language mode; it is more - // relaxed than earlier definitions and we don't want spurrious warnings. - if (PointeeTy->isCXX11PODType()) - return; - - DiagRuntimeBehavior( - Dest->getExprLoc(), Dest, - PDiag(diag::warn_non_pod_memset) - << PointeeTy << Call->getCallee()->getSourceRange()); + unsigned LastArg = FnName->isStr("memset")? 1 : 2; + for (unsigned ArgIdx = 0; ArgIdx != LastArg; ++ArgIdx) { + const Expr *Dest = Call->getArg(ArgIdx)->IgnoreParenImpCasts(); + + QualType DestTy = Dest->getType(); + if (const PointerType *DestPtrTy = DestTy->getAs<PointerType>()) { + QualType PointeeTy = DestPtrTy->getPointeeType(); + if (PointeeTy->isVoidType()) + continue; + + // Always complain about dynamic classes. + if (isDynamicClassType(PointeeTy)) { + DiagRuntimeBehavior( + Dest->getExprLoc(), Dest, + PDiag(diag::warn_dyn_class_memaccess) + << ArgIdx << FnName << PointeeTy + << Call->getCallee()->getSourceRange()); + } else { + continue; + } - SourceRange ArgRange = Call->getArg(0)->getSourceRange(); - DiagRuntimeBehavior( - Dest->getExprLoc(), Dest, - PDiag(diag::note_non_pod_memset_silence) - << FixItHint::CreateInsertion(ArgRange.getBegin(), "(void*)")); + SourceRange ArgRange = Call->getArg(0)->getSourceRange(); + DiagRuntimeBehavior( + Dest->getExprLoc(), Dest, + PDiag(diag::note_bad_memaccess_silence) + << FixItHint::CreateInsertion(ArgRange.getBegin(), "(void*)")); + break; + } } } @@ -2391,7 +2405,7 @@ IntRange GetValueRange(ASTContext &C, APValue &result, QualType Ty, // the sign right on this one case. It would be nice if APValue // preserved this. assert(result.isLValue()); - return IntRange(MaxWidth, Ty->isUnsignedIntegerType()); + return IntRange(MaxWidth, Ty->isUnsignedIntegerOrEnumerationType()); } /// Pseudo-evaluate the given integer expression, estimating the @@ -2565,7 +2579,8 @@ IntRange GetExprRange(ASTContext &C, Expr *E, unsigned MaxWidth) { llvm::APSInt BitWidthAP = BitField->getBitWidth()->EvaluateAsInt(C); unsigned BitWidth = BitWidthAP.getZExtValue(); - return IntRange(BitWidth, BitField->getType()->isUnsignedIntegerType()); + return IntRange(BitWidth, + BitField->getType()->isUnsignedIntegerOrEnumerationType()); } return IntRange::forValueOfType(C, E->getType()); @@ -2982,6 +2997,13 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T, if (!Source->isIntegerType() || !Target->isIntegerType()) return; + if ((E->isNullPointerConstant(S.Context, Expr::NPC_ValueDependentIsNotNull) + == Expr::NPCK_GNUNull) && Target->isIntegerType()) { + S.Diag(E->getExprLoc(), diag::warn_impcast_null_pointer_to_integer) + << E->getSourceRange() << clang::SourceRange(CC); + return; + } + IntRange SourceRange = GetExprRange(S.Context, E); IntRange TargetRange = IntRange::forTargetOfCanonicalType(S.Context, Target); diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaCodeComplete.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaCodeComplete.cpp index cc8726d..e328eeb 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaCodeComplete.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaCodeComplete.cpp @@ -2658,6 +2658,16 @@ CXCursorKind clang::getCursorKindForDecl(Decl *D) { case Decl::UnresolvedUsingTypename: return CXCursor_UsingDeclaration; + case Decl::ObjCPropertyImpl: + switch (cast<ObjCPropertyImplDecl>(D)->getPropertyImplementation()) { + case ObjCPropertyImplDecl::Dynamic: + return CXCursor_ObjCDynamicDecl; + + case ObjCPropertyImplDecl::Synthesize: + return CXCursor_ObjCSynthesizeDecl; + } + break; + default: if (TagDecl *TD = dyn_cast<TagDecl>(D)) { switch (TD->getTagKind()) { @@ -3078,6 +3088,7 @@ typedef llvm::SmallPtrSet<IdentifierInfo*, 16> AddedPropertiesSet; static void AddObjCProperties(ObjCContainerDecl *Container, bool AllowCategories, + bool AllowNullaryMethods, DeclContext *CurContext, AddedPropertiesSet &AddedProperties, ResultBuilder &Results) { @@ -3092,32 +3103,75 @@ static void AddObjCProperties(ObjCContainerDecl *Container, Results.MaybeAddResult(Result(*P, 0), CurContext); } + // Add nullary methods + if (AllowNullaryMethods) { + ASTContext &Context = Container->getASTContext(); + for (ObjCContainerDecl::method_iterator M = Container->meth_begin(), + MEnd = Container->meth_end(); + M != MEnd; ++M) { + if (M->getSelector().isUnarySelector()) + if (IdentifierInfo *Name = M->getSelector().getIdentifierInfoForSlot(0)) + if (AddedProperties.insert(Name)) { + CodeCompletionBuilder Builder(Results.getAllocator()); + AddResultTypeChunk(Context, *M, Builder); + Builder.AddTypedTextChunk( + Results.getAllocator().CopyString(Name->getName())); + + CXAvailabilityKind Availability = CXAvailability_Available; + switch (M->getAvailability()) { + case AR_Available: + case AR_NotYetIntroduced: + Availability = CXAvailability_Available; + break; + + case AR_Deprecated: + Availability = CXAvailability_Deprecated; + break; + + case AR_Unavailable: + Availability = CXAvailability_NotAvailable; + break; + } + + Results.MaybeAddResult(Result(Builder.TakeString(), + CCP_MemberDeclaration + CCD_MethodAsProperty, + M->isInstanceMethod() + ? CXCursor_ObjCInstanceMethodDecl + : CXCursor_ObjCClassMethodDecl, + Availability), + CurContext); + } + } + } + + // Add properties in referenced protocols. if (ObjCProtocolDecl *Protocol = dyn_cast<ObjCProtocolDecl>(Container)) { for (ObjCProtocolDecl::protocol_iterator P = Protocol->protocol_begin(), PEnd = Protocol->protocol_end(); P != PEnd; ++P) - AddObjCProperties(*P, AllowCategories, CurContext, AddedProperties, - Results); + AddObjCProperties(*P, AllowCategories, AllowNullaryMethods, CurContext, + AddedProperties, Results); } else if (ObjCInterfaceDecl *IFace = dyn_cast<ObjCInterfaceDecl>(Container)){ if (AllowCategories) { // Look through categories. for (ObjCCategoryDecl *Category = IFace->getCategoryList(); Category; Category = Category->getNextClassCategory()) - AddObjCProperties(Category, AllowCategories, CurContext, - AddedProperties, Results); + AddObjCProperties(Category, AllowCategories, AllowNullaryMethods, + CurContext, AddedProperties, Results); } // Look through protocols. for (ObjCInterfaceDecl::all_protocol_iterator I = IFace->all_referenced_protocol_begin(), E = IFace->all_referenced_protocol_end(); I != E; ++I) - AddObjCProperties(*I, AllowCategories, CurContext, AddedProperties, - Results); + AddObjCProperties(*I, AllowCategories, AllowNullaryMethods, CurContext, + AddedProperties, Results); // Look in the superclass. if (IFace->getSuperClass()) - AddObjCProperties(IFace->getSuperClass(), AllowCategories, CurContext, + AddObjCProperties(IFace->getSuperClass(), AllowCategories, + AllowNullaryMethods, CurContext, AddedProperties, Results); } else if (const ObjCCategoryDecl *Category = dyn_cast<ObjCCategoryDecl>(Container)) { @@ -3125,8 +3179,8 @@ static void AddObjCProperties(ObjCContainerDecl *Container, for (ObjCCategoryDecl::protocol_iterator P = Category->protocol_begin(), PEnd = Category->protocol_end(); P != PEnd; ++P) - AddObjCProperties(*P, AllowCategories, CurContext, AddedProperties, - Results); + AddObjCProperties(*P, AllowCategories, AllowNullaryMethods, CurContext, + AddedProperties, Results); } } @@ -3192,14 +3246,16 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *BaseE, const ObjCObjectPointerType *ObjCPtr = BaseType->getAsObjCInterfacePointerType(); assert(ObjCPtr && "Non-NULL pointer guaranteed above!"); - AddObjCProperties(ObjCPtr->getInterfaceDecl(), true, CurContext, + AddObjCProperties(ObjCPtr->getInterfaceDecl(), true, + /*AllowNullaryMethods=*/true, CurContext, AddedProperties, Results); // Add properties from the protocols in a qualified interface. for (ObjCObjectPointerType::qual_iterator I = ObjCPtr->qual_begin(), E = ObjCPtr->qual_end(); I != E; ++I) - AddObjCProperties(*I, true, CurContext, AddedProperties, Results); + AddObjCProperties(*I, true, /*AllowNullaryMethods=*/true, CurContext, + AddedProperties, Results); } else if ((IsArrow && BaseType->isObjCObjectPointerType()) || (!IsArrow && BaseType->isObjCObjectType())) { // Objective-C instance variable access. @@ -4109,6 +4165,8 @@ void Sema::CodeCompleteObjCPropertyFlags(Scope *S, ObjCDeclSpec &ODS) { Results.AddResult(CodeCompletionResult("copy")); if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_nonatomic)) Results.AddResult(CodeCompletionResult("nonatomic")); + if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_atomic)) + Results.AddResult(CodeCompletionResult("atomic")); if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_setter)) { CodeCompletionBuilder Setter(Results.getAllocator()); Setter.AddTypedTextChunk("setter"); @@ -5334,11 +5392,13 @@ void Sema::CodeCompleteObjCPropertyDefinition(Scope *S, Decl *ObjCImpDecl) { Results.EnterNewScope(); if (ObjCImplementationDecl *ClassImpl = dyn_cast<ObjCImplementationDecl>(Container)) - AddObjCProperties(ClassImpl->getClassInterface(), false, CurContext, + AddObjCProperties(ClassImpl->getClassInterface(), false, + /*AllowNullaryMethods=*/false, CurContext, AddedProperties, Results); else AddObjCProperties(cast<ObjCCategoryImplDecl>(Container)->getCategoryDecl(), - false, CurContext, AddedProperties, Results); + false, /*AllowNullaryMethods=*/false, CurContext, + AddedProperties, Results); Results.ExitScope(); HandleCodeCompleteResults(this, CodeCompleter, @@ -5549,7 +5609,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, bool IsInstanceMethod, QualType ReturnType, ASTContext &Context, - const KnownMethodsMap &KnownMethods, + VisitedSelectorSet &KnownSelectors, ResultBuilder &Results) { IdentifierInfo *PropName = Property->getIdentifier(); if (!PropName || PropName->getLength() == 0) @@ -5595,7 +5655,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, // Add the normal accessor -(type)key. if (IsInstanceMethod && - !KnownMethods.count(Selectors.getNullarySelector(PropName)) && + KnownSelectors.insert(Selectors.getNullarySelector(PropName)) && ReturnTypeMatchesProperty && !Property->getGetterMethodDecl()) { if (ReturnType.isNull()) AddObjCPassingTypeChunk(Property->getType(), Context, Builder); @@ -5615,7 +5675,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, Property->getType()->isBooleanType())))) { std::string SelectorName = (llvm::Twine("is") + UpperKey).str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); - if (!KnownMethods.count(Selectors.getNullarySelector(SelectorId))) { + if (KnownSelectors.insert(Selectors.getNullarySelector(SelectorId))) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("BOOL"); @@ -5634,7 +5694,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, !Property->getSetterMethodDecl()) { std::string SelectorName = (llvm::Twine("set") + UpperKey).str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); - if (!KnownMethods.count(Selectors.getUnarySelector(SelectorId))) { + if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("void"); @@ -5685,7 +5745,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, (ReturnType.isNull() || ReturnType->isIntegerType())) { std::string SelectorName = (llvm::Twine("countOf") + UpperKey).str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); - if (!KnownMethods.count(Selectors.getNullarySelector(SelectorId))) { + if (KnownSelectors.insert(Selectors.getNullarySelector(SelectorId))) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("NSUInteger"); @@ -5708,7 +5768,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, std::string SelectorName = (llvm::Twine("objectIn") + UpperKey + "AtIndex").str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); - if (!KnownMethods.count(Selectors.getUnarySelector(SelectorId))) { + if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("id"); @@ -5735,7 +5795,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, std::string SelectorName = (llvm::Twine(Property->getName()) + "AtIndexes").str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); - if (!KnownMethods.count(Selectors.getUnarySelector(SelectorId))) { + if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("NSArray *"); @@ -5760,7 +5820,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, &Context.Idents.get("range") }; - if (!KnownMethods.count(Selectors.getSelector(2, SelectorIds))) { + if (KnownSelectors.insert(Selectors.getSelector(2, SelectorIds))) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("void"); @@ -5794,7 +5854,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, &Context.Idents.get(SelectorName) }; - if (!KnownMethods.count(Selectors.getSelector(2, SelectorIds))) { + if (KnownSelectors.insert(Selectors.getSelector(2, SelectorIds))) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("void"); @@ -5826,7 +5886,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, &Context.Idents.get("atIndexes") }; - if (!KnownMethods.count(Selectors.getSelector(2, SelectorIds))) { + if (KnownSelectors.insert(Selectors.getSelector(2, SelectorIds))) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("void"); @@ -5854,7 +5914,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, std::string SelectorName = (llvm::Twine("removeObjectFrom") + UpperKey + "AtIndex").str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); - if (!KnownMethods.count(Selectors.getUnarySelector(SelectorId))) { + if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("void"); @@ -5876,7 +5936,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, std::string SelectorName = (llvm::Twine("remove") + UpperKey + "AtIndexes").str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); - if (!KnownMethods.count(Selectors.getUnarySelector(SelectorId))) { + if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("void"); @@ -5902,7 +5962,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, &Context.Idents.get("withObject") }; - if (!KnownMethods.count(Selectors.getSelector(2, SelectorIds))) { + if (KnownSelectors.insert(Selectors.getSelector(2, SelectorIds))) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("void"); @@ -5935,7 +5995,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, &Context.Idents.get(SelectorName2) }; - if (!KnownMethods.count(Selectors.getSelector(2, SelectorIds))) { + if (KnownSelectors.insert(Selectors.getSelector(2, SelectorIds))) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("void"); @@ -5968,7 +6028,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, ->getName() == "NSEnumerator"))) { std::string SelectorName = (llvm::Twine("enumeratorOf") + UpperKey).str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); - if (!KnownMethods.count(Selectors.getNullarySelector(SelectorId))) { + if (KnownSelectors.insert(Selectors.getNullarySelector(SelectorId))) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("NSEnumerator *"); @@ -5986,7 +6046,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, (ReturnType.isNull() || ReturnType->isObjCObjectPointerType())) { std::string SelectorName = (llvm::Twine("memberOf") + UpperKey).str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); - if (!KnownMethods.count(Selectors.getUnarySelector(SelectorId))) { + if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddPlaceholderChunk("object-type"); @@ -6016,7 +6076,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, std::string SelectorName = (llvm::Twine("add") + UpperKey + llvm::Twine("Object")).str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); - if (!KnownMethods.count(Selectors.getUnarySelector(SelectorId))) { + if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("void"); @@ -6038,7 +6098,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, if (IsInstanceMethod && ReturnTypeMatchesVoid) { std::string SelectorName = (llvm::Twine("add") + UpperKey).str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); - if (!KnownMethods.count(Selectors.getUnarySelector(SelectorId))) { + if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("void"); @@ -6060,7 +6120,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, std::string SelectorName = (llvm::Twine("remove") + UpperKey + llvm::Twine("Object")).str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); - if (!KnownMethods.count(Selectors.getUnarySelector(SelectorId))) { + if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("void"); @@ -6082,7 +6142,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, if (IsInstanceMethod && ReturnTypeMatchesVoid) { std::string SelectorName = (llvm::Twine("remove") + UpperKey).str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); - if (!KnownMethods.count(Selectors.getUnarySelector(SelectorId))) { + if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("void"); @@ -6103,7 +6163,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, if (IsInstanceMethod && ReturnTypeMatchesVoid) { std::string SelectorName = (llvm::Twine("intersect") + UpperKey).str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); - if (!KnownMethods.count(Selectors.getUnarySelector(SelectorId))) { + if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("void"); @@ -6131,7 +6191,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, std::string SelectorName = (llvm::Twine("keyPathsForValuesAffecting") + UpperKey).str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); - if (!KnownMethods.count(Selectors.getNullarySelector(SelectorId))) { + if (KnownSelectors.insert(Selectors.getNullarySelector(SelectorId))) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("NSSet *"); @@ -6140,7 +6200,28 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName)); Results.AddResult(Result(Builder.TakeString(), CCP_CodePattern, - CXCursor_ObjCInstanceMethodDecl)); + CXCursor_ObjCClassMethodDecl)); + } + } + + // + (BOOL)automaticallyNotifiesObserversForKey + if (!IsInstanceMethod && + (ReturnType.isNull() || + ReturnType->isIntegerType() || + ReturnType->isBooleanType())) { + std::string SelectorName + = (llvm::Twine("automaticallyNotifiesObserversOf") + UpperKey).str(); + IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); + if (KnownSelectors.insert(Selectors.getNullarySelector(SelectorId))) { + if (ReturnType.isNull()) { + Builder.AddChunk(CodeCompletionString::CK_LeftParen); + Builder.AddTextChunk("BOOL"); + Builder.AddChunk(CodeCompletionString::CK_RightParen); + } + + Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName)); + Results.AddResult(Result(Builder.TakeString(), CCP_CodePattern, + CXCursor_ObjCClassMethodDecl)); } } } @@ -6271,6 +6352,13 @@ void Sema::CodeCompleteObjCMethodDecl(Scope *S, llvm::SmallVector<ObjCContainerDecl *, 4> Containers; Containers.push_back(SearchDecl); + VisitedSelectorSet KnownSelectors; + for (KnownMethodsMap::iterator M = KnownMethods.begin(), + MEnd = KnownMethods.end(); + M != MEnd; ++M) + KnownSelectors.insert(M->first); + + ObjCInterfaceDecl *IFace = dyn_cast<ObjCInterfaceDecl>(SearchDecl); if (!IFace) if (ObjCCategoryDecl *Category = dyn_cast<ObjCCategoryDecl>(SearchDecl)) @@ -6287,7 +6375,7 @@ void Sema::CodeCompleteObjCMethodDecl(Scope *S, PEnd = Containers[I]->prop_end(); P != PEnd; ++P) { AddObjCKeyValueCompletions(*P, IsInstanceMethod, ReturnType, Context, - KnownMethods, Results); + KnownSelectors, Results); } } } diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaDecl.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaDecl.cpp index 7214988..9446c0e 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaDecl.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaDecl.cpp @@ -891,19 +891,19 @@ static bool isOutOfScopePreviousDeclaration(NamedDecl *, /// Filters out lookup results that don't fall within the given scope /// as determined by isDeclInScope. -static void FilterLookupForScope(Sema &SemaRef, LookupResult &R, - DeclContext *Ctx, Scope *S, - bool ConsiderLinkage, - bool ExplicitInstantiationOrSpecialization) { +void Sema::FilterLookupForScope(LookupResult &R, + DeclContext *Ctx, Scope *S, + bool ConsiderLinkage, + bool ExplicitInstantiationOrSpecialization) { LookupResult::Filter F = R.makeFilter(); while (F.hasNext()) { NamedDecl *D = F.next(); - if (SemaRef.isDeclInScope(D, Ctx, S, ExplicitInstantiationOrSpecialization)) + if (isDeclInScope(D, Ctx, S, ExplicitInstantiationOrSpecialization)) continue; if (ConsiderLinkage && - isOutOfScopePreviousDeclaration(D, Ctx, SemaRef.Context)) + isOutOfScopePreviousDeclaration(D, Ctx, Context)) continue; F.erase(); @@ -938,7 +938,7 @@ static void RemoveUsingDecls(LookupResult &R) { static bool IsDisallowedCopyOrAssign(const CXXMethodDecl *D) { // FIXME: Should check for private access too but access is set after we get // the decl here. - if (D->isThisDeclarationADefinition()) + if (D->doesThisDeclarationHaveABody()) return false; if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(D)) @@ -973,10 +973,9 @@ bool Sema::ShouldWarnIfUnusedFileScopedDecl(const DeclaratorDecl *D) const { return false; } - if (FD->isThisDeclarationADefinition() && + if (FD->doesThisDeclarationHaveABody() && Context.DeclMustBeEmitted(FD)) return false; - } else if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { if (!VD->isFileVarDecl() || VD->getType().isConstant(Context) || @@ -1506,18 +1505,21 @@ struct GNUCompatibleParamWarning { /// getSpecialMember - get the special member enum for a method. Sema::CXXSpecialMember Sema::getSpecialMember(const CXXMethodDecl *MD) { if (const CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(MD)) { + if (Ctor->isDefaultConstructor()) + return Sema::CXXDefaultConstructor; + if (Ctor->isCopyConstructor()) return Sema::CXXCopyConstructor; - - return Sema::CXXConstructor; - } - - if (isa<CXXDestructorDecl>(MD)) + + if (Ctor->isMoveConstructor()) + return Sema::CXXMoveConstructor; + } else if (isa<CXXDestructorDecl>(MD)) { return Sema::CXXDestructor; - - assert(MD->isCopyAssignmentOperator() && - "Must have copy assignment operator"); - return Sema::CXXCopyAssignment; + } else if (MD->isCopyAssignmentOperator()) { + return Sema::CXXCopyAssignment; + } + + return Sema::CXXInvalid; } /// canRedefineFunction - checks if a function can be redefined. Currently, @@ -1525,7 +1527,7 @@ Sema::CXXSpecialMember Sema::getSpecialMember(const CXXMethodDecl *MD) { /// GNU89 mode. static bool canRedefineFunction(const FunctionDecl *FD, const LangOptions& LangOpts) { - return (LangOpts.GNUMode && !LangOpts.C99 && !LangOpts.CPlusPlus && + return (LangOpts.GNUInline && !LangOpts.CPlusPlus && FD->isInlineSpecified() && FD->getStorageClass() == SC_Extern); } @@ -1728,6 +1730,11 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) { << New << getSpecialMember(OldMethod); return true; } + } else if (OldMethod->isExplicitlyDefaulted()) { + Diag(NewMethod->getLocation(), + diag::err_definition_of_explicitly_defaulted_member) + << getSpecialMember(OldMethod); + return true; } } @@ -1907,10 +1914,6 @@ bool Sema::MergeCompatibleFunctionDecls(FunctionDecl *New, FunctionDecl *Old) { if (Old->isPure()) New->setPure(); - // Merge the "deleted" flag. - if (Old->isDeleted()) - New->setDeleted(); - // Merge attributes from the parameters. These can mismatch with K&R // declarations. if (New->getNumParams() == Old->getNumParams()) @@ -1933,7 +1936,9 @@ void Sema::mergeObjCMethodDecls(ObjCMethodDecl *newMethod, for (ObjCMethodDecl::param_iterator oi = oldMethod->param_begin(), ni = newMethod->param_begin(), ne = newMethod->param_end(); ni != ne; ++ni, ++oi) - mergeParamDeclAttributes(*ni, *oi, Context); + mergeParamDeclAttributes(*ni, *oi, Context); + + CheckObjCMethodOverride(newMethod, oldMethod, true); } /// MergeVarDeclTypes - We parsed a variable 'New' which has the same name and @@ -2132,6 +2137,16 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) { /// no declarator (e.g. "struct foo;") is parsed. Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, DeclSpec &DS) { + return ParsedFreeStandingDeclSpec(S, AS, DS, + MultiTemplateParamsArg(*this, 0, 0)); +} + +/// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with +/// no declarator (e.g. "struct foo;") is parsed. It also accopts template +/// parameters to cope with template friend declarations. +Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, + DeclSpec &DS, + MultiTemplateParamsArg TemplateParams) { Decl *TagD = 0; TagDecl *Tag = 0; if (DS.getTypeSpecType() == DeclSpec::TST_class || @@ -2163,7 +2178,7 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, // whatever routines created it handled the friendship aspect. if (TagD && !Tag) return 0; - return ActOnFriendTypeDecl(S, DS, MultiTemplateParamsArg(*this, 0, 0)); + return ActOnFriendTypeDecl(S, DS, TemplateParams); } // Track whether we warned about the fact that there aren't any @@ -2484,6 +2499,24 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, PrevSpec, DiagID, getLangOptions()); } + // Ignore const/volatile/restrict qualifiers. + if (DS.getTypeQualifiers()) { + if (DS.getTypeQualifiers() & DeclSpec::TQ_const) + Diag(DS.getConstSpecLoc(), diag::ext_anonymous_struct_union_qualified) + << Record->isUnion() << 0 + << FixItHint::CreateRemoval(DS.getConstSpecLoc()); + if (DS.getTypeQualifiers() & DeclSpec::TQ_volatile) + Diag(DS.getVolatileSpecLoc(), diag::ext_anonymous_struct_union_qualified) + << Record->isUnion() << 1 + << FixItHint::CreateRemoval(DS.getVolatileSpecLoc()); + if (DS.getTypeQualifiers() & DeclSpec::TQ_restrict) + Diag(DS.getRestrictSpecLoc(), diag::ext_anonymous_struct_union_qualified) + << Record->isUnion() << 2 + << FixItHint::CreateRemoval(DS.getRestrictSpecLoc()); + + DS.ClearTypeQualifiers(); + } + // C++ [class.union]p2: // The member-specification of an anonymous union shall only // define non-static data members. [Note: nested types and @@ -2502,7 +2535,12 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, Invalid = true; } - if (CheckNontrivialField(FD)) + // C++ [class.union]p1 + // An object of a class with a non-trivial constructor, a non-trivial + // copy constructor, a non-trivial destructor, or a non-trivial copy + // assignment operator cannot be a member of a union, nor can an + // array of such objects. + if (!getLangOptions().CPlusPlus0x && CheckNontrivialField(FD)) Invalid = true; } else if ((*Mem)->isImplicit()) { // Any implicit members are fine. @@ -2572,7 +2610,8 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, /*IdentifierInfo=*/0, Context.getTypeDeclType(Record), TInfo, - /*BitWidth=*/0, /*Mutable=*/false); + /*BitWidth=*/0, /*Mutable=*/false, + /*HasInit=*/false); Anon->setAccess(AS); if (getLangOptions().CPlusPlus) FieldCollector->Add(cast<FieldDecl>(Anon)); @@ -2662,7 +2701,8 @@ Decl *Sema::BuildMicrosoftCAnonymousStruct(Scope *S, DeclSpec &DS, /*IdentifierInfo=*/0, Context.getTypeDeclType(Record), TInfo, - /*BitWidth=*/0, /*Mutable=*/false); + /*BitWidth=*/0, /*Mutable=*/false, + /*HasInit=*/false); Anon->setImplicit(); // Add the anonymous struct object to the current context. @@ -2829,7 +2869,8 @@ static bool RebuildDeclaratorInCurrentInstantiation(Sema &S, Declarator &D, switch (DS.getTypeSpecType()) { case DeclSpec::TST_typename: case DeclSpec::TST_typeofType: - case DeclSpec::TST_decltype: { + case DeclSpec::TST_decltype: + case DeclSpec::TST_underlyingType: { // Grab the type from the parser. TypeSourceInfo *TSI = 0; QualType T = S.GetTypeFromParser(DS.getRepAsType(), &TSI); @@ -2883,8 +2924,10 @@ static bool RebuildDeclaratorInCurrentInstantiation(Sema &S, Declarator &D, return false; } -Decl *Sema::ActOnDeclarator(Scope *S, Declarator &D) { - return HandleDeclarator(S, D, MultiTemplateParamsArg(*this), false); +Decl *Sema::ActOnDeclarator(Scope *S, Declarator &D, + bool IsFunctionDefinition) { + return HandleDeclarator(S, D, MultiTemplateParamsArg(*this), + IsFunctionDefinition); } /// DiagnoseClassNameShadow - Implement C++ [class.mem]p13: @@ -2952,7 +2995,6 @@ Decl *Sema::HandleDeclarator(Scope *S, Declarator &D, << D.getCXXScopeSpec().getRange(); return 0; } - bool IsDependentContext = DC->isDependentContext(); if (!IsDependentContext && @@ -3294,15 +3336,13 @@ Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC, // Handle attributes prior to checking for duplicates in MergeVarDecl ProcessDeclAttributes(S, NewTD, D); + CheckTypedefForVariablyModifiedType(S, NewTD); + return ActOnTypedefNameDecl(S, DC, NewTD, Previous, Redeclaration); } -/// ActOnTypedefNameDecl - Perform semantic checking for a declaration which -/// declares a typedef-name, either using the 'typedef' type specifier or via -/// a C++0x [dcl.typedef]p2 alias-declaration: 'using T = A;'. -NamedDecl* -Sema::ActOnTypedefNameDecl(Scope *S, DeclContext *DC, TypedefNameDecl *NewTD, - LookupResult &Previous, bool &Redeclaration) { +void +Sema::CheckTypedefForVariablyModifiedType(Scope *S, TypedefNameDecl *NewTD) { // C99 6.7.7p2: If a typedef name specifies a variably modified type // then it shall have block scope. // Note that variably modified types must be fixed before merging the decl so @@ -3333,10 +3373,18 @@ Sema::ActOnTypedefNameDecl(Scope *S, DeclContext *DC, TypedefNameDecl *NewTD, } } } +} + +/// ActOnTypedefNameDecl - Perform semantic checking for a declaration which +/// declares a typedef-name, either using the 'typedef' type specifier or via +/// a C++0x [dcl.typedef]p2 alias-declaration: 'using T = A;'. +NamedDecl* +Sema::ActOnTypedefNameDecl(Scope *S, DeclContext *DC, TypedefNameDecl *NewTD, + LookupResult &Previous, bool &Redeclaration) { // Merge the decl with the existing one if appropriate. If the decl is // in an outer scope, it isn't the same thing. - FilterLookupForScope(*this, Previous, DC, S, /*ConsiderLinkage*/ false, + FilterLookupForScope(Previous, DC, S, /*ConsiderLinkage*/ false, /*ExplicitInstantiationOrSpecialization=*/false); if (!Previous.empty()) { Redeclaration = true; @@ -3518,7 +3566,8 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, bool Invalid = false; if (TemplateParameterList *TemplateParams = MatchTemplateParametersToScopeSpecifier( - D.getDeclSpec().getSourceRange().getBegin(), + D.getDeclSpec().getSourceRange().getBegin(), + D.getIdentifierLoc(), D.getCXXScopeSpec(), TemplateParamLists.get(), TemplateParamLists.size(), @@ -3540,7 +3589,6 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, << II << SourceRange(TemplateParams->getTemplateLoc(), TemplateParams->getRAngleLoc()); - isExplicitSpecialization = true; } } @@ -3615,7 +3663,7 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, // Don't consider existing declarations that are in a different // scope and are out-of-semantic-context declarations (if the new // declaration has linkage). - FilterLookupForScope(*this, Previous, DC, S, NewVD->hasLinkage(), + FilterLookupForScope(Previous, DC, S, NewVD->hasLinkage(), isExplicitSpecialization); if (!getLangOptions().CPlusPlus) @@ -3806,8 +3854,12 @@ void Sema::CheckVariableDeclaration(VarDecl *NewVD, } if (NewVD->hasLocalStorage() && T.isObjCGCWeak() - && !NewVD->hasAttr<BlocksAttr>()) - Diag(NewVD->getLocation(), diag::warn_attribute_weak_on_local); + && !NewVD->hasAttr<BlocksAttr>()) { + if (getLangOptions().getGCMode() != LangOptions::NonGC) + Diag(NewVD->getLocation(), diag::warn_gc_attribute_weak_on_local); + else + Diag(NewVD->getLocation(), diag::warn_attribute_weak_on_local); + } bool isVM = T->isVariablyModifiedType(); if (isVM || NewVD->hasAttr<CleanupAttr>() || @@ -4062,7 +4114,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, // Set the lexical context. NewFD->setLexicalDeclContext(CurContext); // Filter out previous declarations that don't match the scope. - FilterLookupForScope(*this, Previous, DC, S, NewFD->hasLinkage(), + FilterLookupForScope(Previous, DC, S, NewFD->hasLinkage(), /*ExplicitInstantiationOrSpecialization=*/false); } else { isFriend = D.getDeclSpec().isFriendSpecified(); @@ -4088,24 +4140,38 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, R = CheckConstructorDeclarator(D, R, SC); // Create the new declaration - NewFD = CXXConstructorDecl::Create(Context, + CXXConstructorDecl *NewCD = CXXConstructorDecl::Create( + Context, cast<CXXRecordDecl>(DC), D.getSourceRange().getBegin(), NameInfo, R, TInfo, isExplicit, isInline, /*isImplicitlyDeclared=*/false); + + NewFD = NewCD; } else if (Name.getNameKind() == DeclarationName::CXXDestructorName) { // This is a C++ destructor declaration. if (DC->isRecord()) { R = CheckDestructorDeclarator(D, R, SC); + CXXRecordDecl *Record = cast<CXXRecordDecl>(DC); - NewFD = CXXDestructorDecl::Create(Context, - cast<CXXRecordDecl>(DC), + CXXDestructorDecl *NewDD = CXXDestructorDecl::Create(Context, Record, D.getSourceRange().getBegin(), NameInfo, R, TInfo, isInline, /*isImplicitlyDeclared=*/false); + NewFD = NewDD; isVirtualOkay = true; + + // If the class is complete, then we now create the implicit exception + // specification. If the class is incomplete or dependent, we can't do + // it yet. + if (getLangOptions().CPlusPlus0x && !Record->isDependentType() && + Record->getDefinition() && !Record->isBeingDefined() && + R->getAs<FunctionProtoType>()->getExceptionSpecType() == EST_None) { + AdjustDestructorExceptionSpec(Record, NewDD); + } + } else { Diag(D.getIdentifierLoc(), diag::err_destructor_not_member); @@ -4162,11 +4228,13 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, isStatic = true; // This is a C++ method declaration. - NewFD = CXXMethodDecl::Create(Context, cast<CXXRecordDecl>(DC), - D.getSourceRange().getBegin(), - NameInfo, R, TInfo, - isStatic, SCAsWritten, isInline, - SourceLocation()); + CXXMethodDecl *NewMD = CXXMethodDecl::Create( + Context, cast<CXXRecordDecl>(DC), + D.getSourceRange().getBegin(), + NameInfo, R, TInfo, + isStatic, SCAsWritten, isInline, + SourceLocation()); + NewFD = NewMD; isVirtualOkay = !isStatic; } else { @@ -4202,6 +4270,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, if (TemplateParameterList *TemplateParams = MatchTemplateParametersToScopeSpecifier( D.getDeclSpec().getSourceRange().getBegin(), + D.getIdentifierLoc(), D.getCXXScopeSpec(), TemplateParamLists.get(), TemplateParamLists.size(), @@ -4339,7 +4408,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, } // Filter out previous declarations that don't match the scope. - FilterLookupForScope(*this, Previous, DC, S, NewFD->hasLinkage(), + FilterLookupForScope(Previous, DC, S, NewFD->hasLinkage(), isExplicitSpecialization || isFunctionTemplateSpecialization); @@ -4406,6 +4475,9 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, bool IsTypeAlias = false; if (const TypedefType *TT = Param->getType()->getAs<TypedefType>()) IsTypeAlias = isa<TypeAliasDecl>(TT->getDecl()); + else if (const TemplateSpecializationType *TST = + Param->getType()->getAs<TemplateSpecializationType>()) + IsTypeAlias = TST->isTypeAlias(); Diag(Param->getLocation(), diag::err_param_typedef_of_void) << IsTypeAlias; } @@ -4452,8 +4524,8 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, if (!getLangOptions().CPlusPlus) { // Perform semantic checking on the function declaration. - bool isExplctSpecialization=false; - CheckFunctionDeclaration(S, NewFD, Previous, isExplctSpecialization, + bool isExplicitSpecialization=false; + CheckFunctionDeclaration(S, NewFD, Previous, isExplicitSpecialization, Redeclaration); assert((NewFD->isInvalidDecl() || !Redeclaration || Previous.getResultKind() != LookupResult::FoundOverloaded) && @@ -4476,7 +4548,9 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, HasExplicitTemplateArgs = true; - if (FunctionTemplate) { + if (NewFD->isInvalidDecl()) { + HasExplicitTemplateArgs = false; + } else if (FunctionTemplate) { // Function template with explicit template arguments. Diag(D.getIdentifierLoc(), diag::err_function_template_partial_spec) << SourceRange(TemplateId->LAngleLoc, TemplateId->RAngleLoc); @@ -4532,6 +4606,16 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, (HasExplicitTemplateArgs ? &TemplateArgs : 0), Previous)) NewFD->setInvalidDecl(); + + // C++ [dcl.stc]p1: + // A storage-class-specifier shall not be specified in an explicit + // specialization (14.7.3) + if (SC != SC_None) { + Diag(NewFD->getLocation(), + diag::err_explicit_specialization_storage_class) + << FixItHint::CreateRemoval(D.getDeclSpec().getStorageClassSpecLoc()); + } + } else if (isExplicitSpecialization && isa<CXXMethodDecl>(NewFD)) { if (CheckMemberSpecialization(NewFD, Previous)) NewFD->setInvalidDecl(); @@ -4647,8 +4731,8 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, << D.getCXXScopeSpec().getRange(); } } - - + + // Handle attributes. We need to have merged decls when handling attributes // (for example to check for conflicts, etc). // FIXME: This needs to happen before we merge declarations. Then, @@ -4661,7 +4745,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, if (Redeclaration && Previous.isSingleResult()) { const FunctionDecl *Def; FunctionDecl *PrevFD = dyn_cast<FunctionDecl>(Previous.getFoundDecl()); - if (PrevFD && PrevFD->hasBody(Def) && D.hasAttributes()) { + if (PrevFD && PrevFD->isDefined(Def) && D.hasAttributes()) { Diag(NewFD->getLocation(), diag::warn_attribute_precede_definition); Diag(Def->getLocation(), diag::note_previous_definition); } @@ -5076,9 +5160,11 @@ namespace { if (OrigDecl != ReferenceDecl) return; LookupResult Result(S, DRE->getNameInfo(), Sema::LookupOrdinaryName, Sema::NotForRedeclaration); - S.Diag(SubExpr->getLocStart(), diag::warn_uninit_self_reference_in_init) - << Result.getLookupName() << OrigDecl->getLocation() - << SubExpr->getSourceRange(); + S.DiagRuntimeBehavior(SubExpr->getLocStart(), SubExpr, + S.PDiag(diag::warn_uninit_self_reference_in_init) + << Result.getLookupName() + << OrigDecl->getLocation() + << SubExpr->getSourceRange()); } }; } @@ -5553,40 +5639,53 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl, return; } - const RecordType *Record - = Context.getBaseElementType(Type)->getAs<RecordType>(); - if (Record && getLangOptions().CPlusPlus && - cast<CXXRecordDecl>(Record->getDecl())->isPOD()) { - // C++03 [dcl.init]p9: - // If no initializer is specified for an object, and the - // object is of (possibly cv-qualified) non-POD class type (or - // array thereof), the object shall be default-initialized; if - // the object is of const-qualified type, the underlying class - // type shall have a user-declared default - // constructor. Otherwise, if no initializer is specified for - // a non- static object, the object and its subobjects, if - // any, have an indeterminate initial value); if the object - // or any of its subobjects are of const-qualified type, the - // program is ill-formed. - } else { - // Check for jumps past the implicit initializer. C++0x - // clarifies that this applies to a "variable with automatic - // storage duration", not a "local variable". - if (getLangOptions().CPlusPlus && Var->hasLocalStorage()) - getCurFunction()->setHasBranchProtectedScope(); - - InitializedEntity Entity = InitializedEntity::InitializeVariable(Var); - InitializationKind Kind - = InitializationKind::CreateDefault(Var->getLocation()); - - InitializationSequence InitSeq(*this, Entity, Kind, 0, 0); - ExprResult Init = InitSeq.Perform(*this, Entity, Kind, - MultiExprArg(*this, 0, 0)); - if (Init.isInvalid()) - Var->setInvalidDecl(); - else if (Init.get()) - Var->setInit(MaybeCreateExprWithCleanups(Init.get())); + // Check for jumps past the implicit initializer. C++0x + // clarifies that this applies to a "variable with automatic + // storage duration", not a "local variable". + // C++0x [stmt.dcl]p3 + // A program that jumps from a point where a variable with automatic + // storage duration is not in scope to a point where it is in scope is + // ill-formed unless the variable has scalar type, class type with a + // trivial default constructor and a trivial destructor, a cv-qualified + // version of one of these types, or an array of one of the preceding + // types and is declared without an initializer. + if (getLangOptions().CPlusPlus && Var->hasLocalStorage()) { + if (const RecordType *Record + = Context.getBaseElementType(Type)->getAs<RecordType>()) { + CXXRecordDecl *CXXRecord = cast<CXXRecordDecl>(Record->getDecl()); + if ((!getLangOptions().CPlusPlus0x && !CXXRecord->isPOD()) || + (getLangOptions().CPlusPlus0x && + (!CXXRecord->hasTrivialDefaultConstructor() || + !CXXRecord->hasTrivialDestructor()))) + getCurFunction()->setHasBranchProtectedScope(); + } } + + // C++03 [dcl.init]p9: + // If no initializer is specified for an object, and the + // object is of (possibly cv-qualified) non-POD class type (or + // array thereof), the object shall be default-initialized; if + // the object is of const-qualified type, the underlying class + // type shall have a user-declared default + // constructor. Otherwise, if no initializer is specified for + // a non- static object, the object and its subobjects, if + // any, have an indeterminate initial value); if the object + // or any of its subobjects are of const-qualified type, the + // program is ill-formed. + // C++0x [dcl.init]p11: + // If no initializer is specified for an object, the object is + // default-initialized; [...]. + InitializedEntity Entity = InitializedEntity::InitializeVariable(Var); + InitializationKind Kind + = InitializationKind::CreateDefault(Var->getLocation()); + + InitializationSequence InitSeq(*this, Entity, Kind, 0, 0); + ExprResult Init = InitSeq.Perform(*this, Entity, Kind, + MultiExprArg(*this, 0, 0)); + if (Init.isInvalid()) + Var->setInvalidDecl(); + else if (Init.get()) + Var->setInit(MaybeCreateExprWithCleanups(Init.get())); CheckCompleteVariableDeclaration(Var); } @@ -6056,7 +6155,7 @@ void Sema::CheckForFunctionRedefinition(FunctionDecl *FD) { // Don't complain if we're in GNU89 mode and the previous definition // was an extern inline function. const FunctionDecl *Definition; - if (FD->hasBody(Definition) && + if (FD->isDefined(Definition) && !canRedefineFunction(Definition, getLangOptions())) { if (getLangOptions().GNUMode && Definition->isInlineSpecified() && Definition->getStorageClass() == SC_Extern) @@ -6221,6 +6320,11 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, WP.disableCheckFallThrough(); } + // MSVC permits the use of pure specifier (=0) on function definition, + // defined at class scope, warn about this non standard construct. + if (getLangOptions().Microsoft && FD->isPure()) + Diag(FD->getLocation(), diag::warn_pure_function_definition); + if (!FD->isInvalidDecl()) { DiagnoseUnusedParameters(FD->param_begin(), FD->param_end()); DiagnoseSizeOfParametersAndReturnValue(FD->param_begin(), FD->param_end(), @@ -6499,7 +6603,7 @@ TypedefDecl *Sema::ParseTypedefDecl(Scope *S, Declarator &D, QualType T, /// /// \returns true if the new tag kind is acceptable, false otherwise. bool Sema::isAcceptableTagRedeclaration(const TagDecl *Previous, - TagTypeKind NewTag, + TagTypeKind NewTag, bool isDefinition, SourceLocation NewTagLoc, const IdentifierInfo &Name) { // C++ [dcl.type.elab]p3: @@ -6516,8 +6620,9 @@ bool Sema::isAcceptableTagRedeclaration(const TagDecl *Previous, // struct class-key shall be used to refer to a class (clause 9) // declared using the class or struct class-key. TagTypeKind OldTag = Previous->getTagKind(); - if (OldTag == NewTag) - return true; + if (!isDefinition || (NewTag != TTK_Class && NewTag != TTK_Struct)) + if (OldTag == NewTag) + return true; if ((OldTag == TTK_Struct || OldTag == TTK_Class) && (NewTag == TTK_Struct || NewTag == TTK_Class)) { @@ -6526,12 +6631,63 @@ bool Sema::isAcceptableTagRedeclaration(const TagDecl *Previous, if (const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Previous)) isTemplate = Record->getDescribedClassTemplate(); + if (!ActiveTemplateInstantiations.empty()) { + // In a template instantiation, do not offer fix-its for tag mismatches + // since they usually mess up the template instead of fixing the problem. + Diag(NewTagLoc, diag::warn_struct_class_tag_mismatch) + << (NewTag == TTK_Class) << isTemplate << &Name; + return true; + } + + if (isDefinition) { + // On definitions, check previous tags and issue a fix-it for each + // one that doesn't match the current tag. + if (Previous->getDefinition()) { + // Don't suggest fix-its for redefinitions. + return true; + } + + bool previousMismatch = false; + for (TagDecl::redecl_iterator I(Previous->redecls_begin()), + E(Previous->redecls_end()); I != E; ++I) { + if (I->getTagKind() != NewTag) { + if (!previousMismatch) { + previousMismatch = true; + Diag(NewTagLoc, diag::warn_struct_class_previous_tag_mismatch) + << (NewTag == TTK_Class) << isTemplate << &Name; + } + Diag(I->getInnerLocStart(), diag::note_struct_class_suggestion) + << (NewTag == TTK_Class) + << FixItHint::CreateReplacement(I->getInnerLocStart(), + NewTag == TTK_Class? + "class" : "struct"); + } + } + return true; + } + + // Check for a previous definition. If current tag and definition + // are same type, do nothing. If no definition, but disagree with + // with previous tag type, give a warning, but no fix-it. + const TagDecl *Redecl = Previous->getDefinition() ? + Previous->getDefinition() : Previous; + if (Redecl->getTagKind() == NewTag) { + return true; + } + Diag(NewTagLoc, diag::warn_struct_class_tag_mismatch) << (NewTag == TTK_Class) - << isTemplate << &Name - << FixItHint::CreateReplacement(SourceRange(NewTagLoc), - OldTag == TTK_Class? "class" : "struct"); - Diag(Previous->getLocation(), diag::note_previous_use); + << isTemplate << &Name; + Diag(Redecl->getLocation(), diag::note_previous_use); + + // If there is a previous defintion, suggest a fix-it. + if (Previous->getDefinition()) { + Diag(NewTagLoc, diag::note_struct_class_suggestion) + << (Redecl->getTagKind() == TTK_Class) + << FixItHint::CreateReplacement(SourceRange(NewTagLoc), + Redecl->getTagKind() == TTK_Class? "class" : "struct"); + } + return true; } return false; @@ -6567,7 +6723,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, if (TemplateParameterLists.size() > 0 || (SS.isNotEmpty() && TUK != TUK_Reference)) { if (TemplateParameterList *TemplateParams - = MatchTemplateParametersToScopeSpecifier(KWLoc, SS, + = MatchTemplateParametersToScopeSpecifier(KWLoc, NameLoc, SS, TemplateParameterLists.get(), TemplateParameterLists.size(), TUK == TUK_Friend, @@ -6705,6 +6861,17 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, // shouldn't be diagnosing. LookupName(Previous, S); + if (Previous.isAmbiguous() && + (TUK == TUK_Definition || TUK == TUK_Declaration)) { + LookupResult::Filter F = Previous.makeFilter(); + while (F.hasNext()) { + NamedDecl *ND = F.next(); + if (ND->getDeclContext()->getRedeclContext() != SearchDC) + F.erase(); + } + F.done(); + } + // Note: there used to be some attempt at recovery here. if (Previous.isAmbiguous()) return 0; @@ -6846,7 +7013,9 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, isDeclInScope(PrevDecl, SearchDC, S, isExplicitSpecialization)) { // Make sure that this wasn't declared as an enum and now used as a // struct or something similar. - if (!isAcceptableTagRedeclaration(PrevTagDecl, Kind, KWLoc, *Name)) { + if (!isAcceptableTagRedeclaration(PrevTagDecl, Kind, + TUK == TUK_Definition, KWLoc, + *Name)) { bool SafeToContinue = (PrevTagDecl->getTagKind() != TTK_Enum && Kind != TTK_Enum); @@ -6911,8 +7080,8 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, // for the consumer of this Decl to know it doesn't own it. // For our current ASTs this shouldn't be a problem, but will // need to be changed with DeclGroups. - if ((TUK == TUK_Reference && !PrevTagDecl->getFriendObjectKind()) || - TUK == TUK_Friend) + if ((TUK == TUK_Reference && (!PrevTagDecl->getFriendObjectKind() || + getLangOptions().Microsoft)) || TUK == TUK_Friend) return PrevTagDecl; // Diagnose attempts to redefine a tag. @@ -7154,8 +7323,12 @@ CreateNewDecl: New->setLexicalDeclContext(CurContext); // Mark this as a friend decl if applicable. + // In Microsoft mode, a friend declaration also acts as a forward + // declaration so we always pass true to setObjectOfFriendDecl to make + // the tag name visible. if (TUK == TUK_Friend) - New->setObjectOfFriendDecl(/* PreviouslyDeclared = */ !Previous.empty()); + New->setObjectOfFriendDecl(/* PreviouslyDeclared = */ !Previous.empty() || + getLangOptions().Microsoft); // Set the access specifier. if (!Invalid && SearchDC->isRecord()) @@ -7341,14 +7514,13 @@ bool Sema::VerifyBitField(SourceLocation FieldLoc, IdentifierInfo *FieldName, return false; } -/// ActOnField - Each field of a struct/union/class is passed into this in order +/// ActOnField - Each field of a C struct/union is passed into this in order /// to create a FieldDecl object for it. -Decl *Sema::ActOnField(Scope *S, Decl *TagD, - SourceLocation DeclStart, - Declarator &D, ExprTy *BitfieldWidth) { +Decl *Sema::ActOnField(Scope *S, Decl *TagD, SourceLocation DeclStart, + Declarator &D, ExprTy *BitfieldWidth) { FieldDecl *Res = HandleField(S, cast_or_null<RecordDecl>(TagD), DeclStart, D, static_cast<Expr*>(BitfieldWidth), - AS_public); + /*HasInit=*/false, AS_public); return Res; } @@ -7356,7 +7528,7 @@ Decl *Sema::ActOnField(Scope *S, Decl *TagD, /// FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record, SourceLocation DeclStart, - Declarator &D, Expr *BitWidth, + Declarator &D, Expr *BitWidth, bool HasInit, AccessSpecifier AS) { IdentifierInfo *II = D.getIdentifier(); SourceLocation Loc = DeclStart; @@ -7405,8 +7577,8 @@ FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record, = (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_mutable); SourceLocation TSSL = D.getSourceRange().getBegin(); FieldDecl *NewFD - = CheckFieldDecl(II, T, TInfo, Record, Loc, Mutable, BitWidth, TSSL, - AS, PrevDecl, &D); + = CheckFieldDecl(II, T, TInfo, Record, Loc, Mutable, BitWidth, HasInit, + TSSL, AS, PrevDecl, &D); if (NewFD->isInvalidDecl()) Record->setInvalidDecl(); @@ -7435,7 +7607,7 @@ FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record, FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T, TypeSourceInfo *TInfo, RecordDecl *Record, SourceLocation Loc, - bool Mutable, Expr *BitWidth, + bool Mutable, Expr *BitWidth, bool HasInit, SourceLocation TSSL, AccessSpecifier AS, NamedDecl *PrevDecl, Declarator *D) { @@ -7515,7 +7687,7 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T, } FieldDecl *NewFD = FieldDecl::Create(Context, Record, TSSL, Loc, II, T, TInfo, - BitWidth, Mutable); + BitWidth, Mutable, HasInit); if (InvalidDecl) NewFD->setInvalidDecl(); @@ -7535,8 +7707,7 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T, // destructor, or a non-trivial copy assignment operator // cannot be a member of a union, nor can an array of such // objects. - // TODO: C++0x alters this restriction significantly. - if (CheckNontrivialField(NewFD)) + if (!getLangOptions().CPlusPlus0x && CheckNontrivialField(NewFD)) NewFD->setInvalidDecl(); } } @@ -7582,8 +7753,8 @@ bool Sema::CheckNontrivialField(FieldDecl *FD) { CXXSpecialMember member = CXXInvalid; if (!RDecl->hasTrivialCopyConstructor()) member = CXXCopyConstructor; - else if (!RDecl->hasTrivialConstructor()) - member = CXXConstructor; + else if (!RDecl->hasTrivialDefaultConstructor()) + member = CXXDefaultConstructor; else if (!RDecl->hasTrivialCopyAssignment()) member = CXXCopyAssignment; else if (!RDecl->hasTrivialDestructor()) @@ -7612,7 +7783,7 @@ void Sema::DiagnoseNontrivial(const RecordType* T, CXXSpecialMember member) { case CXXInvalid: break; - case CXXConstructor: + case CXXDefaultConstructor: if (RD->hasUserDeclaredConstructor()) { typedef CXXRecordDecl::ctor_iterator ctor_iter; for (ctor_iter ci = RD->ctor_begin(), ce = RD->ctor_end(); ci != ce;++ci){ @@ -7633,7 +7804,15 @@ void Sema::DiagnoseNontrivial(const RecordType* T, CXXSpecialMember member) { case CXXCopyConstructor: if (RD->hasUserDeclaredCopyConstructor()) { SourceLocation CtorLoc = - RD->getCopyConstructor(Context, 0)->getLocation(); + RD->getCopyConstructor(0)->getLocation(); + Diag(CtorLoc, diag::note_nontrivial_user_defined) << QT << member; + return; + } + break; + + case CXXMoveConstructor: + if (RD->hasUserDeclaredMoveConstructor()) { + SourceLocation CtorLoc = RD->getMoveConstructor()->getLocation(); Diag(CtorLoc, diag::note_nontrivial_user_defined) << QT << member; return; } @@ -7649,6 +7828,14 @@ void Sema::DiagnoseNontrivial(const RecordType* T, CXXSpecialMember member) { } break; + case CXXMoveAssignment: + if (RD->hasUserDeclaredMoveAssignment()) { + SourceLocation AssignLoc = RD->getMoveAssignmentOperator()->getLocation(); + Diag(AssignLoc, diag::note_nontrivial_user_defined) << QT << member; + return; + } + break; + case CXXDestructor: if (RD->hasUserDeclaredDestructor()) { SourceLocation DtorLoc = LookupDestructor(RD)->getLocation(); @@ -7686,8 +7873,8 @@ void Sema::DiagnoseNontrivial(const RecordType* T, CXXSpecialMember member) { bool (CXXRecordDecl::*hasTrivial)() const; switch (member) { - case CXXConstructor: - hasTrivial = &CXXRecordDecl::hasTrivialConstructor; break; + case CXXDefaultConstructor: + hasTrivial = &CXXRecordDecl::hasTrivialDefaultConstructor; break; case CXXCopyConstructor: hasTrivial = &CXXRecordDecl::hasTrivialCopyConstructor; break; case CXXCopyAssignment: @@ -8047,6 +8234,11 @@ void Sema::ActOnFields(Scope* S, Convs->setAccess(I, (*I)->getAccess()); if (!CXXRecord->isDependentType()) { + // Adjust user-defined destructor exception spec. + if (getLangOptions().CPlusPlus0x && + CXXRecord->hasUserDeclaredDestructor()) + AdjustDestructorExceptionSpec(CXXRecord,CXXRecord->getDestructor()); + // Add any implicitly-declared members to this class. AddImplicitlyDeclaredMembersToClass(CXXRecord); @@ -8095,6 +8287,22 @@ void Sema::ActOnFields(Scope* S, if (!Completed) Record->completeDefinition(); + + // Now that the record is complete, do any delayed exception spec checks + // we were missing. + while (!DelayedDestructorExceptionSpecChecks.empty()) { + const CXXDestructorDecl *Dtor = + DelayedDestructorExceptionSpecChecks.back().first; + if (Dtor->getParent() != Record) + break; + + assert(!Dtor->getParent()->isDependentType() && + "Should not ever add destructors of templates into the list."); + CheckOverridingFunctionExceptionSpec(Dtor, + DelayedDestructorExceptionSpecChecks.back().second); + DelayedDestructorExceptionSpecChecks.pop_back(); + } + } else { ObjCIvarDecl **ClsFields = reinterpret_cast<ObjCIvarDecl**>(RecFields.data()); @@ -8149,7 +8357,7 @@ static bool isRepresentableIntegerValue(ASTContext &Context, unsigned BitWidth = Context.getIntWidth(T); if (Value.isUnsigned() || Value.isNonNegative()) { - if (T->isSignedIntegerType()) + if (T->isSignedIntegerOrEnumerationType()) --BitWidth; return Value.getActiveBits() <= BitWidth; } @@ -8172,8 +8380,8 @@ static QualType getNextLargerIntegralType(ASTContext &Context, QualType T) { }; unsigned BitWidth = Context.getTypeSize(T); - QualType *Types = T->isSignedIntegerType()? SignedIntegralTypes - : UnsignedIntegralTypes; + QualType *Types = T->isSignedIntegerOrEnumerationType()? SignedIntegralTypes + : UnsignedIntegralTypes; for (unsigned I = 0; I != NumTypes; ++I) if (Context.getTypeSize(Types[I]) > BitWidth) return Types[I]; @@ -8307,7 +8515,7 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum, // type that is supposed to be large enough to represent the incremented // value, then increment. EnumVal = LastEnumConst->getInitVal(); - EnumVal.setIsSigned(EltTy->isSignedIntegerType()); + EnumVal.setIsSigned(EltTy->isSignedIntegerOrEnumerationType()); EnumVal = EnumVal.zextOrTrunc(Context.getIntWidth(EltTy)); ++EnumVal; @@ -8331,7 +8539,7 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum, // Make the enumerator value match the signedness and size of the // enumerator's type. EnumVal = EnumVal.zextOrTrunc(Context.getIntWidth(EltTy)); - EnumVal.setIsSigned(EltTy->isSignedIntegerType()); + EnumVal.setIsSigned(EltTy->isSignedIntegerOrEnumerationType()); } return EnumConstantDecl::Create(Context, Enum, IdLoc, Id, EltTy, @@ -8589,7 +8797,7 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, } else { NewTy = BestType; NewWidth = BestWidth; - NewSign = BestType->isSignedIntegerType(); + NewSign = BestType->isSignedIntegerOrEnumerationType(); } // Adjust the APSInt value. diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaDeclCXX.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaDeclCXX.cpp index 27632a1..ce99efb 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaDeclCXX.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaDeclCXX.cpp @@ -111,6 +111,102 @@ namespace { } } +void Sema::ImplicitExceptionSpecification::CalledDecl(CXXMethodDecl *Method) { + assert(Context && "ImplicitExceptionSpecification without an ASTContext"); + // If we have an MSAny or unknown spec already, don't bother. + if (!Method || ComputedEST == EST_MSAny || ComputedEST == EST_Delayed) + return; + + const FunctionProtoType *Proto + = Method->getType()->getAs<FunctionProtoType>(); + + ExceptionSpecificationType EST = Proto->getExceptionSpecType(); + + // If this function can throw any exceptions, make a note of that. + if (EST == EST_Delayed || EST == EST_MSAny || EST == EST_None) { + ClearExceptions(); + ComputedEST = EST; + return; + } + + // FIXME: If the call to this decl is using any of its default arguments, we + // need to search them for potentially-throwing calls. + + // If this function has a basic noexcept, it doesn't affect the outcome. + if (EST == EST_BasicNoexcept) + return; + + // If we have a throw-all spec at this point, ignore the function. + if (ComputedEST == EST_None) + return; + + // If we're still at noexcept(true) and there's a nothrow() callee, + // change to that specification. + if (EST == EST_DynamicNone) { + if (ComputedEST == EST_BasicNoexcept) + ComputedEST = EST_DynamicNone; + return; + } + + // Check out noexcept specs. + if (EST == EST_ComputedNoexcept) { + FunctionProtoType::NoexceptResult NR = Proto->getNoexceptSpec(*Context); + assert(NR != FunctionProtoType::NR_NoNoexcept && + "Must have noexcept result for EST_ComputedNoexcept."); + assert(NR != FunctionProtoType::NR_Dependent && + "Should not generate implicit declarations for dependent cases, " + "and don't know how to handle them anyway."); + + // noexcept(false) -> no spec on the new function + if (NR == FunctionProtoType::NR_Throw) { + ClearExceptions(); + ComputedEST = EST_None; + } + // noexcept(true) won't change anything either. + return; + } + + assert(EST == EST_Dynamic && "EST case not considered earlier."); + assert(ComputedEST != EST_None && + "Shouldn't collect exceptions when throw-all is guaranteed."); + ComputedEST = EST_Dynamic; + // Record the exceptions in this function's exception specification. + for (FunctionProtoType::exception_iterator E = Proto->exception_begin(), + EEnd = Proto->exception_end(); + E != EEnd; ++E) + if (ExceptionsSeen.insert(Context->getCanonicalType(*E))) + Exceptions.push_back(*E); +} + +void Sema::ImplicitExceptionSpecification::CalledExpr(Expr *E) { + if (!E || ComputedEST == EST_MSAny || ComputedEST == EST_Delayed) + return; + + // FIXME: + // + // C++0x [except.spec]p14: + // [An] implicit exception-specification specifies the type-id T if and + // only if T is allowed by the exception-specification of a function directly + // invoked by f’s implicit definition; f shall allow all exceptions if any + // function it directly invokes allows all exceptions, and f shall allow no + // exceptions if every function it directly invokes allows no exceptions. + // + // Note in particular that if an implicit exception-specification is generated + // for a function containing a throw-expression, that specification can still + // be noexcept(true). + // + // Note also that 'directly invoked' is not defined in the standard, and there + // is no indication that we should only consider potentially-evaluated calls. + // + // Ultimately we should implement the intent of the standard: the exception + // specification should be the set of exceptions which can be thrown by the + // implicit definition. For now, we assume that any non-nothrow expression can + // throw any exception. + + if (E->CanThrow(*Context)) + ComputedEST = EST_None; +} + bool Sema::SetParamDefaultArgument(ParmVarDecl *Param, Expr *Arg, SourceLocation EqualLoc) { @@ -393,6 +489,15 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old) { diag::err_param_default_argument_member_template_redecl) << WhichKind << NewParam->getDefaultArgRange(); + } else if (CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(New)) { + CXXSpecialMember NewSM = getSpecialMember(Ctor), + OldSM = getSpecialMember(cast<CXXConstructorDecl>(Old)); + if (NewSM != OldSM) { + Diag(NewParam->getLocation(),diag::warn_default_arg_makes_ctor_special) + << NewParam->getDefaultArgRange() << NewSM; + Diag(Old->getLocation(), diag::note_previous_declaration_special) + << OldSM; + } } } } @@ -956,14 +1061,15 @@ bool Sema::CheckIfOverriddenFunctionIsMarkedFinal(const CXXMethodDecl *New, /// ActOnCXXMemberDeclarator - This is invoked when a C++ class member /// declarator is parsed. 'AS' is the access specifier, 'BW' specifies the -/// bitfield width if there is one and 'InitExpr' specifies the initializer if -/// any. +/// bitfield width if there is one, 'InitExpr' specifies the initializer if +/// one has been parsed, and 'HasDeferredInit' is true if an initializer is +/// present but parsing it has been deferred. Decl * Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, MultiTemplateParamsArg TemplateParameterLists, ExprTy *BW, const VirtSpecifiers &VS, - ExprTy *InitExpr, bool IsDefinition, - bool Deleted) { + ExprTy *InitExpr, bool HasDeferredInit, + bool IsDefinition) { const DeclSpec &DS = D.getDeclSpec(); DeclarationNameInfo NameInfo = GetNameForDeclarator(D); DeclarationName Name = NameInfo.getName(); @@ -978,6 +1084,7 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, assert(isa<CXXRecordDecl>(CurContext)); assert(!DS.isFriendSpecified()); + assert(!Init || !HasDeferredInit); bool isFunc = false; if (D.isFunctionDeclarator()) @@ -1028,7 +1135,6 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, if (isInstField) { CXXScopeSpec &SS = D.getCXXScopeSpec(); - if (SS.isSet() && !SS.isInvalid()) { // The user provided a superfluous scope specifier inside a class // definition: @@ -1050,9 +1156,11 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, // FIXME: Check for template parameters! // FIXME: Check that the name is an identifier! Member = HandleField(S, cast<CXXRecordDecl>(CurContext), Loc, D, BitWidth, - AS); + HasDeferredInit, AS); assert(Member && "HandleField never returns null"); } else { + assert(!HasDeferredInit); + Member = HandleDeclarator(S, D, move(TemplateParameterLists), IsDefinition); if (!Member) { return 0; @@ -1123,8 +1231,14 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, if (Init) AddInitializerToDecl(Member, Init, false, DS.getTypeSpecType() == DeclSpec::TST_auto); - if (Deleted) // FIXME: Source location is not very good. - SetDeclDeleted(Member, D.getSourceRange().getBegin()); + else if (DS.getTypeSpecType() == DeclSpec::TST_auto && + DS.getStorageClassSpec() == DeclSpec::SCS_static) { + // C++0x [dcl.spec.auto]p4: 'auto' can only be used in the type of a static + // data member if a brace-or-equal-initializer is provided. + Diag(Loc, diag::err_auto_var_requires_init) + << Name << cast<ValueDecl>(Member)->getType(); + Member->setInvalidDecl(); + } FinalizeDeclaration(Member); @@ -1133,6 +1247,47 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, return Member; } +/// ActOnCXXInClassMemberInitializer - This is invoked after parsing an +/// in-class initializer for a non-static C++ class member. Such parsing +/// is deferred until the class is complete. +void +Sema::ActOnCXXInClassMemberInitializer(Decl *D, SourceLocation EqualLoc, + Expr *InitExpr) { + FieldDecl *FD = cast<FieldDecl>(D); + + if (!InitExpr) { + FD->setInvalidDecl(); + FD->removeInClassInitializer(); + return; + } + + ExprResult Init = InitExpr; + if (!FD->getType()->isDependentType() && !InitExpr->isTypeDependent()) { + // FIXME: if there is no EqualLoc, this is list-initialization. + Init = PerformCopyInitialization( + InitializedEntity::InitializeMember(FD), EqualLoc, InitExpr); + if (Init.isInvalid()) { + FD->setInvalidDecl(); + return; + } + + CheckImplicitConversions(Init.get(), EqualLoc); + } + + // C++0x [class.base.init]p7: + // The initialization of each base and member constitutes a + // full-expression. + Init = MaybeCreateExprWithCleanups(Init); + if (Init.isInvalid()) { + FD->setInvalidDecl(); + return; + } + + InitExpr = Init.release(); + + FD->setInClassInitializer(InitExpr); +} + /// \brief Find the direct and/or virtual base specifiers that /// correspond to the given base type, for use in base initialization /// within a constructor. @@ -1547,7 +1702,8 @@ Sema::BuildDelegatingInitializer(TypeSourceInfo *TInfo, return true; CXXConstructExpr *ConExpr = cast<CXXConstructExpr>(DelegationInit.get()); - CXXConstructorDecl *Constructor = ConExpr->getConstructor(); + CXXConstructorDecl *Constructor + = ConExpr->getConstructor(); assert(Constructor && "Delegating constructor with no target?"); CheckImplicitConversions(DelegationInit.get(), LParenLoc); @@ -1956,24 +2112,26 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor, return false; } - if (FieldBaseElementType->isReferenceType()) { - SemaRef.Diag(Constructor->getLocation(), - diag::err_uninitialized_member_in_ctor) - << (int)Constructor->isImplicit() - << SemaRef.Context.getTagDeclType(Constructor->getParent()) - << 0 << Field->getDeclName(); - SemaRef.Diag(Field->getLocation(), diag::note_declared_at); - return true; - } + if (!Field->getParent()->isUnion()) { + if (FieldBaseElementType->isReferenceType()) { + SemaRef.Diag(Constructor->getLocation(), + diag::err_uninitialized_member_in_ctor) + << (int)Constructor->isImplicit() + << SemaRef.Context.getTagDeclType(Constructor->getParent()) + << 0 << Field->getDeclName(); + SemaRef.Diag(Field->getLocation(), diag::note_declared_at); + return true; + } - if (FieldBaseElementType.isConstQualified()) { - SemaRef.Diag(Constructor->getLocation(), - diag::err_uninitialized_member_in_ctor) - << (int)Constructor->isImplicit() - << SemaRef.Context.getTagDeclType(Constructor->getParent()) - << 1 << Field->getDeclName(); - SemaRef.Diag(Field->getLocation(), diag::note_declared_at); - return true; + if (FieldBaseElementType.isConstQualified()) { + SemaRef.Diag(Constructor->getLocation(), + diag::err_uninitialized_member_in_ctor) + << (int)Constructor->isImplicit() + << SemaRef.Context.getTagDeclType(Constructor->getParent()) + << 1 << Field->getDeclName(); + SemaRef.Diag(Field->getLocation(), diag::note_declared_at); + return true; + } } // Nothing to initialize. @@ -2001,7 +2159,7 @@ struct BaseAndFieldInfo { }; } -static bool CollectFieldInitializer(BaseAndFieldInfo &Info, +static bool CollectFieldInitializer(Sema &SemaRef, BaseAndFieldInfo &Info, FieldDecl *Top, FieldDecl *Field) { // Overwhelmingly common case: we have a direct initializer for this field. @@ -2010,6 +2168,18 @@ static bool CollectFieldInitializer(BaseAndFieldInfo &Info, return false; } + // C++0x [class.base.init]p8: if the entity is a non-static data member that + // has a brace-or-equal-initializer, the entity is initialized as specified + // in [dcl.init]. + if (Field->hasInClassInitializer()) { + Info.AllToInit.push_back( + new (SemaRef.Context) CXXCtorInitializer(SemaRef.Context, Field, + SourceLocation(), + SourceLocation(), 0, + SourceLocation())); + return false; + } + if (Info.IIK == IIK_Default && Field->isAnonymousStructOrUnion()) { const RecordType *FieldClassType = Field->getType()->getAs<RecordType>(); assert(FieldClassType && "anonymous struct/union without record type"); @@ -2032,7 +2202,7 @@ static bool CollectFieldInitializer(BaseAndFieldInfo &Info, // field in the class is also initialized, so exit immediately. return false; } else if ((*FA)->isAnonymousStructOrUnion()) { - if (CollectFieldInitializer(Info, Top, *FA)) + if (CollectFieldInitializer(SemaRef, Info, Top, *FA)) return true; } } @@ -2047,7 +2217,7 @@ static bool CollectFieldInitializer(BaseAndFieldInfo &Info, // necessary. for (RecordDecl::field_iterator FA = FieldClassDecl->field_begin(), EA = FieldClassDecl->field_end(); FA != EA; FA++) { - if (CollectFieldInitializer(Info, Top, *FA)) + if (CollectFieldInitializer(SemaRef, Info, Top, *FA)) return true; } } @@ -2056,7 +2226,7 @@ static bool CollectFieldInitializer(BaseAndFieldInfo &Info, // Don't try to build an implicit initializer if there were semantic // errors in any of the initializers (and therefore we might be // missing some that the user actually wrote). - if (Info.AnyErrorsInInits) + if (Info.AnyErrorsInInits || Field->isInvalidDecl()) return false; CXXCtorInitializer *Init = 0; @@ -2072,26 +2242,22 @@ static bool CollectFieldInitializer(BaseAndFieldInfo &Info, bool Sema::SetDelegatingInitializer(CXXConstructorDecl *Constructor, CXXCtorInitializer *Initializer) { + assert(Initializer->isDelegatingInitializer()); Constructor->setNumCtorInitializers(1); CXXCtorInitializer **initializer = new (Context) CXXCtorInitializer*[1]; memcpy(initializer, &Initializer, sizeof (CXXCtorInitializer*)); Constructor->setCtorInitializers(initializer); - // FIXME: This doesn't catch indirect loops yet - CXXConstructorDecl *Target = Initializer->getTargetConstructor(); - while (Target) { - if (Target == Constructor) { - Diag(Initializer->getSourceLocation(), diag::err_delegating_ctor_loop) - << Constructor; - return true; - } - Target = Target->getTargetConstructor(); + if (CXXDestructorDecl *Dtor = LookupDestructor(Constructor->getParent())) { + MarkDeclarationReferenced(Initializer->getSourceLocation(), Dtor); + DiagnoseUseOfDecl(Dtor, Initializer->getSourceLocation()); } + DelegatingCtorDecls.push_back(Constructor); + return false; } - bool Sema::SetCtorInitializers(CXXConstructorDecl *Constructor, @@ -2192,7 +2358,7 @@ Sema::SetCtorInitializers(CXXConstructorDecl *Constructor, "Incomplete array type is not valid"); continue; } - if (CollectFieldInitializer(Info, *Field, *Field)) + if (CollectFieldInitializer(*this, Info, *Field, *Field)) HadError = true; } @@ -2468,7 +2634,7 @@ void Sema::ActOnMemInitializers(Decl *ConstructorDecl, HadError = true; // We will treat this as being the only initializer. } - SetDelegatingInitializer(Constructor, *MemInits); + SetDelegatingInitializer(Constructor, MemInits[i]); // Return immediately as the initializer is set. return; } @@ -2805,7 +2971,7 @@ static void CheckAbstractClassUsage(AbstractUsageInfo &Info, CXXMethodDecl *MD) { // No need to do the check on definitions, which require that // the return/param types be complete. - if (MD->isThisDeclarationADefinition()) + if (MD->doesThisDeclarationHaveABody()) return; // For safety's sake, just ignore it if we don't have type source @@ -2871,6 +3037,9 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) { for (RecordDecl::field_iterator F = Record->field_begin(), FEnd = Record->field_end(); F != FEnd; ++F) { + if (F->hasInClassInitializer()) + continue; + if (F->getType()->isReferenceType() || (F->getType().isConstQualified() && F->getType()->isScalarType())) { if (!Complained) { @@ -2937,6 +3106,953 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) { // instantiated (e.g. meta-functions). This doesn't apply to classes that // have inherited constructors. DeclareInheritedConstructors(Record); + + if (!Record->isDependentType()) + CheckExplicitlyDefaultedMethods(Record); +} + +void Sema::CheckExplicitlyDefaultedMethods(CXXRecordDecl *Record) { + for (CXXRecordDecl::method_iterator MI = Record->method_begin(), + ME = Record->method_end(); + MI != ME; ++MI) { + if (!MI->isInvalidDecl() && MI->isExplicitlyDefaulted()) { + switch (getSpecialMember(*MI)) { + case CXXDefaultConstructor: + CheckExplicitlyDefaultedDefaultConstructor( + cast<CXXConstructorDecl>(*MI)); + break; + + case CXXDestructor: + CheckExplicitlyDefaultedDestructor(cast<CXXDestructorDecl>(*MI)); + break; + + case CXXCopyConstructor: + CheckExplicitlyDefaultedCopyConstructor(cast<CXXConstructorDecl>(*MI)); + break; + + case CXXCopyAssignment: + CheckExplicitlyDefaultedCopyAssignment(*MI); + break; + + case CXXMoveConstructor: + case CXXMoveAssignment: + Diag(MI->getLocation(), diag::err_defaulted_move_unsupported); + break; + + default: + // FIXME: Do moves once they exist + llvm_unreachable("non-special member explicitly defaulted!"); + } + } + } + +} + +void Sema::CheckExplicitlyDefaultedDefaultConstructor(CXXConstructorDecl *CD) { + assert(CD->isExplicitlyDefaulted() && CD->isDefaultConstructor()); + + // Whether this was the first-declared instance of the constructor. + // This affects whether we implicitly add an exception spec (and, eventually, + // constexpr). It is also ill-formed to explicitly default a constructor such + // that it would be deleted. (C++0x [decl.fct.def.default]) + bool First = CD == CD->getCanonicalDecl(); + + bool HadError = false; + if (CD->getNumParams() != 0) { + Diag(CD->getLocation(), diag::err_defaulted_default_ctor_params) + << CD->getSourceRange(); + HadError = true; + } + + ImplicitExceptionSpecification Spec + = ComputeDefaultedDefaultCtorExceptionSpec(CD->getParent()); + FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI(); + if (EPI.ExceptionSpecType == EST_Delayed) { + // Exception specification depends on some deferred part of the class. We'll + // try again when the class's definition has been fully processed. + return; + } + const FunctionProtoType *CtorType = CD->getType()->getAs<FunctionProtoType>(), + *ExceptionType = Context.getFunctionType( + Context.VoidTy, 0, 0, EPI)->getAs<FunctionProtoType>(); + + if (CtorType->hasExceptionSpec()) { + if (CheckEquivalentExceptionSpec( + PDiag(diag::err_incorrect_defaulted_exception_spec) + << CXXDefaultConstructor, + PDiag(), + ExceptionType, SourceLocation(), + CtorType, CD->getLocation())) { + HadError = true; + } + } else if (First) { + // We set the declaration to have the computed exception spec here. + // We know there are no parameters. + EPI.ExtInfo = CtorType->getExtInfo(); + CD->setType(Context.getFunctionType(Context.VoidTy, 0, 0, EPI)); + } + + if (HadError) { + CD->setInvalidDecl(); + return; + } + + if (ShouldDeleteDefaultConstructor(CD)) { + if (First) { + CD->setDeletedAsWritten(); + } else { + Diag(CD->getLocation(), diag::err_out_of_line_default_deletes) + << CXXDefaultConstructor; + CD->setInvalidDecl(); + } + } +} + +void Sema::CheckExplicitlyDefaultedCopyConstructor(CXXConstructorDecl *CD) { + assert(CD->isExplicitlyDefaulted() && CD->isCopyConstructor()); + + // Whether this was the first-declared instance of the constructor. + bool First = CD == CD->getCanonicalDecl(); + + bool HadError = false; + if (CD->getNumParams() != 1) { + Diag(CD->getLocation(), diag::err_defaulted_copy_ctor_params) + << CD->getSourceRange(); + HadError = true; + } + + ImplicitExceptionSpecification Spec(Context); + bool Const; + llvm::tie(Spec, Const) = + ComputeDefaultedCopyCtorExceptionSpecAndConst(CD->getParent()); + + FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI(); + const FunctionProtoType *CtorType = CD->getType()->getAs<FunctionProtoType>(), + *ExceptionType = Context.getFunctionType( + Context.VoidTy, 0, 0, EPI)->getAs<FunctionProtoType>(); + + // Check for parameter type matching. + // This is a copy ctor so we know it's a cv-qualified reference to T. + QualType ArgType = CtorType->getArgType(0); + if (ArgType->getPointeeType().isVolatileQualified()) { + Diag(CD->getLocation(), diag::err_defaulted_copy_ctor_volatile_param); + HadError = true; + } + if (ArgType->getPointeeType().isConstQualified() && !Const) { + Diag(CD->getLocation(), diag::err_defaulted_copy_ctor_const_param); + HadError = true; + } + + if (CtorType->hasExceptionSpec()) { + if (CheckEquivalentExceptionSpec( + PDiag(diag::err_incorrect_defaulted_exception_spec) + << CXXCopyConstructor, + PDiag(), + ExceptionType, SourceLocation(), + CtorType, CD->getLocation())) { + HadError = true; + } + } else if (First) { + // We set the declaration to have the computed exception spec here. + // We duplicate the one parameter type. + EPI.ExtInfo = CtorType->getExtInfo(); + CD->setType(Context.getFunctionType(Context.VoidTy, &ArgType, 1, EPI)); + } + + if (HadError) { + CD->setInvalidDecl(); + return; + } + + if (ShouldDeleteCopyConstructor(CD)) { + if (First) { + CD->setDeletedAsWritten(); + } else { + Diag(CD->getLocation(), diag::err_out_of_line_default_deletes) + << CXXCopyConstructor; + CD->setInvalidDecl(); + } + } +} + +void Sema::CheckExplicitlyDefaultedCopyAssignment(CXXMethodDecl *MD) { + assert(MD->isExplicitlyDefaulted()); + + // Whether this was the first-declared instance of the operator + bool First = MD == MD->getCanonicalDecl(); + + bool HadError = false; + if (MD->getNumParams() != 1) { + Diag(MD->getLocation(), diag::err_defaulted_copy_assign_params) + << MD->getSourceRange(); + HadError = true; + } + + QualType ReturnType = + MD->getType()->getAs<FunctionType>()->getResultType(); + if (!ReturnType->isLValueReferenceType() || + !Context.hasSameType( + Context.getCanonicalType(ReturnType->getPointeeType()), + Context.getCanonicalType(Context.getTypeDeclType(MD->getParent())))) { + Diag(MD->getLocation(), diag::err_defaulted_copy_assign_return_type); + HadError = true; + } + + ImplicitExceptionSpecification Spec(Context); + bool Const; + llvm::tie(Spec, Const) = + ComputeDefaultedCopyCtorExceptionSpecAndConst(MD->getParent()); + + FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI(); + const FunctionProtoType *OperType = MD->getType()->getAs<FunctionProtoType>(), + *ExceptionType = Context.getFunctionType( + Context.VoidTy, 0, 0, EPI)->getAs<FunctionProtoType>(); + + QualType ArgType = OperType->getArgType(0); + if (!ArgType->isReferenceType()) { + Diag(MD->getLocation(), diag::err_defaulted_copy_assign_not_ref); + HadError = true; + } else { + if (ArgType->getPointeeType().isVolatileQualified()) { + Diag(MD->getLocation(), diag::err_defaulted_copy_assign_volatile_param); + HadError = true; + } + if (ArgType->getPointeeType().isConstQualified() && !Const) { + Diag(MD->getLocation(), diag::err_defaulted_copy_assign_const_param); + HadError = true; + } + } + + if (OperType->getTypeQuals()) { + Diag(MD->getLocation(), diag::err_defaulted_copy_assign_quals); + HadError = true; + } + + if (OperType->hasExceptionSpec()) { + if (CheckEquivalentExceptionSpec( + PDiag(diag::err_incorrect_defaulted_exception_spec) + << CXXCopyAssignment, + PDiag(), + ExceptionType, SourceLocation(), + OperType, MD->getLocation())) { + HadError = true; + } + } else if (First) { + // We set the declaration to have the computed exception spec here. + // We duplicate the one parameter type. + EPI.RefQualifier = OperType->getRefQualifier(); + EPI.ExtInfo = OperType->getExtInfo(); + MD->setType(Context.getFunctionType(ReturnType, &ArgType, 1, EPI)); + } + + if (HadError) { + MD->setInvalidDecl(); + return; + } + + if (ShouldDeleteCopyAssignmentOperator(MD)) { + if (First) { + MD->setDeletedAsWritten(); + } else { + Diag(MD->getLocation(), diag::err_out_of_line_default_deletes) + << CXXCopyAssignment; + MD->setInvalidDecl(); + } + } +} + +void Sema::CheckExplicitlyDefaultedDestructor(CXXDestructorDecl *DD) { + assert(DD->isExplicitlyDefaulted()); + + // Whether this was the first-declared instance of the destructor. + bool First = DD == DD->getCanonicalDecl(); + + ImplicitExceptionSpecification Spec + = ComputeDefaultedDtorExceptionSpec(DD->getParent()); + FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI(); + const FunctionProtoType *DtorType = DD->getType()->getAs<FunctionProtoType>(), + *ExceptionType = Context.getFunctionType( + Context.VoidTy, 0, 0, EPI)->getAs<FunctionProtoType>(); + + if (DtorType->hasExceptionSpec()) { + if (CheckEquivalentExceptionSpec( + PDiag(diag::err_incorrect_defaulted_exception_spec) + << CXXDestructor, + PDiag(), + ExceptionType, SourceLocation(), + DtorType, DD->getLocation())) { + DD->setInvalidDecl(); + return; + } + } else if (First) { + // We set the declaration to have the computed exception spec here. + // There are no parameters. + EPI.ExtInfo = DtorType->getExtInfo(); + DD->setType(Context.getFunctionType(Context.VoidTy, 0, 0, EPI)); + } + + if (ShouldDeleteDestructor(DD)) { + if (First) { + DD->setDeletedAsWritten(); + } else { + Diag(DD->getLocation(), diag::err_out_of_line_default_deletes) + << CXXDestructor; + DD->setInvalidDecl(); + } + } +} + +bool Sema::ShouldDeleteDefaultConstructor(CXXConstructorDecl *CD) { + CXXRecordDecl *RD = CD->getParent(); + assert(!RD->isDependentType() && "do deletion after instantiation"); + if (!LangOpts.CPlusPlus0x) + return false; + + SourceLocation Loc = CD->getLocation(); + + // Do access control from the constructor + ContextRAII CtorContext(*this, CD); + + bool Union = RD->isUnion(); + bool AllConst = true; + + // We do this because we should never actually use an anonymous + // union's constructor. + if (Union && RD->isAnonymousStructOrUnion()) + return false; + + // FIXME: We should put some diagnostic logic right into this function. + + // C++0x [class.ctor]/5 + // A defaulted default constructor for class X is defined as deleted if: + + for (CXXRecordDecl::base_class_iterator BI = RD->bases_begin(), + BE = RD->bases_end(); + BI != BE; ++BI) { + // We'll handle this one later + if (BI->isVirtual()) + continue; + + CXXRecordDecl *BaseDecl = BI->getType()->getAsCXXRecordDecl(); + assert(BaseDecl && "base isn't a CXXRecordDecl"); + + // -- any [direct base class] has a type with a destructor that is + // deleted or inaccessible from the defaulted default constructor + CXXDestructorDecl *BaseDtor = LookupDestructor(BaseDecl); + if (BaseDtor->isDeleted()) + return true; + if (CheckDestructorAccess(Loc, BaseDtor, PDiag()) != + AR_accessible) + return true; + + // -- any [direct base class either] has no default constructor or + // overload resolution as applied to [its] default constructor + // results in an ambiguity or in a function that is deleted or + // inaccessible from the defaulted default constructor + CXXConstructorDecl *BaseDefault = LookupDefaultConstructor(BaseDecl); + if (!BaseDefault || BaseDefault->isDeleted()) + return true; + + if (CheckConstructorAccess(Loc, BaseDefault, BaseDefault->getAccess(), + PDiag()) != AR_accessible) + return true; + } + + for (CXXRecordDecl::base_class_iterator BI = RD->vbases_begin(), + BE = RD->vbases_end(); + BI != BE; ++BI) { + CXXRecordDecl *BaseDecl = BI->getType()->getAsCXXRecordDecl(); + assert(BaseDecl && "base isn't a CXXRecordDecl"); + + // -- any [virtual base class] has a type with a destructor that is + // delete or inaccessible from the defaulted default constructor + CXXDestructorDecl *BaseDtor = LookupDestructor(BaseDecl); + if (BaseDtor->isDeleted()) + return true; + if (CheckDestructorAccess(Loc, BaseDtor, PDiag()) != + AR_accessible) + return true; + + // -- any [virtual base class either] has no default constructor or + // overload resolution as applied to [its] default constructor + // results in an ambiguity or in a function that is deleted or + // inaccessible from the defaulted default constructor + CXXConstructorDecl *BaseDefault = LookupDefaultConstructor(BaseDecl); + if (!BaseDefault || BaseDefault->isDeleted()) + return true; + + if (CheckConstructorAccess(Loc, BaseDefault, BaseDefault->getAccess(), + PDiag()) != AR_accessible) + return true; + } + + for (CXXRecordDecl::field_iterator FI = RD->field_begin(), + FE = RD->field_end(); + FI != FE; ++FI) { + if (FI->isInvalidDecl()) + continue; + + QualType FieldType = Context.getBaseElementType(FI->getType()); + CXXRecordDecl *FieldRecord = FieldType->getAsCXXRecordDecl(); + + // -- any non-static data member with no brace-or-equal-initializer is of + // reference type + if (FieldType->isReferenceType() && !FI->hasInClassInitializer()) + return true; + + // -- X is a union and all its variant members are of const-qualified type + // (or array thereof) + if (Union && !FieldType.isConstQualified()) + AllConst = false; + + if (FieldRecord) { + // -- X is a union-like class that has a variant member with a non-trivial + // default constructor + if (Union && !FieldRecord->hasTrivialDefaultConstructor()) + return true; + + CXXDestructorDecl *FieldDtor = LookupDestructor(FieldRecord); + if (FieldDtor->isDeleted()) + return true; + if (CheckDestructorAccess(Loc, FieldDtor, PDiag()) != + AR_accessible) + return true; + + // -- any non-variant non-static data member of const-qualified type (or + // array thereof) with no brace-or-equal-initializer does not have a + // user-provided default constructor + if (FieldType.isConstQualified() && + !FI->hasInClassInitializer() && + !FieldRecord->hasUserProvidedDefaultConstructor()) + return true; + + if (!Union && FieldRecord->isUnion() && + FieldRecord->isAnonymousStructOrUnion()) { + // We're okay to reuse AllConst here since we only care about the + // value otherwise if we're in a union. + AllConst = true; + + for (CXXRecordDecl::field_iterator UI = FieldRecord->field_begin(), + UE = FieldRecord->field_end(); + UI != UE; ++UI) { + QualType UnionFieldType = Context.getBaseElementType(UI->getType()); + CXXRecordDecl *UnionFieldRecord = + UnionFieldType->getAsCXXRecordDecl(); + + if (!UnionFieldType.isConstQualified()) + AllConst = false; + + if (UnionFieldRecord && + !UnionFieldRecord->hasTrivialDefaultConstructor()) + return true; + } + + if (AllConst) + return true; + + // Don't try to initialize the anonymous union + // This is technically non-conformant, but sanity demands it. + continue; + } + + // -- any non-static data member with no brace-or-equal-initializer has + // class type M (or array thereof) and either M has no default + // constructor or overload resolution as applied to M's default + // constructor results in an ambiguity or in a function that is deleted + // or inaccessible from the defaulted default constructor. + if (!FI->hasInClassInitializer()) { + CXXConstructorDecl *FieldDefault = LookupDefaultConstructor(FieldRecord); + if (!FieldDefault || FieldDefault->isDeleted()) + return true; + if (CheckConstructorAccess(Loc, FieldDefault, FieldDefault->getAccess(), + PDiag()) != AR_accessible) + return true; + } + } else if (!Union && FieldType.isConstQualified() && + !FI->hasInClassInitializer()) { + // -- any non-variant non-static data member of const-qualified type (or + // array thereof) with no brace-or-equal-initializer does not have a + // user-provided default constructor + return true; + } + } + + if (Union && AllConst) + return true; + + return false; +} + +bool Sema::ShouldDeleteCopyConstructor(CXXConstructorDecl *CD) { + CXXRecordDecl *RD = CD->getParent(); + assert(!RD->isDependentType() && "do deletion after instantiation"); + if (!LangOpts.CPlusPlus0x) + return false; + + SourceLocation Loc = CD->getLocation(); + + // Do access control from the constructor + ContextRAII CtorContext(*this, CD); + + bool Union = RD->isUnion(); + + assert(!CD->getParamDecl(0)->getType()->getPointeeType().isNull() && + "copy assignment arg has no pointee type"); + unsigned ArgQuals = + CD->getParamDecl(0)->getType()->getPointeeType().isConstQualified() ? + Qualifiers::Const : 0; + + // We do this because we should never actually use an anonymous + // union's constructor. + if (Union && RD->isAnonymousStructOrUnion()) + return false; + + // FIXME: We should put some diagnostic logic right into this function. + + // C++0x [class.copy]/11 + // A defaulted [copy] constructor for class X is defined as delete if X has: + + for (CXXRecordDecl::base_class_iterator BI = RD->bases_begin(), + BE = RD->bases_end(); + BI != BE; ++BI) { + // We'll handle this one later + if (BI->isVirtual()) + continue; + + QualType BaseType = BI->getType(); + CXXRecordDecl *BaseDecl = BaseType->getAsCXXRecordDecl(); + assert(BaseDecl && "base isn't a CXXRecordDecl"); + + // -- any [direct base class] of a type with a destructor that is deleted or + // inaccessible from the defaulted constructor + CXXDestructorDecl *BaseDtor = LookupDestructor(BaseDecl); + if (BaseDtor->isDeleted()) + return true; + if (CheckDestructorAccess(Loc, BaseDtor, PDiag()) != + AR_accessible) + return true; + + // -- a [direct base class] B that cannot be [copied] because overload + // resolution, as applied to B's [copy] constructor, results in an + // ambiguity or a function that is deleted or inaccessible from the + // defaulted constructor + CXXConstructorDecl *BaseCtor = LookupCopyConstructor(BaseDecl, ArgQuals); + if (!BaseCtor || BaseCtor->isDeleted()) + return true; + if (CheckConstructorAccess(Loc, BaseCtor, BaseCtor->getAccess(), PDiag()) != + AR_accessible) + return true; + } + + for (CXXRecordDecl::base_class_iterator BI = RD->vbases_begin(), + BE = RD->vbases_end(); + BI != BE; ++BI) { + QualType BaseType = BI->getType(); + CXXRecordDecl *BaseDecl = BaseType->getAsCXXRecordDecl(); + assert(BaseDecl && "base isn't a CXXRecordDecl"); + + // -- any [virtual base class] of a type with a destructor that is deleted or + // inaccessible from the defaulted constructor + CXXDestructorDecl *BaseDtor = LookupDestructor(BaseDecl); + if (BaseDtor->isDeleted()) + return true; + if (CheckDestructorAccess(Loc, BaseDtor, PDiag()) != + AR_accessible) + return true; + + // -- a [virtual base class] B that cannot be [copied] because overload + // resolution, as applied to B's [copy] constructor, results in an + // ambiguity or a function that is deleted or inaccessible from the + // defaulted constructor + CXXConstructorDecl *BaseCtor = LookupCopyConstructor(BaseDecl, ArgQuals); + if (!BaseCtor || BaseCtor->isDeleted()) + return true; + if (CheckConstructorAccess(Loc, BaseCtor, BaseCtor->getAccess(), PDiag()) != + AR_accessible) + return true; + } + + for (CXXRecordDecl::field_iterator FI = RD->field_begin(), + FE = RD->field_end(); + FI != FE; ++FI) { + QualType FieldType = Context.getBaseElementType(FI->getType()); + + // -- for a copy constructor, a non-static data member of rvalue reference + // type + if (FieldType->isRValueReferenceType()) + return true; + + CXXRecordDecl *FieldRecord = FieldType->getAsCXXRecordDecl(); + + if (FieldRecord) { + // This is an anonymous union + if (FieldRecord->isUnion() && FieldRecord->isAnonymousStructOrUnion()) { + // Anonymous unions inside unions do not variant members create + if (!Union) { + for (CXXRecordDecl::field_iterator UI = FieldRecord->field_begin(), + UE = FieldRecord->field_end(); + UI != UE; ++UI) { + QualType UnionFieldType = Context.getBaseElementType(UI->getType()); + CXXRecordDecl *UnionFieldRecord = + UnionFieldType->getAsCXXRecordDecl(); + + // -- a variant member with a non-trivial [copy] constructor and X + // is a union-like class + if (UnionFieldRecord && + !UnionFieldRecord->hasTrivialCopyConstructor()) + return true; + } + } + + // Don't try to initalize an anonymous union + continue; + } else { + // -- a variant member with a non-trivial [copy] constructor and X is a + // union-like class + if (Union && !FieldRecord->hasTrivialCopyConstructor()) + return true; + + // -- any [non-static data member] of a type with a destructor that is + // deleted or inaccessible from the defaulted constructor + CXXDestructorDecl *FieldDtor = LookupDestructor(FieldRecord); + if (FieldDtor->isDeleted()) + return true; + if (CheckDestructorAccess(Loc, FieldDtor, PDiag()) != + AR_accessible) + return true; + } + + // -- a [non-static data member of class type (or array thereof)] B that + // cannot be [copied] because overload resolution, as applied to B's + // [copy] constructor, results in an ambiguity or a function that is + // deleted or inaccessible from the defaulted constructor + CXXConstructorDecl *FieldCtor = LookupCopyConstructor(FieldRecord, + ArgQuals); + if (!FieldCtor || FieldCtor->isDeleted()) + return true; + if (CheckConstructorAccess(Loc, FieldCtor, FieldCtor->getAccess(), + PDiag()) != AR_accessible) + return true; + } + } + + return false; +} + +bool Sema::ShouldDeleteCopyAssignmentOperator(CXXMethodDecl *MD) { + CXXRecordDecl *RD = MD->getParent(); + assert(!RD->isDependentType() && "do deletion after instantiation"); + if (!LangOpts.CPlusPlus0x) + return false; + + SourceLocation Loc = MD->getLocation(); + + // Do access control from the constructor + ContextRAII MethodContext(*this, MD); + + bool Union = RD->isUnion(); + + bool ConstArg = + MD->getParamDecl(0)->getType()->getPointeeType().isConstQualified(); + + // We do this because we should never actually use an anonymous + // union's constructor. + if (Union && RD->isAnonymousStructOrUnion()) + return false; + + DeclarationName OperatorName = + Context.DeclarationNames.getCXXOperatorName(OO_Equal); + LookupResult R(*this, OperatorName, Loc, LookupOrdinaryName); + R.suppressDiagnostics(); + + // FIXME: We should put some diagnostic logic right into this function. + + // C++0x [class.copy]/11 + // A defaulted [copy] assignment operator for class X is defined as deleted + // if X has: + + for (CXXRecordDecl::base_class_iterator BI = RD->bases_begin(), + BE = RD->bases_end(); + BI != BE; ++BI) { + // We'll handle this one later + if (BI->isVirtual()) + continue; + + QualType BaseType = BI->getType(); + CXXRecordDecl *BaseDecl = BaseType->getAsCXXRecordDecl(); + assert(BaseDecl && "base isn't a CXXRecordDecl"); + + // -- a [direct base class] B that cannot be [copied] because overload + // resolution, as applied to B's [copy] assignment operator, results in + // an ambiguity or a function that is deleted or inaccessible from the + // assignment operator + + LookupQualifiedName(R, BaseDecl, false); + + // Filter out any result that isn't a copy-assignment operator. + LookupResult::Filter F = R.makeFilter(); + while (F.hasNext()) { + NamedDecl *D = F.next(); + if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) + if (Method->isCopyAssignmentOperator()) + continue; + + F.erase(); + } + F.done(); + + // Build a fake argument expression + QualType ArgType = BaseType; + QualType ThisType = BaseType; + if (ConstArg) + ArgType.addConst(); + Expr *Args[] = { new (Context) OpaqueValueExpr(Loc, ThisType, VK_LValue) + , new (Context) OpaqueValueExpr(Loc, ArgType, VK_LValue) + }; + + OverloadCandidateSet OCS((Loc)); + OverloadCandidateSet::iterator Best; + + AddFunctionCandidates(R.asUnresolvedSet(), Args, 2, OCS); + + if (OCS.BestViableFunction(*this, Loc, Best, false) != + OR_Success) + return true; + } + + for (CXXRecordDecl::base_class_iterator BI = RD->vbases_begin(), + BE = RD->vbases_end(); + BI != BE; ++BI) { + QualType BaseType = BI->getType(); + CXXRecordDecl *BaseDecl = BaseType->getAsCXXRecordDecl(); + assert(BaseDecl && "base isn't a CXXRecordDecl"); + + // -- a [virtual base class] B that cannot be [copied] because overload + // resolution, as applied to B's [copy] assignment operator, results in + // an ambiguity or a function that is deleted or inaccessible from the + // assignment operator + + LookupQualifiedName(R, BaseDecl, false); + + // Filter out any result that isn't a copy-assignment operator. + LookupResult::Filter F = R.makeFilter(); + while (F.hasNext()) { + NamedDecl *D = F.next(); + if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) + if (Method->isCopyAssignmentOperator()) + continue; + + F.erase(); + } + F.done(); + + // Build a fake argument expression + QualType ArgType = BaseType; + QualType ThisType = BaseType; + if (ConstArg) + ArgType.addConst(); + Expr *Args[] = { new (Context) OpaqueValueExpr(Loc, ThisType, VK_LValue) + , new (Context) OpaqueValueExpr(Loc, ArgType, VK_LValue) + }; + + OverloadCandidateSet OCS((Loc)); + OverloadCandidateSet::iterator Best; + + AddFunctionCandidates(R.asUnresolvedSet(), Args, 2, OCS); + + if (OCS.BestViableFunction(*this, Loc, Best, false) != + OR_Success) + return true; + } + + for (CXXRecordDecl::field_iterator FI = RD->field_begin(), + FE = RD->field_end(); + FI != FE; ++FI) { + QualType FieldType = Context.getBaseElementType(FI->getType()); + + // -- a non-static data member of reference type + if (FieldType->isReferenceType()) + return true; + + // -- a non-static data member of const non-class type (or array thereof) + if (FieldType.isConstQualified() && !FieldType->isRecordType()) + return true; + + CXXRecordDecl *FieldRecord = FieldType->getAsCXXRecordDecl(); + + if (FieldRecord) { + // This is an anonymous union + if (FieldRecord->isUnion() && FieldRecord->isAnonymousStructOrUnion()) { + // Anonymous unions inside unions do not variant members create + if (!Union) { + for (CXXRecordDecl::field_iterator UI = FieldRecord->field_begin(), + UE = FieldRecord->field_end(); + UI != UE; ++UI) { + QualType UnionFieldType = Context.getBaseElementType(UI->getType()); + CXXRecordDecl *UnionFieldRecord = + UnionFieldType->getAsCXXRecordDecl(); + + // -- a variant member with a non-trivial [copy] assignment operator + // and X is a union-like class + if (UnionFieldRecord && + !UnionFieldRecord->hasTrivialCopyAssignment()) + return true; + } + } + + // Don't try to initalize an anonymous union + continue; + // -- a variant member with a non-trivial [copy] assignment operator + // and X is a union-like class + } else if (Union && !FieldRecord->hasTrivialCopyAssignment()) { + return true; + } + + LookupQualifiedName(R, FieldRecord, false); + + // Filter out any result that isn't a copy-assignment operator. + LookupResult::Filter F = R.makeFilter(); + while (F.hasNext()) { + NamedDecl *D = F.next(); + if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) + if (Method->isCopyAssignmentOperator()) + continue; + + F.erase(); + } + F.done(); + + // Build a fake argument expression + QualType ArgType = FieldType; + QualType ThisType = FieldType; + if (ConstArg) + ArgType.addConst(); + Expr *Args[] = { new (Context) OpaqueValueExpr(Loc, ThisType, VK_LValue) + , new (Context) OpaqueValueExpr(Loc, ArgType, VK_LValue) + }; + + OverloadCandidateSet OCS((Loc)); + OverloadCandidateSet::iterator Best; + + AddFunctionCandidates(R.asUnresolvedSet(), Args, 2, OCS); + + if (OCS.BestViableFunction(*this, Loc, Best, false) != + OR_Success) + return true; + } + } + + return false; +} + +bool Sema::ShouldDeleteDestructor(CXXDestructorDecl *DD) { + CXXRecordDecl *RD = DD->getParent(); + assert(!RD->isDependentType() && "do deletion after instantiation"); + if (!LangOpts.CPlusPlus0x) + return false; + + SourceLocation Loc = DD->getLocation(); + + // Do access control from the destructor + ContextRAII CtorContext(*this, DD); + + bool Union = RD->isUnion(); + + // We do this because we should never actually use an anonymous + // union's destructor. + if (Union && RD->isAnonymousStructOrUnion()) + return false; + + // C++0x [class.dtor]p5 + // A defaulted destructor for a class X is defined as deleted if: + for (CXXRecordDecl::base_class_iterator BI = RD->bases_begin(), + BE = RD->bases_end(); + BI != BE; ++BI) { + // We'll handle this one later + if (BI->isVirtual()) + continue; + + CXXRecordDecl *BaseDecl = BI->getType()->getAsCXXRecordDecl(); + CXXDestructorDecl *BaseDtor = LookupDestructor(BaseDecl); + assert(BaseDtor && "base has no destructor"); + + // -- any direct or virtual base class has a deleted destructor or + // a destructor that is inaccessible from the defaulted destructor + if (BaseDtor->isDeleted()) + return true; + if (CheckDestructorAccess(Loc, BaseDtor, PDiag()) != + AR_accessible) + return true; + } + + for (CXXRecordDecl::base_class_iterator BI = RD->vbases_begin(), + BE = RD->vbases_end(); + BI != BE; ++BI) { + CXXRecordDecl *BaseDecl = BI->getType()->getAsCXXRecordDecl(); + CXXDestructorDecl *BaseDtor = LookupDestructor(BaseDecl); + assert(BaseDtor && "base has no destructor"); + + // -- any direct or virtual base class has a deleted destructor or + // a destructor that is inaccessible from the defaulted destructor + if (BaseDtor->isDeleted()) + return true; + if (CheckDestructorAccess(Loc, BaseDtor, PDiag()) != + AR_accessible) + return true; + } + + for (CXXRecordDecl::field_iterator FI = RD->field_begin(), + FE = RD->field_end(); + FI != FE; ++FI) { + QualType FieldType = Context.getBaseElementType(FI->getType()); + CXXRecordDecl *FieldRecord = FieldType->getAsCXXRecordDecl(); + if (FieldRecord) { + if (FieldRecord->isUnion() && FieldRecord->isAnonymousStructOrUnion()) { + for (CXXRecordDecl::field_iterator UI = FieldRecord->field_begin(), + UE = FieldRecord->field_end(); + UI != UE; ++UI) { + QualType UnionFieldType = Context.getBaseElementType(FI->getType()); + CXXRecordDecl *UnionFieldRecord = + UnionFieldType->getAsCXXRecordDecl(); + + // -- X is a union-like class that has a variant member with a non- + // trivial destructor. + if (UnionFieldRecord && !UnionFieldRecord->hasTrivialDestructor()) + return true; + } + // Technically we are supposed to do this next check unconditionally. + // But that makes absolutely no sense. + } else { + CXXDestructorDecl *FieldDtor = LookupDestructor(FieldRecord); + + // -- any of the non-static data members has class type M (or array + // thereof) and M has a deleted destructor or a destructor that is + // inaccessible from the defaulted destructor + if (FieldDtor->isDeleted()) + return true; + if (CheckDestructorAccess(Loc, FieldDtor, PDiag()) != + AR_accessible) + return true; + + // -- X is a union-like class that has a variant member with a non- + // trivial destructor. + if (Union && !FieldDtor->isTrivial()) + return true; + } + } + } + + if (DD->isVirtual()) { + FunctionDecl *OperatorDelete = 0; + DeclarationName Name = + Context.DeclarationNames.getCXXOperatorName(OO_Delete); + if (FindDeallocationFunction(Loc, RD, Name, OperatorDelete, + false)) + return true; + } + + + return false; } /// \brief Data used with FindHiddenVirtualMethod @@ -3053,113 +4169,6 @@ void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc, dyn_cast_or_null<CXXRecordDecl>(TagDecl)); } -namespace { - /// \brief Helper class that collects exception specifications for - /// implicitly-declared special member functions. - class ImplicitExceptionSpecification { - ASTContext &Context; - // We order exception specifications thus: - // noexcept is the most restrictive, but is only used in C++0x. - // throw() comes next. - // Then a throw(collected exceptions) - // Finally no specification. - // throw(...) is used instead if any called function uses it. - ExceptionSpecificationType ComputedEST; - llvm::SmallPtrSet<CanQualType, 4> ExceptionsSeen; - llvm::SmallVector<QualType, 4> Exceptions; - - void ClearExceptions() { - ExceptionsSeen.clear(); - Exceptions.clear(); - } - - public: - explicit ImplicitExceptionSpecification(ASTContext &Context) - : Context(Context), ComputedEST(EST_BasicNoexcept) { - if (!Context.getLangOptions().CPlusPlus0x) - ComputedEST = EST_DynamicNone; - } - - /// \brief Get the computed exception specification type. - ExceptionSpecificationType getExceptionSpecType() const { - assert(ComputedEST != EST_ComputedNoexcept && - "noexcept(expr) should not be a possible result"); - return ComputedEST; - } - - /// \brief The number of exceptions in the exception specification. - unsigned size() const { return Exceptions.size(); } - - /// \brief The set of exceptions in the exception specification. - const QualType *data() const { return Exceptions.data(); } - - /// \brief Integrate another called method into the collected data. - void CalledDecl(CXXMethodDecl *Method) { - // If we have an MSAny spec already, don't bother. - if (!Method || ComputedEST == EST_MSAny) - return; - - const FunctionProtoType *Proto - = Method->getType()->getAs<FunctionProtoType>(); - - ExceptionSpecificationType EST = Proto->getExceptionSpecType(); - - // If this function can throw any exceptions, make a note of that. - if (EST == EST_MSAny || EST == EST_None) { - ClearExceptions(); - ComputedEST = EST; - return; - } - - // If this function has a basic noexcept, it doesn't affect the outcome. - if (EST == EST_BasicNoexcept) - return; - - // If we have a throw-all spec at this point, ignore the function. - if (ComputedEST == EST_None) - return; - - // If we're still at noexcept(true) and there's a nothrow() callee, - // change to that specification. - if (EST == EST_DynamicNone) { - if (ComputedEST == EST_BasicNoexcept) - ComputedEST = EST_DynamicNone; - return; - } - - // Check out noexcept specs. - if (EST == EST_ComputedNoexcept) { - FunctionProtoType::NoexceptResult NR = Proto->getNoexceptSpec(Context); - assert(NR != FunctionProtoType::NR_NoNoexcept && - "Must have noexcept result for EST_ComputedNoexcept."); - assert(NR != FunctionProtoType::NR_Dependent && - "Should not generate implicit declarations for dependent cases, " - "and don't know how to handle them anyway."); - - // noexcept(false) -> no spec on the new function - if (NR == FunctionProtoType::NR_Throw) { - ClearExceptions(); - ComputedEST = EST_None; - } - // noexcept(true) won't change anything either. - return; - } - - assert(EST == EST_Dynamic && "EST case not considered earlier."); - assert(ComputedEST != EST_None && - "Shouldn't collect exceptions when throw-all is guaranteed."); - ComputedEST = EST_Dynamic; - // Record the exceptions in this function's exception specification. - for (FunctionProtoType::exception_iterator E = Proto->exception_begin(), - EEnd = Proto->exception_end(); - E != EEnd; ++E) - if (ExceptionsSeen.insert(Context.getCanonicalType(*E))) - Exceptions.push_back(*E); - } - }; -} - - /// AddImplicitlyDeclaredMembersToClass - Adds any implicitly-declared /// special functions, such as the default constructor, copy /// constructor, or destructor, to the given C++ class (C++ @@ -3467,6 +4476,11 @@ QualType Sema::CheckDestructorDeclarator(Declarator &D, QualType R, if (const TypedefType *TT = DeclaratorType->getAs<TypedefType>()) Diag(D.getIdentifierLoc(), diag::err_destructor_typedef_name) << DeclaratorType << isa<TypeAliasDecl>(TT->getDecl()); + else if (const TemplateSpecializationType *TST = + DeclaratorType->getAs<TemplateSpecializationType>()) + if (TST->isTypeAlias()) + Diag(D.getIdentifierLoc(), diag::err_destructor_typedef_name) + << DeclaratorType << 1; // C++ [class.dtor]p2: // A destructor is used to destroy objects of its class type. A @@ -3725,18 +4739,37 @@ Decl *Sema::ActOnStartNamespaceDef(Scope *NamespcScope, // treated as an original-namespace-name. // // Since namespace names are unique in their scope, and we don't - // look through using directives, just - DeclContext::lookup_result R = CurContext->getRedeclContext()->lookup(II); - NamedDecl *PrevDecl = R.first == R.second? 0 : *R.first; - + // look through using directives, just look for any ordinary names. + + const unsigned IDNS = Decl::IDNS_Ordinary | Decl::IDNS_Member | + Decl::IDNS_Type | Decl::IDNS_Using | Decl::IDNS_Tag | + Decl::IDNS_Namespace; + NamedDecl *PrevDecl = 0; + for (DeclContext::lookup_result R + = CurContext->getRedeclContext()->lookup(II); + R.first != R.second; ++R.first) { + if ((*R.first)->getIdentifierNamespace() & IDNS) { + PrevDecl = *R.first; + break; + } + } + if (NamespaceDecl *OrigNS = dyn_cast_or_null<NamespaceDecl>(PrevDecl)) { // This is an extended namespace definition. if (Namespc->isInline() != OrigNS->isInline()) { // inline-ness must match - Diag(Namespc->getLocation(), diag::err_inline_namespace_mismatch) - << Namespc->isInline(); + if (OrigNS->isInline()) { + // The user probably just forgot the 'inline', so suggest that it + // be added back. + Diag(Namespc->getLocation(), + diag::warn_inline_namespace_reopened_noninline) + << FixItHint::CreateInsertion(NamespaceLoc, "inline "); + } else { + Diag(Namespc->getLocation(), diag::err_inline_namespace_mismatch) + << Namespc->isInline(); + } Diag(OrigNS->getLocation(), diag::note_previous_definition); - Namespc->setInvalidDecl(); + // Recover by ignoring the new namespace's inline status. Namespc->setInline(OrigNS->isInline()); } @@ -4408,6 +5441,7 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS, // Otherwise, look up the target name. LookupResult R(*this, NameInfo, LookupOrdinaryName); + R.setUsingDeclaration(true); // Unlike most lookups, we don't always want to hide tag // declarations: tag names are visible through the using declaration @@ -4701,9 +5735,13 @@ bool Sema::CheckUsingDeclQualifier(SourceLocation UsingLoc, Decl *Sema::ActOnAliasDeclaration(Scope *S, AccessSpecifier AS, + MultiTemplateParamsArg TemplateParamLists, SourceLocation UsingLoc, UnqualifiedId &Name, TypeResult Type) { + // Skip up to the relevant declaration scope. + while (S->getFlags() & Scope::TemplateParamScope) + S = S->getParent(); assert((S->getFlags() & Scope::DeclScope) && "got alias-declaration outside of declaration scope"); @@ -4719,8 +5757,11 @@ Decl *Sema::ActOnAliasDeclaration(Scope *S, return 0; if (DiagnoseUnexpandedParameterPack(Name.StartLocation, TInfo, - UPPC_DeclarationType)) + UPPC_DeclarationType)) { Invalid = true; + TInfo = Context.getTrivialTypeSourceInfo(Context.IntTy, + TInfo->getTypeLoc().getBeginLoc()); + } LookupResult Previous(*this, NameInfo, LookupOrdinaryName, ForRedeclaration); LookupName(Previous, S); @@ -4745,13 +5786,93 @@ Decl *Sema::ActOnAliasDeclaration(Scope *S, if (Invalid) NewTD->setInvalidDecl(); + CheckTypedefForVariablyModifiedType(S, NewTD); + Invalid |= NewTD->isInvalidDecl(); + bool Redeclaration = false; - ActOnTypedefNameDecl(S, CurContext, NewTD, Previous, Redeclaration); + + NamedDecl *NewND; + if (TemplateParamLists.size()) { + TypeAliasTemplateDecl *OldDecl = 0; + TemplateParameterList *OldTemplateParams = 0; + + if (TemplateParamLists.size() != 1) { + Diag(UsingLoc, diag::err_alias_template_extra_headers) + << SourceRange(TemplateParamLists.get()[1]->getTemplateLoc(), + TemplateParamLists.get()[TemplateParamLists.size()-1]->getRAngleLoc()); + } + TemplateParameterList *TemplateParams = TemplateParamLists.get()[0]; + + // Only consider previous declarations in the same scope. + FilterLookupForScope(Previous, CurContext, S, /*ConsiderLinkage*/false, + /*ExplicitInstantiationOrSpecialization*/false); + if (!Previous.empty()) { + Redeclaration = true; + + OldDecl = Previous.getAsSingle<TypeAliasTemplateDecl>(); + if (!OldDecl && !Invalid) { + Diag(UsingLoc, diag::err_redefinition_different_kind) + << Name.Identifier; + + NamedDecl *OldD = Previous.getRepresentativeDecl(); + if (OldD->getLocation().isValid()) + Diag(OldD->getLocation(), diag::note_previous_definition); + + Invalid = true; + } + + if (!Invalid && OldDecl && !OldDecl->isInvalidDecl()) { + if (TemplateParameterListsAreEqual(TemplateParams, + OldDecl->getTemplateParameters(), + /*Complain=*/true, + TPL_TemplateMatch)) + OldTemplateParams = OldDecl->getTemplateParameters(); + else + Invalid = true; + + TypeAliasDecl *OldTD = OldDecl->getTemplatedDecl(); + if (!Invalid && + !Context.hasSameType(OldTD->getUnderlyingType(), + NewTD->getUnderlyingType())) { + // FIXME: The C++0x standard does not clearly say this is ill-formed, + // but we can't reasonably accept it. + Diag(NewTD->getLocation(), diag::err_redefinition_different_typedef) + << 2 << NewTD->getUnderlyingType() << OldTD->getUnderlyingType(); + if (OldTD->getLocation().isValid()) + Diag(OldTD->getLocation(), diag::note_previous_definition); + Invalid = true; + } + } + } + + // Merge any previous default template arguments into our parameters, + // and check the parameter list. + if (CheckTemplateParameterList(TemplateParams, OldTemplateParams, + TPC_TypeAliasTemplate)) + return 0; + + TypeAliasTemplateDecl *NewDecl = + TypeAliasTemplateDecl::Create(Context, CurContext, UsingLoc, + Name.Identifier, TemplateParams, + NewTD); + + NewDecl->setAccess(AS); + + if (Invalid) + NewDecl->setInvalidDecl(); + else if (OldDecl) + NewDecl->setPreviousDeclaration(OldDecl); + + NewND = NewDecl; + } else { + ActOnTypedefNameDecl(S, CurContext, NewTD, Previous, Redeclaration); + NewND = NewTD; + } if (!Redeclaration) - PushOnScopeChains(NewTD, S); + PushOnScopeChains(NewND, S); - return NewTD; + return NewND; } Decl *Sema::ActOnNamespaceAliasDef(Scope *S, @@ -4855,39 +5976,8 @@ namespace { }; } -static CXXConstructorDecl *getDefaultConstructorUnsafe(Sema &Self, - CXXRecordDecl *D) { - ASTContext &Context = Self.Context; - QualType ClassType = Context.getTypeDeclType(D); - DeclarationName ConstructorName - = Context.DeclarationNames.getCXXConstructorName( - Context.getCanonicalType(ClassType.getUnqualifiedType())); - - DeclContext::lookup_const_iterator Con, ConEnd; - for (llvm::tie(Con, ConEnd) = D->lookup(ConstructorName); - Con != ConEnd; ++Con) { - // FIXME: In C++0x, a constructor template can be a default constructor. - if (isa<FunctionTemplateDecl>(*Con)) - continue; - - CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(*Con); - if (Constructor->isDefaultConstructor()) - return Constructor; - } - return 0; -} - -CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor( - CXXRecordDecl *ClassDecl) { - // C++ [class.ctor]p5: - // A default constructor for a class X is a constructor of class X - // that can be called without an argument. If there is no - // user-declared constructor for class X, a default constructor is - // implicitly declared. An implicitly-declared default constructor - // is an inline public member of its class. - assert(!ClassDecl->hasUserDeclaredConstructor() && - "Should not build implicit default constructor!"); - +Sema::ImplicitExceptionSpecification +Sema::ComputeDefaultedDefaultCtorExceptionSpec(CXXRecordDecl *ClassDecl) { // C++ [except.spec]p14: // An implicitly declared special member function (Clause 12) shall have an // exception-specification. [...] @@ -4902,10 +5992,10 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor( if (const RecordType *BaseType = B->getType()->getAs<RecordType>()) { CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(BaseType->getDecl()); - if (!BaseClassDecl->hasDeclaredDefaultConstructor()) - ExceptSpec.CalledDecl(DeclareImplicitDefaultConstructor(BaseClassDecl)); - else if (CXXConstructorDecl *Constructor - = getDefaultConstructorUnsafe(*this, BaseClassDecl)) + CXXConstructorDecl *Constructor = LookupDefaultConstructor(BaseClassDecl); + // If this is a deleted function, add it anyway. This might be conformant + // with the standard. This might not. I'm not sure. It might not matter. + if (Constructor) ExceptSpec.CalledDecl(Constructor); } } @@ -4916,10 +6006,10 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor( B != BEnd; ++B) { if (const RecordType *BaseType = B->getType()->getAs<RecordType>()) { CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(BaseType->getDecl()); - if (!BaseClassDecl->hasDeclaredDefaultConstructor()) - ExceptSpec.CalledDecl(DeclareImplicitDefaultConstructor(BaseClassDecl)); - else if (CXXConstructorDecl *Constructor - = getDefaultConstructorUnsafe(*this, BaseClassDecl)) + CXXConstructorDecl *Constructor = LookupDefaultConstructor(BaseClassDecl); + // If this is a deleted function, add it anyway. This might be conformant + // with the standard. This might not. I'm not sure. It might not matter. + if (Constructor) ExceptSpec.CalledDecl(Constructor); } } @@ -4928,22 +6018,42 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor( for (RecordDecl::field_iterator F = ClassDecl->field_begin(), FEnd = ClassDecl->field_end(); F != FEnd; ++F) { - if (const RecordType *RecordTy + if (F->hasInClassInitializer()) { + if (Expr *E = F->getInClassInitializer()) + ExceptSpec.CalledExpr(E); + else if (!F->isInvalidDecl()) + ExceptSpec.SetDelayed(); + } else if (const RecordType *RecordTy = Context.getBaseElementType(F->getType())->getAs<RecordType>()) { - CXXRecordDecl *FieldClassDecl = cast<CXXRecordDecl>(RecordTy->getDecl()); - if (!FieldClassDecl->hasDeclaredDefaultConstructor()) - ExceptSpec.CalledDecl( - DeclareImplicitDefaultConstructor(FieldClassDecl)); - else if (CXXConstructorDecl *Constructor - = getDefaultConstructorUnsafe(*this, FieldClassDecl)) + CXXRecordDecl *FieldRecDecl = cast<CXXRecordDecl>(RecordTy->getDecl()); + CXXConstructorDecl *Constructor = LookupDefaultConstructor(FieldRecDecl); + // If this is a deleted function, add it anyway. This might be conformant + // with the standard. This might not. I'm not sure. It might not matter. + // In particular, the problem is that this function never gets called. It + // might just be ill-formed because this function attempts to refer to + // a deleted function here. + if (Constructor) ExceptSpec.CalledDecl(Constructor); } } - FunctionProtoType::ExtProtoInfo EPI; - EPI.ExceptionSpecType = ExceptSpec.getExceptionSpecType(); - EPI.NumExceptions = ExceptSpec.size(); - EPI.Exceptions = ExceptSpec.data(); + return ExceptSpec; +} + +CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor( + CXXRecordDecl *ClassDecl) { + // C++ [class.ctor]p5: + // A default constructor for a class X is a constructor of class X + // that can be called without an argument. If there is no + // user-declared constructor for class X, a default constructor is + // implicitly declared. An implicitly-declared default constructor + // is an inline public member of its class. + assert(!ClassDecl->hasUserDeclaredConstructor() && + "Should not build implicit default constructor!"); + + ImplicitExceptionSpecification Spec = + ComputeDefaultedDefaultCtorExceptionSpec(ClassDecl); + FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI(); // Create the actual constructor declaration. CanQualType ClassType @@ -4961,8 +6071,9 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor( /*isInline=*/true, /*isImplicitlyDeclared=*/true); DefaultCon->setAccess(AS_public); + DefaultCon->setDefaulted(); DefaultCon->setImplicit(); - DefaultCon->setTrivial(ClassDecl->hasTrivialConstructor()); + DefaultCon->setTrivial(ClassDecl->hasTrivialDefaultConstructor()); // Note that we have declared this constructor. ++ASTContext::NumImplicitDefaultConstructorsDeclared; @@ -4970,14 +6081,18 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor( if (Scope *S = getScopeForContext(ClassDecl)) PushOnScopeChains(DefaultCon, S, false); ClassDecl->addDecl(DefaultCon); + + if (ShouldDeleteDefaultConstructor(DefaultCon)) + DefaultCon->setDeletedAsWritten(); return DefaultCon; } void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation, CXXConstructorDecl *Constructor) { - assert((Constructor->isImplicit() && Constructor->isDefaultConstructor() && - !Constructor->isUsed(false)) && + assert((Constructor->isDefaulted() && Constructor->isDefaultConstructor() && + !Constructor->doesThisDeclarationHaveABody() && + !Constructor->isDeleted()) && "DefineImplicitDefaultConstructor - call it for implicit default ctor"); CXXRecordDecl *ClassDecl = Constructor->getParent(); @@ -4988,7 +6103,7 @@ void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation, if (SetCtorInitializers(Constructor, 0, 0, /*AnyErrors=*/false) || Trap.hasErrorOccurred()) { Diag(CurrentLocation, diag::note_member_synthesized_at) - << CXXConstructor << Context.getTagDeclType(ClassDecl); + << CXXDefaultConstructor << Context.getTagDeclType(ClassDecl); Constructor->setInvalidDecl(); return; } @@ -5004,6 +6119,59 @@ void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation, } } +/// Get any existing defaulted default constructor for the given class. Do not +/// implicitly define one if it does not exist. +static CXXConstructorDecl *getDefaultedDefaultConstructorUnsafe(Sema &Self, + CXXRecordDecl *D) { + ASTContext &Context = Self.Context; + QualType ClassType = Context.getTypeDeclType(D); + DeclarationName ConstructorName + = Context.DeclarationNames.getCXXConstructorName( + Context.getCanonicalType(ClassType.getUnqualifiedType())); + + DeclContext::lookup_const_iterator Con, ConEnd; + for (llvm::tie(Con, ConEnd) = D->lookup(ConstructorName); + Con != ConEnd; ++Con) { + // A function template cannot be defaulted. + if (isa<FunctionTemplateDecl>(*Con)) + continue; + + CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(*Con); + if (Constructor->isDefaultConstructor()) + return Constructor->isDefaulted() ? Constructor : 0; + } + return 0; +} + +void Sema::ActOnFinishDelayedMemberInitializers(Decl *D) { + if (!D) return; + AdjustDeclIfTemplate(D); + + CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(D); + CXXConstructorDecl *CtorDecl + = getDefaultedDefaultConstructorUnsafe(*this, ClassDecl); + + if (!CtorDecl) return; + + // Compute the exception specification for the default constructor. + const FunctionProtoType *CtorTy = + CtorDecl->getType()->castAs<FunctionProtoType>(); + if (CtorTy->getExceptionSpecType() == EST_Delayed) { + ImplicitExceptionSpecification Spec = + ComputeDefaultedDefaultCtorExceptionSpec(ClassDecl); + FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI(); + assert(EPI.ExceptionSpecType != EST_Delayed); + + CtorDecl->setType(Context.getFunctionType(Context.VoidTy, 0, 0, EPI)); + } + + // If the default constructor is explicitly defaulted, checking the exception + // specification is deferred until now. + if (!CtorDecl->isInvalidDecl() && CtorDecl->isExplicitlyDefaulted() && + !ClassDecl->isDependentType()) + CheckExplicitlyDefaultedDefaultConstructor(CtorDecl); +} + void Sema::DeclareInheritedConstructors(CXXRecordDecl *ClassDecl) { // We start with an initial pass over the base classes to collect those that // inherit constructors from. If there are none, we can forgo all further @@ -5097,7 +6265,9 @@ void Sema::DeclareInheritedConstructors(CXXRecordDecl *ClassDecl) { // Build up a function type for this particular constructor. // FIXME: The working paper does not consider that the exception spec // for the inheriting constructor might be larger than that of the - // source. This code doesn't yet, either. + // source. This code doesn't yet, either. When it does, this code will + // need to be delayed until after exception specifications and in-class + // member initializers are attached. const Type *NewCtorType; if (params == maxParams) NewCtorType = BaseCtorType; @@ -5179,12 +6349,8 @@ void Sema::DeclareInheritedConstructors(CXXRecordDecl *ClassDecl) { } } -CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) { - // C++ [class.dtor]p2: - // If a class has no user-declared destructor, a destructor is - // declared implicitly. An implicitly-declared destructor is an - // inline public member of its class. - +Sema::ImplicitExceptionSpecification +Sema::ComputeDefaultedDtorExceptionSpec(CXXRecordDecl *ClassDecl) { // C++ [except.spec]p14: // An implicitly declared special member function (Clause 12) shall have // an exception-specification. @@ -5199,18 +6365,18 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) { if (const RecordType *BaseType = B->getType()->getAs<RecordType>()) ExceptSpec.CalledDecl( - LookupDestructor(cast<CXXRecordDecl>(BaseType->getDecl()))); + LookupDestructor(cast<CXXRecordDecl>(BaseType->getDecl()))); } - + // Virtual base-class destructors. for (CXXRecordDecl::base_class_iterator B = ClassDecl->vbases_begin(), BEnd = ClassDecl->vbases_end(); B != BEnd; ++B) { if (const RecordType *BaseType = B->getType()->getAs<RecordType>()) ExceptSpec.CalledDecl( - LookupDestructor(cast<CXXRecordDecl>(BaseType->getDecl()))); + LookupDestructor(cast<CXXRecordDecl>(BaseType->getDecl()))); } - + // Field destructors. for (RecordDecl::field_iterator F = ClassDecl->field_begin(), FEnd = ClassDecl->field_end(); @@ -5218,14 +6384,23 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) { if (const RecordType *RecordTy = Context.getBaseElementType(F->getType())->getAs<RecordType>()) ExceptSpec.CalledDecl( - LookupDestructor(cast<CXXRecordDecl>(RecordTy->getDecl()))); + LookupDestructor(cast<CXXRecordDecl>(RecordTy->getDecl()))); } + return ExceptSpec; +} + +CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) { + // C++ [class.dtor]p2: + // If a class has no user-declared destructor, a destructor is + // declared implicitly. An implicitly-declared destructor is an + // inline public member of its class. + + ImplicitExceptionSpecification Spec = + ComputeDefaultedDtorExceptionSpec(ClassDecl); + FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI(); + // Create the actual destructor declaration. - FunctionProtoType::ExtProtoInfo EPI; - EPI.ExceptionSpecType = ExceptSpec.getExceptionSpecType(); - EPI.NumExceptions = ExceptSpec.size(); - EPI.Exceptions = ExceptSpec.data(); QualType Ty = Context.getFunctionType(Context.VoidTy, 0, 0, EPI); CanQualType ClassType @@ -5239,6 +6414,7 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) { /*isInline=*/true, /*isImplicitlyDeclared=*/true); Destructor->setAccess(AS_public); + Destructor->setDefaulted(); Destructor->setImplicit(); Destructor->setTrivial(ClassDecl->hasTrivialDestructor()); @@ -5252,6 +6428,9 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) { // This could be uniqued if it ever proves significant. Destructor->setTypeSourceInfo(Context.getTrivialTypeSourceInfo(Ty)); + + if (ShouldDeleteDestructor(Destructor)) + Destructor->setDeletedAsWritten(); AddOverriddenMethods(ClassDecl, Destructor); @@ -5260,7 +6439,8 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) { void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation, CXXDestructorDecl *Destructor) { - assert((Destructor->isImplicit() && !Destructor->isUsed(false)) && + assert((Destructor->isDefaulted() && + !Destructor->doesThisDeclarationHaveABody()) && "DefineImplicitDestructor - call it for implicit default dtor"); CXXRecordDecl *ClassDecl = Destructor->getParent(); assert(ClassDecl && "DefineImplicitDestructor - invalid destructor"); @@ -5293,6 +6473,35 @@ void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation, } } +void Sema::AdjustDestructorExceptionSpec(CXXRecordDecl *classDecl, + CXXDestructorDecl *destructor) { + // C++11 [class.dtor]p3: + // A declaration of a destructor that does not have an exception- + // specification is implicitly considered to have the same exception- + // specification as an implicit declaration. + const FunctionProtoType *dtorType = destructor->getType()-> + getAs<FunctionProtoType>(); + if (dtorType->hasExceptionSpec()) + return; + + ImplicitExceptionSpecification exceptSpec = + ComputeDefaultedDtorExceptionSpec(classDecl); + + // Replace the destructor's type. + FunctionProtoType::ExtProtoInfo epi; + epi.ExceptionSpecType = exceptSpec.getExceptionSpecType(); + epi.NumExceptions = exceptSpec.size(); + epi.Exceptions = exceptSpec.data(); + QualType ty = Context.getFunctionType(Context.VoidTy, 0, 0, epi); + + destructor->setType(ty); + + // FIXME: If the destructor has a body that could throw, and the newly created + // spec doesn't allow exceptions, we should emit a warning, because this + // change in behavior can break conforming C++03 programs at runtime. + // However, we don't have a body yet, so it needs to be done somewhere else. +} + /// \brief Builds a statement that copies the given entity from \p From to /// \c To. /// @@ -5530,13 +6739,9 @@ static bool hasConstCopyAssignment(Sema &S, const CXXRecordDecl *CClass) { return false; } -CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) { - // Note: The following rules are largely analoguous to the copy - // constructor rules. Note that virtual bases are not taken into account - // for determining the argument type of the operator. Note also that - // operators taking an object instead of a reference are allowed. - - +std::pair<Sema::ImplicitExceptionSpecification, bool> +Sema::ComputeDefaultedCopyAssignmentExceptionSpecAndConst( + CXXRecordDecl *ClassDecl) { // C++ [class.copy]p10: // If the class definition does not explicitly declare a copy // assignment operator, one is declared implicitly. @@ -5581,11 +6786,6 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) { // have the form // // X& X::operator=(X&) - QualType ArgType = Context.getTypeDeclType(ClassDecl); - QualType RetType = Context.getLValueReferenceType(ArgType); - if (HasConstCopyAssignment) - ArgType = ArgType.withConst(); - ArgType = Context.getLValueReferenceType(ArgType); // C++ [except.spec]p14: // An implicitly declared special member function (Clause 12) shall have an @@ -5622,12 +6822,29 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) { } } + return std::make_pair(ExceptSpec, HasConstCopyAssignment); +} + +CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) { + // Note: The following rules are largely analoguous to the copy + // constructor rules. Note that virtual bases are not taken into account + // for determining the argument type of the operator. Note also that + // operators taking an object instead of a reference are allowed. + + ImplicitExceptionSpecification Spec(Context); + bool Const; + llvm::tie(Spec, Const) = + ComputeDefaultedCopyAssignmentExceptionSpecAndConst(ClassDecl); + + QualType ArgType = Context.getTypeDeclType(ClassDecl); + QualType RetType = Context.getLValueReferenceType(ArgType); + if (Const) + ArgType = ArgType.withConst(); + ArgType = Context.getLValueReferenceType(ArgType); + // An implicitly-declared copy assignment operator is an inline public // member of its class. - FunctionProtoType::ExtProtoInfo EPI; - EPI.ExceptionSpecType = ExceptSpec.getExceptionSpecType(); - EPI.NumExceptions = ExceptSpec.size(); - EPI.Exceptions = ExceptSpec.data(); + FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI(); DeclarationName Name = Context.DeclarationNames.getCXXOperatorName(OO_Equal); SourceLocation ClassLoc = ClassDecl->getLocation(); DeclarationNameInfo NameInfo(Name, ClassLoc); @@ -5639,6 +6856,7 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) { /*isInline=*/true, SourceLocation()); CopyAssignment->setAccess(AS_public); + CopyAssignment->setDefaulted(); CopyAssignment->setImplicit(); CopyAssignment->setTrivial(ClassDecl->hasTrivialCopyAssignment()); @@ -5652,21 +6870,24 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) { // Note that we have added this copy-assignment operator. ++ASTContext::NumImplicitCopyAssignmentOperatorsDeclared; - + if (Scope *S = getScopeForContext(ClassDecl)) PushOnScopeChains(CopyAssignment, S, false); ClassDecl->addDecl(CopyAssignment); + if (ShouldDeleteCopyAssignmentOperator(CopyAssignment)) + CopyAssignment->setDeletedAsWritten(); + AddOverriddenMethods(ClassDecl, CopyAssignment); return CopyAssignment; } void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, CXXMethodDecl *CopyAssignOperator) { - assert((CopyAssignOperator->isImplicit() && + assert((CopyAssignOperator->isDefaulted() && CopyAssignOperator->isOverloadedOperator() && CopyAssignOperator->getOverloadedOperator() == OO_Equal && - !CopyAssignOperator->isUsed(false)) && + !CopyAssignOperator->doesThisDeclarationHaveABody()) && "DefineImplicitCopyAssignment called for wrong function"); CXXRecordDecl *ClassDecl = CopyAssignOperator->getParent(); @@ -5956,12 +7177,8 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, } } -CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor( - CXXRecordDecl *ClassDecl) { - // C++ [class.copy]p4: - // If the class definition does not explicitly declare a copy - // constructor, one is declared implicitly. - +std::pair<Sema::ImplicitExceptionSpecification, bool> +Sema::ComputeDefaultedCopyCtorExceptionSpecAndConst(CXXRecordDecl *ClassDecl) { // C++ [class.copy]p5: // The implicitly-declared copy constructor for a class X will // have the form @@ -5969,6 +7186,7 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor( // X::X(const X&) // // if + // FIXME: It ought to be possible to store this on the record. bool HasConstCopyConstructor = true; // -- each direct or virtual base class B of X has a copy @@ -5984,11 +7202,8 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor( CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); - if (!BaseClassDecl->hasDeclaredCopyConstructor()) - DeclareImplicitCopyConstructor(BaseClassDecl); - - HasConstCopyConstructor - = BaseClassDecl->hasConstCopyConstructor(Context); + LookupCopyConstructor(BaseClassDecl, Qualifiers::Const, + &HasConstCopyConstructor); } for (CXXRecordDecl::base_class_iterator Base = ClassDecl->vbases_begin(), @@ -5997,11 +7212,8 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor( ++Base) { CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); - if (!BaseClassDecl->hasDeclaredCopyConstructor()) - DeclareImplicitCopyConstructor(BaseClassDecl); - - HasConstCopyConstructor - = BaseClassDecl->hasConstCopyConstructor(Context); + LookupCopyConstructor(BaseClassDecl, Qualifiers::Const, + &HasConstCopyConstructor); } // -- for all the nonstatic data members of X that are of a @@ -6013,27 +7225,16 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor( HasConstCopyConstructor && Field != FieldEnd; ++Field) { QualType FieldType = Context.getBaseElementType((*Field)->getType()); - if (const RecordType *FieldClassType = FieldType->getAs<RecordType>()) { - CXXRecordDecl *FieldClassDecl - = cast<CXXRecordDecl>(FieldClassType->getDecl()); - if (!FieldClassDecl->hasDeclaredCopyConstructor()) - DeclareImplicitCopyConstructor(FieldClassDecl); - - HasConstCopyConstructor - = FieldClassDecl->hasConstCopyConstructor(Context); + if (CXXRecordDecl *FieldClassDecl = FieldType->getAsCXXRecordDecl()) { + LookupCopyConstructor(FieldClassDecl, Qualifiers::Const, + &HasConstCopyConstructor); } } - // Otherwise, the implicitly declared copy constructor will have // the form // // X::X(X&) - QualType ClassType = Context.getTypeDeclType(ClassDecl); - QualType ArgType = ClassType; - if (HasConstCopyConstructor) - ArgType = ArgType.withConst(); - ArgType = Context.getLValueReferenceType(ArgType); - + // C++ [except.spec]p14: // An implicitly declared special member function (Clause 12) shall have an // exception-specification. [...] @@ -6049,11 +7250,8 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor( CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); - if (!BaseClassDecl->hasDeclaredCopyConstructor()) - DeclareImplicitCopyConstructor(BaseClassDecl); - - if (CXXConstructorDecl *CopyConstructor - = BaseClassDecl->getCopyConstructor(Context, Quals)) + if (CXXConstructorDecl *CopyConstructor = + LookupCopyConstructor(BaseClassDecl, Quals)) ExceptSpec.CalledDecl(CopyConstructor); } for (CXXRecordDecl::base_class_iterator Base = ClassDecl->vbases_begin(), @@ -6062,11 +7260,8 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor( ++Base) { CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); - if (!BaseClassDecl->hasDeclaredCopyConstructor()) - DeclareImplicitCopyConstructor(BaseClassDecl); - - if (CXXConstructorDecl *CopyConstructor - = BaseClassDecl->getCopyConstructor(Context, Quals)) + if (CXXConstructorDecl *CopyConstructor = + LookupCopyConstructor(BaseClassDecl, Quals)) ExceptSpec.CalledDecl(CopyConstructor); } for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), @@ -6074,29 +7269,43 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor( Field != FieldEnd; ++Field) { QualType FieldType = Context.getBaseElementType((*Field)->getType()); - if (const RecordType *FieldClassType = FieldType->getAs<RecordType>()) { - CXXRecordDecl *FieldClassDecl - = cast<CXXRecordDecl>(FieldClassType->getDecl()); - if (!FieldClassDecl->hasDeclaredCopyConstructor()) - DeclareImplicitCopyConstructor(FieldClassDecl); - - if (CXXConstructorDecl *CopyConstructor - = FieldClassDecl->getCopyConstructor(Context, Quals)) - ExceptSpec.CalledDecl(CopyConstructor); + if (CXXRecordDecl *FieldClassDecl = FieldType->getAsCXXRecordDecl()) { + if (CXXConstructorDecl *CopyConstructor = + LookupCopyConstructor(FieldClassDecl, Quals)) + ExceptSpec.CalledDecl(CopyConstructor); } } - // An implicitly-declared copy constructor is an inline public - // member of its class. - FunctionProtoType::ExtProtoInfo EPI; - EPI.ExceptionSpecType = ExceptSpec.getExceptionSpecType(); - EPI.NumExceptions = ExceptSpec.size(); - EPI.Exceptions = ExceptSpec.data(); + return std::make_pair(ExceptSpec, HasConstCopyConstructor); +} + +CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor( + CXXRecordDecl *ClassDecl) { + // C++ [class.copy]p4: + // If the class definition does not explicitly declare a copy + // constructor, one is declared implicitly. + + ImplicitExceptionSpecification Spec(Context); + bool Const; + llvm::tie(Spec, Const) = + ComputeDefaultedCopyCtorExceptionSpecAndConst(ClassDecl); + + QualType ClassType = Context.getTypeDeclType(ClassDecl); + QualType ArgType = ClassType; + if (Const) + ArgType = ArgType.withConst(); + ArgType = Context.getLValueReferenceType(ArgType); + + FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI(); + DeclarationName Name = Context.DeclarationNames.getCXXConstructorName( Context.getCanonicalType(ClassType)); SourceLocation ClassLoc = ClassDecl->getLocation(); DeclarationNameInfo NameInfo(Name, ClassLoc); + + // An implicitly-declared copy constructor is an inline public + // member of its class. CXXConstructorDecl *CopyConstructor = CXXConstructorDecl::Create(Context, ClassDecl, ClassLoc, NameInfo, Context.getFunctionType(Context.VoidTy, @@ -6106,6 +7315,7 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor( /*isInline=*/true, /*isImplicitlyDeclared=*/true); CopyConstructor->setAccess(AS_public); + CopyConstructor->setDefaulted(); CopyConstructor->setTrivial(ClassDecl->hasTrivialCopyConstructor()); // Note that we have declared this constructor. @@ -6119,19 +7329,22 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor( SC_None, SC_None, 0); CopyConstructor->setParams(&FromParam, 1); + if (Scope *S = getScopeForContext(ClassDecl)) PushOnScopeChains(CopyConstructor, S, false); ClassDecl->addDecl(CopyConstructor); + + if (ShouldDeleteCopyConstructor(CopyConstructor)) + CopyConstructor->setDeletedAsWritten(); return CopyConstructor; } void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation, - CXXConstructorDecl *CopyConstructor, - unsigned TypeQuals) { - assert((CopyConstructor->isImplicit() && - CopyConstructor->isCopyConstructor(TypeQuals) && - !CopyConstructor->isUsed(false)) && + CXXConstructorDecl *CopyConstructor) { + assert((CopyConstructor->isDefaulted() && + CopyConstructor->isCopyConstructor() && + !CopyConstructor->doesThisDeclarationHaveABody()) && "DefineImplicitCopyConstructor - call it for implicit copy ctor"); CXXRecordDecl *ClassDecl = CopyConstructor->getParent(); @@ -7138,7 +8351,7 @@ Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc, bool Invalid = false; if (TemplateParameterList *TemplateParams - = MatchTemplateParametersToScopeSpecifier(TagLoc, SS, + = MatchTemplateParametersToScopeSpecifier(TagLoc, NameLoc, SS, TempParamLists.get(), TempParamLists.size(), /*friend*/ true, @@ -7554,7 +8767,83 @@ void Sema::SetDeclDeleted(Decl *Dcl, SourceLocation DelLoc) { // If the declaration wasn't the first, we delete the function anyway for // recovery. } - Fn->setDeleted(); + Fn->setDeletedAsWritten(); +} + +void Sema::SetDeclDefaulted(Decl *Dcl, SourceLocation DefaultLoc) { + CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Dcl); + + if (MD) { + if (MD->getParent()->isDependentType()) { + MD->setDefaulted(); + MD->setExplicitlyDefaulted(); + return; + } + + CXXSpecialMember Member = getSpecialMember(MD); + if (Member == CXXInvalid) { + Diag(DefaultLoc, diag::err_default_special_members); + return; + } + + MD->setDefaulted(); + MD->setExplicitlyDefaulted(); + + // If this definition appears within the record, do the checking when + // the record is complete. + const FunctionDecl *Primary = MD; + if (MD->getTemplatedKind() != FunctionDecl::TK_NonTemplate) + // Find the uninstantiated declaration that actually had the '= default' + // on it. + MD->getTemplateInstantiationPattern()->isDefined(Primary); + + if (Primary == Primary->getCanonicalDecl()) + return; + + switch (Member) { + case CXXDefaultConstructor: { + CXXConstructorDecl *CD = cast<CXXConstructorDecl>(MD); + CheckExplicitlyDefaultedDefaultConstructor(CD); + if (!CD->isInvalidDecl()) + DefineImplicitDefaultConstructor(DefaultLoc, CD); + break; + } + + case CXXCopyConstructor: { + CXXConstructorDecl *CD = cast<CXXConstructorDecl>(MD); + CheckExplicitlyDefaultedCopyConstructor(CD); + if (!CD->isInvalidDecl()) + DefineImplicitCopyConstructor(DefaultLoc, CD); + break; + } + + case CXXCopyAssignment: { + CheckExplicitlyDefaultedCopyAssignment(MD); + if (!MD->isInvalidDecl()) + DefineImplicitCopyAssignment(DefaultLoc, MD); + break; + } + + case CXXDestructor: { + CXXDestructorDecl *DD = cast<CXXDestructorDecl>(MD); + CheckExplicitlyDefaultedDestructor(DD); + if (!DD->isInvalidDecl()) + DefineImplicitDestructor(DefaultLoc, DD); + break; + } + + case CXXMoveConstructor: + case CXXMoveAssignment: + Diag(Dcl->getLocation(), diag::err_defaulted_move_unsupported); + break; + + default: + // FIXME: Do the rest once we have move functions + break; + } + } else { + Diag(DefaultLoc, diag::err_default_special_members); + } } static void SearchForReturnInStmt(Sema &Self, Stmt *S) { @@ -7946,3 +9235,86 @@ void Sema::SetIvarInitializers(ObjCImplementationDecl *ObjCImplementation) { AllToInit.data(), AllToInit.size()); } } + +static +void DelegatingCycleHelper(CXXConstructorDecl* Ctor, + llvm::SmallSet<CXXConstructorDecl*, 4> &Valid, + llvm::SmallSet<CXXConstructorDecl*, 4> &Invalid, + llvm::SmallSet<CXXConstructorDecl*, 4> &Current, + Sema &S) { + llvm::SmallSet<CXXConstructorDecl*, 4>::iterator CI = Current.begin(), + CE = Current.end(); + if (Ctor->isInvalidDecl()) + return; + + const FunctionDecl *FNTarget = 0; + CXXConstructorDecl *Target; + + // We ignore the result here since if we don't have a body, Target will be + // null below. + (void)Ctor->getTargetConstructor()->hasBody(FNTarget); + Target += const_cast<CXXConstructorDecl*>(cast_or_null<CXXConstructorDecl>(FNTarget)); + + CXXConstructorDecl *Canonical = Ctor->getCanonicalDecl(), + // Avoid dereferencing a null pointer here. + *TCanonical = Target ? Target->getCanonicalDecl() : 0; + + if (!Current.insert(Canonical)) + return; + + // We know that beyond here, we aren't chaining into a cycle. + if (!Target || !Target->isDelegatingConstructor() || + Target->isInvalidDecl() || Valid.count(TCanonical)) { + for (CI = Current.begin(), CE = Current.end(); CI != CE; ++CI) + Valid.insert(*CI); + Current.clear(); + // We've hit a cycle. + } else if (TCanonical == Canonical || Invalid.count(TCanonical) || + Current.count(TCanonical)) { + // If we haven't diagnosed this cycle yet, do so now. + if (!Invalid.count(TCanonical)) { + S.Diag((*Ctor->init_begin())->getSourceLocation(), + diag::warn_delegating_ctor_cycle) + << Ctor; + + // Don't add a note for a function delegating directo to itself. + if (TCanonical != Canonical) + S.Diag(Target->getLocation(), diag::note_it_delegates_to); + + CXXConstructorDecl *C = Target; + while (C->getCanonicalDecl() != Canonical) { + (void)C->getTargetConstructor()->hasBody(FNTarget); + assert(FNTarget && "Ctor cycle through bodiless function"); + + C + = const_cast<CXXConstructorDecl*>(cast<CXXConstructorDecl>(FNTarget)); + S.Diag(C->getLocation(), diag::note_which_delegates_to); + } + } + + for (CI = Current.begin(), CE = Current.end(); CI != CE; ++CI) + Invalid.insert(*CI); + Current.clear(); + } else { + DelegatingCycleHelper(Target, Valid, Invalid, Current, S); + } +} + + +void Sema::CheckDelegatingCtorCycles() { + llvm::SmallSet<CXXConstructorDecl*, 4> Valid, Invalid, Current; + + llvm::SmallSet<CXXConstructorDecl*, 4>::iterator CI = Current.begin(), + CE = Current.end(); + + for (llvm::SmallVector<CXXConstructorDecl*, 4>::iterator + I = DelegatingCtorDecls.begin(), + E = DelegatingCtorDecls.end(); + I != E; ++I) { + DelegatingCycleHelper(*I, Valid, Invalid, Current, *this); + } + + for (CI = Invalid.begin(), CE = Invalid.end(); CI != CE; ++CI) + (*CI)->setInvalidDecl(); +} diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaDeclObjC.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaDeclObjC.cpp index 7b235ba..de9097e 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaDeclObjC.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaDeclObjC.cpp @@ -24,6 +24,141 @@ using namespace clang; +bool Sema::CheckObjCMethodOverride(ObjCMethodDecl *NewMethod, + const ObjCMethodDecl *Overridden, + bool IsImplementation) { + if (Overridden->hasRelatedResultType() && + !NewMethod->hasRelatedResultType()) { + // This can only happen when the method follows a naming convention that + // implies a related result type, and the original (overridden) method has + // a suitable return type, but the new (overriding) method does not have + // a suitable return type. + QualType ResultType = NewMethod->getResultType(); + SourceRange ResultTypeRange; + if (const TypeSourceInfo *ResultTypeInfo + = NewMethod->getResultTypeSourceInfo()) + ResultTypeRange = ResultTypeInfo->getTypeLoc().getSourceRange(); + + // Figure out which class this method is part of, if any. + ObjCInterfaceDecl *CurrentClass + = dyn_cast<ObjCInterfaceDecl>(NewMethod->getDeclContext()); + if (!CurrentClass) { + DeclContext *DC = NewMethod->getDeclContext(); + if (ObjCCategoryDecl *Cat = dyn_cast<ObjCCategoryDecl>(DC)) + CurrentClass = Cat->getClassInterface(); + else if (ObjCImplDecl *Impl = dyn_cast<ObjCImplDecl>(DC)) + CurrentClass = Impl->getClassInterface(); + else if (ObjCCategoryImplDecl *CatImpl + = dyn_cast<ObjCCategoryImplDecl>(DC)) + CurrentClass = CatImpl->getClassInterface(); + } + + if (CurrentClass) { + Diag(NewMethod->getLocation(), + diag::warn_related_result_type_compatibility_class) + << Context.getObjCInterfaceType(CurrentClass) + << ResultType + << ResultTypeRange; + } else { + Diag(NewMethod->getLocation(), + diag::warn_related_result_type_compatibility_protocol) + << ResultType + << ResultTypeRange; + } + + Diag(Overridden->getLocation(), diag::note_related_result_type_overridden) + << Overridden->getMethodFamily(); + } + + return false; +} + + +static bool CheckObjCMethodOverrides(Sema &S, ObjCMethodDecl *NewMethod, + DeclContext *DC, + bool SkipCurrent = true) { + if (!DC) + return false; + + if (!SkipCurrent) { + // Look for this method. If we find it, we're done. + Selector Sel = NewMethod->getSelector(); + bool IsInstance = NewMethod->isInstanceMethod(); + DeclContext::lookup_const_iterator Meth, MethEnd; + for (llvm::tie(Meth, MethEnd) = DC->lookup(Sel); Meth != MethEnd; ++Meth) { + ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(*Meth); + if (MD && MD->isInstanceMethod() == IsInstance) + return S.CheckObjCMethodOverride(NewMethod, MD, false); + } + } + + if (ObjCInterfaceDecl *Class = llvm::dyn_cast<ObjCInterfaceDecl>(DC)) { + // Look through categories. + for (ObjCCategoryDecl *Category = Class->getCategoryList(); + Category; Category = Category->getNextClassCategory()) { + if (CheckObjCMethodOverrides(S, NewMethod, Category, false)) + return true; + } + + // Look through protocols. + for (ObjCList<ObjCProtocolDecl>::iterator I = Class->protocol_begin(), + IEnd = Class->protocol_end(); + I != IEnd; ++I) + if (CheckObjCMethodOverrides(S, NewMethod, *I, false)) + return true; + + // Look in our superclass. + return CheckObjCMethodOverrides(S, NewMethod, Class->getSuperClass(), + false); + } + + if (ObjCCategoryDecl *Category = dyn_cast<ObjCCategoryDecl>(DC)) { + // Look through protocols. + for (ObjCList<ObjCProtocolDecl>::iterator I = Category->protocol_begin(), + IEnd = Category->protocol_end(); + I != IEnd; ++I) + if (CheckObjCMethodOverrides(S, NewMethod, *I, false)) + return true; + + return false; + } + + if (ObjCProtocolDecl *Protocol = dyn_cast<ObjCProtocolDecl>(DC)) { + // Look through protocols. + for (ObjCList<ObjCProtocolDecl>::iterator I = Protocol->protocol_begin(), + IEnd = Protocol->protocol_end(); + I != IEnd; ++I) + if (CheckObjCMethodOverrides(S, NewMethod, *I, false)) + return true; + + return false; + } + + return false; +} + +bool Sema::CheckObjCMethodOverrides(ObjCMethodDecl *NewMethod, + DeclContext *DC) { + if (ObjCInterfaceDecl *Class = dyn_cast<ObjCInterfaceDecl>(DC)) + return ::CheckObjCMethodOverrides(*this, NewMethod, Class); + + if (ObjCCategoryDecl *Category = dyn_cast<ObjCCategoryDecl>(DC)) + return ::CheckObjCMethodOverrides(*this, NewMethod, Category); + + if (ObjCProtocolDecl *Protocol = dyn_cast<ObjCProtocolDecl>(DC)) + return ::CheckObjCMethodOverrides(*this, NewMethod, Protocol); + + if (ObjCImplementationDecl *Impl = dyn_cast<ObjCImplementationDecl>(DC)) + return ::CheckObjCMethodOverrides(*this, NewMethod, + Impl->getClassInterface()); + + if (ObjCCategoryImplDecl *CatImpl = dyn_cast<ObjCCategoryImplDecl>(DC)) + return ::CheckObjCMethodOverrides(*this, NewMethod, + CatImpl->getClassInterface()); + + return ::CheckObjCMethodOverrides(*this, NewMethod, CurContext); +} + static void DiagnoseObjCImplementedDeprecations(Sema &S, NamedDecl *ND, SourceLocation ImplLoc, @@ -272,23 +407,27 @@ Decl *Sema::ActOnCompatiblityAlias(SourceLocation AtLoc, return AliasDecl; } -void Sema::CheckForwardProtocolDeclarationForCircularDependency( +bool Sema::CheckForwardProtocolDeclarationForCircularDependency( IdentifierInfo *PName, SourceLocation &Ploc, SourceLocation PrevLoc, const ObjCList<ObjCProtocolDecl> &PList) { + + bool res = false; for (ObjCList<ObjCProtocolDecl>::iterator I = PList.begin(), E = PList.end(); I != E; ++I) { - if (ObjCProtocolDecl *PDecl = LookupProtocol((*I)->getIdentifier(), Ploc)) { if (PDecl->getIdentifier() == PName) { Diag(Ploc, diag::err_protocol_has_circular_dependency); Diag(PrevLoc, diag::note_previous_definition); + res = true; } - CheckForwardProtocolDeclarationForCircularDependency(PName, Ploc, - PDecl->getLocation(), PDecl->getReferencedProtocols()); + if (CheckForwardProtocolDeclarationForCircularDependency(PName, Ploc, + PDecl->getLocation(), PDecl->getReferencedProtocols())) + res = true; } } + return res; } Decl * @@ -300,6 +439,7 @@ Sema::ActOnStartProtocolInterface(SourceLocation AtProtoInterfaceLoc, const SourceLocation *ProtoLocs, SourceLocation EndProtoLoc, AttributeList *AttrList) { + bool err = false; // FIXME: Deal with AttrList. assert(ProtocolName && "Missing protocol identifier"); ObjCProtocolDecl *PDecl = LookupProtocol(ProtocolName, ProtocolLoc); @@ -314,8 +454,8 @@ Sema::ActOnStartProtocolInterface(SourceLocation AtProtoInterfaceLoc, } ObjCList<ObjCProtocolDecl> PList; PList.set((ObjCProtocolDecl *const*)ProtoRefs, NumProtoRefs, Context); - CheckForwardProtocolDeclarationForCircularDependency( - ProtocolName, ProtocolLoc, PDecl->getLocation(), PList); + err = CheckForwardProtocolDeclarationForCircularDependency( + ProtocolName, ProtocolLoc, PDecl->getLocation(), PList); // Make sure the cached decl gets a valid start location. PDecl->setLocation(AtProtoInterfaceLoc); @@ -331,7 +471,7 @@ Sema::ActOnStartProtocolInterface(SourceLocation AtProtoInterfaceLoc, } if (AttrList) ProcessDeclAttributeList(TUScope, PDecl, AttrList); - if (NumProtoRefs) { + if (!err && NumProtoRefs ) { /// Check then save referenced protocols. PDecl->setProtocolList((ObjCProtocolDecl**)ProtoRefs, NumProtoRefs, ProtoLocs, Context); @@ -1712,11 +1852,71 @@ bool containsInvalidMethodImplAttribute(const AttrVec &A) { return false; } +/// \brief Check whether the declared result type of the given Objective-C +/// method declaration is compatible with the method's class. +/// +static bool +CheckRelatedResultTypeCompatibility(Sema &S, ObjCMethodDecl *Method, + ObjCInterfaceDecl *CurrentClass) { + QualType ResultType = Method->getResultType(); + SourceRange ResultTypeRange; + if (const TypeSourceInfo *ResultTypeInfo = Method->getResultTypeSourceInfo()) + ResultTypeRange = ResultTypeInfo->getTypeLoc().getSourceRange(); + + // If an Objective-C method inherits its related result type, then its + // declared result type must be compatible with its own class type. The + // declared result type is compatible if: + if (const ObjCObjectPointerType *ResultObjectType + = ResultType->getAs<ObjCObjectPointerType>()) { + // - it is id or qualified id, or + if (ResultObjectType->isObjCIdType() || + ResultObjectType->isObjCQualifiedIdType()) + return false; + + if (CurrentClass) { + if (ObjCInterfaceDecl *ResultClass + = ResultObjectType->getInterfaceDecl()) { + // - it is the same as the method's class type, or + if (CurrentClass == ResultClass) + return false; + + // - it is a superclass of the method's class type + if (ResultClass->isSuperClassOf(CurrentClass)) + return false; + } + } + } + + return true; +} + +/// \brief Determine if any method in the global method pool has an inferred +/// result type. +static bool +anyMethodInfersRelatedResultType(Sema &S, Selector Sel, bool IsInstance) { + Sema::GlobalMethodPool::iterator Pos = S.MethodPool.find(Sel); + if (Pos == S.MethodPool.end()) { + if (S.ExternalSource) + Pos = S.ReadMethodPool(Sel); + else + return 0; + } + + ObjCMethodList &List = IsInstance ? Pos->second.first : Pos->second.second; + for (ObjCMethodList *M = &List; M; M = M->Next) { + if (M->Method && M->Method->hasRelatedResultType()) + return true; + } + + return false; +} + Decl *Sema::ActOnMethodDeclaration( Scope *S, SourceLocation MethodLoc, SourceLocation EndLoc, tok::TokenKind MethodType, Decl *ClassDecl, ObjCDeclSpec &ReturnQT, ParsedType ReturnType, + SourceLocation SelectorStartLoc, Selector Sel, // optional arguments. The number of types/arguments is obtained // from the Sel.getNumArgs(). @@ -1741,7 +1941,7 @@ Decl *Sema::ActOnMethodDeclaration( Diag(MethodLoc, diag::err_object_cannot_be_passed_returned_by_value) << 0 << resultDeclType; return 0; - } + } } else // get the type for "id". resultDeclType = Context.getObjCIdType(); @@ -1751,9 +1951,10 @@ Decl *Sema::ActOnMethodDeclaration( cast<DeclContext>(ClassDecl), MethodType == tok::minus, isVariadic, false, false, - MethodDeclKind == tok::objc_optional ? - ObjCMethodDecl::Optional : - ObjCMethodDecl::Required); + MethodDeclKind == tok::objc_optional + ? ObjCMethodDecl::Optional + : ObjCMethodDecl::Required, + false); llvm::SmallVector<ParmVarDecl*, 16> Params; @@ -1849,6 +2050,7 @@ Decl *Sema::ActOnMethodDeclaration( } InterfaceMD = ImpDecl->getClassInterface()->getMethod(Sel, MethodType == tok::minus); + if (ObjCMethod->hasAttrs() && containsInvalidMethodImplAttribute(ObjCMethod->getAttrs())) Diag(EndLoc, diag::warn_attribute_method_def); @@ -1861,6 +2063,10 @@ Decl *Sema::ActOnMethodDeclaration( PrevMethod = CatImpDecl->getClassMethod(Sel); CatImpDecl->addClassMethod(ObjCMethod); } + + if (ObjCCategoryDecl *Cat = CatImpDecl->getCategoryDecl()) + InterfaceMD = Cat->getMethod(Sel, MethodType == tok::minus); + if (ObjCMethod->hasAttrs() && containsInvalidMethodImplAttribute(ObjCMethod->getAttrs())) Diag(EndLoc, diag::warn_attribute_method_def); @@ -1874,10 +2080,65 @@ Decl *Sema::ActOnMethodDeclaration( Diag(PrevMethod->getLocation(), diag::note_previous_declaration); } + // If this Objective-C method does not have a related result type, but we + // are allowed to infer related result types, try to do so based on the + // method family. + ObjCInterfaceDecl *CurrentClass = dyn_cast<ObjCInterfaceDecl>(ClassDecl); + if (!CurrentClass) { + if (ObjCCategoryDecl *Cat = dyn_cast<ObjCCategoryDecl>(ClassDecl)) + CurrentClass = Cat->getClassInterface(); + else if (ObjCImplDecl *Impl = dyn_cast<ObjCImplDecl>(ClassDecl)) + CurrentClass = Impl->getClassInterface(); + else if (ObjCCategoryImplDecl *CatImpl + = dyn_cast<ObjCCategoryImplDecl>(ClassDecl)) + CurrentClass = CatImpl->getClassInterface(); + } + // Merge information down from the interface declaration if we have one. - if (InterfaceMD) + if (InterfaceMD) { + // Inherit the related result type, if we can. + if (InterfaceMD->hasRelatedResultType() && + !CheckRelatedResultTypeCompatibility(*this, ObjCMethod, CurrentClass)) + ObjCMethod->SetRelatedResultType(); + mergeObjCMethodDecls(ObjCMethod, InterfaceMD); - + } + + if (!ObjCMethod->hasRelatedResultType() && + getLangOptions().ObjCInferRelatedResultType) { + bool InferRelatedResultType = false; + switch (ObjCMethod->getMethodFamily()) { + case OMF_None: + case OMF_copy: + case OMF_dealloc: + case OMF_mutableCopy: + case OMF_release: + case OMF_retainCount: + break; + + case OMF_alloc: + case OMF_new: + InferRelatedResultType = ObjCMethod->isClassMethod(); + break; + + case OMF_init: + case OMF_autorelease: + case OMF_retain: + case OMF_self: + InferRelatedResultType = ObjCMethod->isInstanceMethod(); + break; + } + + if (InferRelatedResultType && + !CheckRelatedResultTypeCompatibility(*this, ObjCMethod, CurrentClass)) + ObjCMethod->SetRelatedResultType(); + + if (!InterfaceMD && + anyMethodInfersRelatedResultType(*this, ObjCMethod->getSelector(), + ObjCMethod->isInstanceMethod())) + CheckObjCMethodOverrides(ObjCMethod, cast<DeclContext>(ClassDecl)); + } + return ObjCMethod; } diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaExceptionSpec.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaExceptionSpec.cpp index f1033dc..7bcec31 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaExceptionSpec.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaExceptionSpec.cpp @@ -298,8 +298,6 @@ bool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID, // - both are non-throwing, regardless of their form, // - both have the form noexcept(constant-expression) and the constant- // expressions are equivalent, - // - one exception-specification is a noexcept-specification allowing all - // exceptions and the other is of the form throw(type-id-list), or // - both are dynamic-exception-specifications that have the same set of // adjusted types. // @@ -307,8 +305,6 @@ bool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID, // of the form throw(), noexcept, or noexcept(constant-expression) where the // constant-expression yields true. // - // CWG 1073 Proposed resolution: Strike the third bullet above. - // // C++0x [except.spec]p4: If any declaration of a function has an exception- // specifier that is not a noexcept-specification allowing all exceptions, // all declarations [...] of that function shall have a compatible @@ -320,6 +316,9 @@ bool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID, ExceptionSpecificationType OldEST = Old->getExceptionSpecType(); ExceptionSpecificationType NewEST = New->getExceptionSpecType(); + assert(OldEST != EST_Delayed && NewEST != EST_Delayed && + "Shouldn't see unknown exception specifications here"); + // Shortcut the case where both have no spec. if (OldEST == EST_None && NewEST == EST_None) return false; @@ -506,6 +505,9 @@ bool Sema::CheckExceptionSpecSubset( ExceptionSpecificationType SubEST = Subset->getExceptionSpecType(); + assert(SuperEST != EST_Delayed && SubEST != EST_Delayed && + "Shouldn't see unknown exception specifications here"); + // It does not. If the subset contains everything, we've failed. if (SubEST == EST_None || SubEST == EST_MSAny) { Diag(SubLoc, DiagID); @@ -701,7 +703,23 @@ bool Sema::CheckExceptionSpecCompatibility(Expr *From, QualType ToType) bool Sema::CheckOverridingFunctionExceptionSpec(const CXXMethodDecl *New, const CXXMethodDecl *Old) { - return CheckExceptionSpecSubset(PDiag(diag::err_override_exception_spec), + if (getLangOptions().CPlusPlus0x && isa<CXXDestructorDecl>(New)) { + // Don't check uninstantiated template destructors at all. We can only + // synthesize correct specs after the template is instantiated. + if (New->getParent()->isDependentType()) + return false; + if (New->getParent()->isBeingDefined()) { + // The destructor might be updated once the definition is finished. So + // remember it and check later. + DelayedDestructorExceptionSpecChecks.push_back(std::make_pair( + cast<CXXDestructorDecl>(New), cast<CXXDestructorDecl>(Old))); + return false; + } + } + unsigned DiagID = diag::err_override_exception_spec; + if (getLangOptions().Microsoft) + DiagID = diag::warn_override_exception_spec; + return CheckExceptionSpecSubset(PDiag(DiagID), PDiag(diag::note_overridden_virtual_function), Old->getType()->getAs<FunctionProtoType>(), Old->getLocation(), diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaExpr.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaExpr.cpp index 20b92b8..0549e94 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaExpr.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaExpr.cpp @@ -449,18 +449,58 @@ ExprResult Sema::DefaultVariadicArgumentPromotion(Expr *E, VariadicCallType CT, if (FDecl && FDecl->getBuiltinID() == Builtin::BI__builtin_va_start) return Owned(E); + // Don't allow one to pass an Objective-C interface to a vararg. if (E->getType()->isObjCObjectType() && - DiagRuntimeBehavior(E->getLocStart(), 0, - PDiag(diag::err_cannot_pass_objc_interface_to_vararg) - << E->getType() << CT)) + DiagRuntimeBehavior(E->getLocStart(), 0, + PDiag(diag::err_cannot_pass_objc_interface_to_vararg) + << E->getType() << CT)) return ExprError(); - - if (!E->getType()->isPODType() && - DiagRuntimeBehavior(E->getLocStart(), 0, + + if (!E->getType()->isPODType()) { + // C++0x [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. + bool TrivialEnough = false; + if (getLangOptions().CPlusPlus0x && !E->getType()->isDependentType()) { + if (CXXRecordDecl *Record = E->getType()->getAsCXXRecordDecl()) { + if (Record->hasTrivialCopyConstructor() && + Record->hasTrivialMoveConstructor() && + Record->hasTrivialDestructor()) + TrivialEnough = true; + } + } + + if (TrivialEnough) { + // Nothing to diagnose. This is okay. + } else if (DiagRuntimeBehavior(E->getLocStart(), 0, PDiag(diag::warn_cannot_pass_non_pod_arg_to_vararg) - << E->getType() << CT)) - return ExprError(); + << getLangOptions().CPlusPlus0x << E->getType() + << CT)) { + // Turn this into a trap. + CXXScopeSpec SS; + UnqualifiedId Name; + Name.setIdentifier(PP.getIdentifierInfo("__builtin_trap"), + E->getLocStart()); + ExprResult TrapFn = ActOnIdExpression(TUScope, SS, Name, true, false); + if (TrapFn.isInvalid()) + return ExprError(); + ExprResult Call = ActOnCallExpr(TUScope, TrapFn.get(), E->getLocStart(), + MultiExprArg(), E->getLocEnd()); + if (Call.isInvalid()) + return ExprError(); + + ExprResult Comma = ActOnBinOp(TUScope, E->getLocStart(), tok::comma, + Call.get(), E); + if (Comma.isInvalid()) + return ExprError(); + + E = Comma.get(); + } + } + return Owned(E); } @@ -1293,8 +1333,8 @@ Sema::BuildAnonymousStructUnionMemberReference(const CXXScopeSpec &SS, // We've found a member of an anonymous struct/union that is // inside a non-anonymous struct/union, so in a well-formed // program our base object expression is "this". - CXXMethodDecl *method = tryCaptureCXXThis(); - if (!method) { + QualType ThisTy = getAndCaptureCurrentThisType(); + if (ThisTy.isNull()) { Diag(loc, diag::err_invalid_member_use_in_static_method) << indirectField->getDeclName(); return ExprError(); @@ -1302,10 +1342,9 @@ Sema::BuildAnonymousStructUnionMemberReference(const CXXScopeSpec &SS, // Our base object expression is "this". baseObjectExpr = - new (Context) CXXThisExpr(loc, method->getThisType(Context), - /*isImplicit=*/ true); + new (Context) CXXThisExpr(loc, ThisTy, /*isImplicit=*/ true); baseObjectIsPointer = true; - baseQuals = Qualifiers::fromCVRMask(method->getTypeQualifiers()); + baseQuals = ThisTy->castAs<PointerType>()->getPointeeType().getQualifiers(); } // Build the implicit member references to the field of the @@ -1452,14 +1491,23 @@ enum IMAKind { /// conservatively answer "yes", in which case some errors will simply /// not be caught until template-instantiation. static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef, + Scope *CurScope, const LookupResult &R) { assert(!R.empty() && (*R.begin())->isCXXClassMember()); DeclContext *DC = SemaRef.getFunctionLevelDeclContext(); + bool isStaticContext = (!isa<CXXMethodDecl>(DC) || cast<CXXMethodDecl>(DC)->isStatic()); + // C++0x [expr.prim]p4: + // Otherwise, if a member-declarator declares a non-static data member + // of a class X, the expression this is a prvalue of type "pointer to X" + // within the optional brace-or-equal-initializer. + if (CurScope->getFlags() & Scope::ThisScope) + isStaticContext = false; + if (R.isUnresolvableResult()) return isStaticContext ? IMA_Unresolved_StaticContext : IMA_Unresolved; @@ -1507,8 +1555,11 @@ static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef, return IMA_Error_StaticContext; } - CXXRecordDecl * - contextClass = cast<CXXMethodDecl>(DC)->getParent()->getCanonicalDecl(); + CXXRecordDecl *contextClass; + if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(DC)) + contextClass = MD->getParent()->getCanonicalDecl(); + else + contextClass = cast<CXXRecordDecl>(DC); // [class.mfct.non-static]p3: // ...is used in the body of a non-static member function of class X, @@ -1986,7 +2037,7 @@ ExprResult Sema::BuildPossibleImplicitMemberExpr(const CXXScopeSpec &SS, LookupResult &R, const TemplateArgumentListInfo *TemplateArgs) { - switch (ClassifyImplicitMemberAccess(*this, R)) { + switch (ClassifyImplicitMemberAccess(*this, CurScope, R)) { case IMA_Instance: return BuildImplicitMemberExpr(SS, R, TemplateArgs, true); @@ -2429,19 +2480,18 @@ Sema::BuildImplicitMemberExpr(const CXXScopeSpec &SS, // If this is known to be an instance access, go ahead and build an // implicit 'this' expression now. // 'this' expression now. - CXXMethodDecl *method = tryCaptureCXXThis(); - assert(method && "didn't correctly pre-flight capture of 'this'"); + QualType ThisTy = getAndCaptureCurrentThisType(); + assert(!ThisTy.isNull() && "didn't correctly pre-flight capture of 'this'"); - QualType thisType = method->getThisType(Context); Expr *baseExpr = 0; // null signifies implicit access if (IsKnownInstance) { SourceLocation Loc = R.getNameLoc(); if (SS.getRange().isValid()) Loc = SS.getRange().getBegin(); - baseExpr = new (Context) CXXThisExpr(loc, thisType, /*isImplicit=*/true); + baseExpr = new (Context) CXXThisExpr(loc, ThisTy, /*isImplicit=*/true); } - return BuildMemberReferenceExpr(baseExpr, thisType, + return BuildMemberReferenceExpr(baseExpr, ThisTy, /*OpLoc*/ SourceLocation(), /*IsArrow*/ true, SS, @@ -3014,8 +3064,120 @@ ExprResult Sema::ActOnParenExpr(SourceLocation L, return Owned(new (Context) ParenExpr(L, R, E)); } +static bool CheckVecStepTraitOperandType(Sema &S, QualType T, + SourceLocation Loc, + SourceRange ArgRange) { + // [OpenCL 1.1 6.11.12] "The vec_step built-in function takes a built-in + // scalar or vector data type argument..." + // Every built-in scalar type (OpenCL 1.1 6.1.1) is either an arithmetic + // type (C99 6.2.5p18) or void. + if (!(T->isArithmeticType() || T->isVoidType() || T->isVectorType())) { + S.Diag(Loc, diag::err_vecstep_non_scalar_vector_type) + << T << ArgRange; + return true; + } + + assert((T->isVoidType() || !T->isIncompleteType()) && + "Scalar types should always be complete"); + return false; +} + +static bool CheckExtensionTraitOperandType(Sema &S, QualType T, + SourceLocation Loc, + SourceRange ArgRange, + UnaryExprOrTypeTrait TraitKind) { + // C99 6.5.3.4p1: + if (T->isFunctionType()) { + // alignof(function) is allowed as an extension. + if (TraitKind == UETT_SizeOf) + S.Diag(Loc, diag::ext_sizeof_function_type) << ArgRange; + return false; + } + + // Allow sizeof(void)/alignof(void) as an extension. + if (T->isVoidType()) { + S.Diag(Loc, diag::ext_sizeof_void_type) << TraitKind << ArgRange; + return false; + } + + return true; +} + +static bool CheckObjCTraitOperandConstraints(Sema &S, QualType T, + SourceLocation Loc, + SourceRange ArgRange, + UnaryExprOrTypeTrait TraitKind) { + // Reject sizeof(interface) and sizeof(interface<proto>) in 64-bit mode. + if (S.LangOpts.ObjCNonFragileABI && T->isObjCObjectType()) { + S.Diag(Loc, diag::err_sizeof_nonfragile_interface) + << T << (TraitKind == UETT_SizeOf) + << ArgRange; + return true; + } + + return false; +} + +/// \brief Check the constrains on expression operands to unary type expression +/// and type traits. +/// +/// Completes any types necessary and validates the constraints on the operand +/// expression. The logic mostly mirrors the type-based overload, but may modify +/// the expression as it completes the type for that expression through template +/// instantiation, etc. +bool Sema::CheckUnaryExprOrTypeTraitOperand(Expr *Op, + UnaryExprOrTypeTrait ExprKind) { + QualType ExprTy = Op->getType(); + + // C++ [expr.sizeof]p2: "When applied to a reference or a reference type, + // the result is the size of the referenced type." + // C++ [expr.alignof]p3: "When alignof is applied to a reference type, the + // result shall be the alignment of the referenced type." + if (const ReferenceType *Ref = ExprTy->getAs<ReferenceType>()) + ExprTy = Ref->getPointeeType(); + + if (ExprKind == UETT_VecStep) + return CheckVecStepTraitOperandType(*this, ExprTy, Op->getExprLoc(), + Op->getSourceRange()); + + // Whitelist some types as extensions + if (!CheckExtensionTraitOperandType(*this, ExprTy, Op->getExprLoc(), + Op->getSourceRange(), ExprKind)) + return false; + + if (RequireCompleteExprType(Op, + PDiag(diag::err_sizeof_alignof_incomplete_type) + << ExprKind << Op->getSourceRange(), + std::make_pair(SourceLocation(), PDiag(0)))) + return true; + + // Completeing the expression's type may have changed it. + ExprTy = Op->getType(); + if (const ReferenceType *Ref = ExprTy->getAs<ReferenceType>()) + ExprTy = Ref->getPointeeType(); + + if (CheckObjCTraitOperandConstraints(*this, ExprTy, Op->getExprLoc(), + Op->getSourceRange(), ExprKind)) + return true; + + return false; +} + +/// \brief Check the constraints on operands to unary expression and type +/// traits. +/// +/// This will complete any types necessary, and validate the various constraints +/// on those operands. +/// /// The UsualUnaryConversions() function is *not* called by this routine. -/// See C99 6.3.2.1p[2-4] for more details. +/// C99 6.3.2.1p[2-4] all state: +/// Except when it is the operand of the sizeof operator ... +/// +/// C++ [expr.sizeof]p4 +/// The lvalue-to-rvalue, array-to-pointer, and function-to-pointer +/// standard conversions are not applied to the operand of sizeof. +/// +/// This policy is followed for all of the unary trait expressions. bool Sema::CheckUnaryExprOrTypeTraitOperand(QualType exprType, SourceLocation OpLoc, SourceRange ExprRange, @@ -3030,55 +3192,27 @@ bool Sema::CheckUnaryExprOrTypeTraitOperand(QualType exprType, if (const ReferenceType *Ref = exprType->getAs<ReferenceType>()) exprType = Ref->getPointeeType(); - // [OpenCL 1.1 6.11.12] "The vec_step built-in function takes a built-in - // scalar or vector data type argument..." - // Every built-in scalar type (OpenCL 1.1 6.1.1) is either an arithmetic - // type (C99 6.2.5p18) or void. - if (ExprKind == UETT_VecStep) { - if (!(exprType->isArithmeticType() || exprType->isVoidType() || - exprType->isVectorType())) { - Diag(OpLoc, diag::err_vecstep_non_scalar_vector_type) - << exprType << ExprRange; - return true; - } - } + if (ExprKind == UETT_VecStep) + return CheckVecStepTraitOperandType(*this, exprType, OpLoc, ExprRange); - // C99 6.5.3.4p1: - if (exprType->isFunctionType()) { - // alignof(function) is allowed as an extension. - if (ExprKind == UETT_SizeOf) - Diag(OpLoc, diag::ext_sizeof_function_type) - << ExprRange; + // Whitelist some types as extensions + if (!CheckExtensionTraitOperandType(*this, exprType, OpLoc, ExprRange, + ExprKind)) return false; - } - - // Allow sizeof(void)/alignof(void) as an extension. vec_step(void) is not - // an extension, as void is a built-in scalar type (OpenCL 1.1 6.1.1). - if (exprType->isVoidType()) { - if (ExprKind != UETT_VecStep) - Diag(OpLoc, diag::ext_sizeof_void_type) - << ExprKind << ExprRange; - return false; - } if (RequireCompleteType(OpLoc, exprType, PDiag(diag::err_sizeof_alignof_incomplete_type) << ExprKind << ExprRange)) return true; - // Reject sizeof(interface) and sizeof(interface<proto>) in 64-bit mode. - if (LangOpts.ObjCNonFragileABI && exprType->isObjCObjectType()) { - Diag(OpLoc, diag::err_sizeof_nonfragile_interface) - << exprType << (ExprKind == UETT_SizeOf) - << ExprRange; + if (CheckObjCTraitOperandConstraints(*this, exprType, OpLoc, ExprRange, + ExprKind)) return true; - } return false; } -static bool CheckAlignOfExpr(Sema &S, Expr *E, SourceLocation OpLoc, - SourceRange ExprRange) { +static bool CheckAlignOfExpr(Sema &S, Expr *E) { E = E->IgnoreParens(); // alignof decl is always ok. @@ -3090,7 +3224,8 @@ static bool CheckAlignOfExpr(Sema &S, Expr *E, SourceLocation OpLoc, return false; if (E->getBitField()) { - S. Diag(OpLoc, diag::err_sizeof_alignof_bitfield) << 1 << ExprRange; + S.Diag(E->getExprLoc(), diag::err_sizeof_alignof_bitfield) + << 1 << E->getSourceRange(); return true; } @@ -3100,20 +3235,17 @@ static bool CheckAlignOfExpr(Sema &S, Expr *E, SourceLocation OpLoc, if (isa<FieldDecl>(ME->getMemberDecl())) return false; - return S.CheckUnaryExprOrTypeTraitOperand(E->getType(), OpLoc, ExprRange, - UETT_AlignOf); + return S.CheckUnaryExprOrTypeTraitOperand(E, UETT_AlignOf); } -bool Sema::CheckVecStepExpr(Expr *E, SourceLocation OpLoc, - SourceRange ExprRange) { +bool Sema::CheckVecStepExpr(Expr *E) { E = E->IgnoreParens(); // Cannot know anything else if the expression is dependent. if (E->isTypeDependent()) return false; - return CheckUnaryExprOrTypeTraitOperand(E->getType(), OpLoc, ExprRange, - UETT_VecStep); + return CheckUnaryExprOrTypeTraitOperand(E, UETT_VecStep); } /// \brief Build a sizeof or alignof expression given a type operand. @@ -3141,35 +3273,33 @@ Sema::CreateUnaryExprOrTypeTraitExpr(TypeSourceInfo *TInfo, /// operand. ExprResult Sema::CreateUnaryExprOrTypeTraitExpr(Expr *E, SourceLocation OpLoc, - UnaryExprOrTypeTrait ExprKind, - SourceRange R) { + UnaryExprOrTypeTrait ExprKind) { // Verify that the operand is valid. bool isInvalid = false; if (E->isTypeDependent()) { // Delay type-checking for type-dependent expressions. } else if (ExprKind == UETT_AlignOf) { - isInvalid = CheckAlignOfExpr(*this, E, OpLoc, R); + isInvalid = CheckAlignOfExpr(*this, E); } else if (ExprKind == UETT_VecStep) { - isInvalid = CheckVecStepExpr(E, OpLoc, R); + isInvalid = CheckVecStepExpr(E); } else if (E->getBitField()) { // C99 6.5.3.4p1. - Diag(OpLoc, diag::err_sizeof_alignof_bitfield) << 0; + Diag(E->getExprLoc(), diag::err_sizeof_alignof_bitfield) << 0; isInvalid = true; } else if (E->getType()->isPlaceholderType()) { ExprResult PE = CheckPlaceholderExpr(E); if (PE.isInvalid()) return ExprError(); - return CreateUnaryExprOrTypeTraitExpr(PE.take(), OpLoc, ExprKind, R); + return CreateUnaryExprOrTypeTraitExpr(PE.take(), OpLoc, ExprKind); } else { - isInvalid = CheckUnaryExprOrTypeTraitOperand(E->getType(), OpLoc, R, - UETT_SizeOf); + isInvalid = CheckUnaryExprOrTypeTraitOperand(E, UETT_SizeOf); } if (isInvalid) return ExprError(); // C99 6.5.3.4p4: the type (an unsigned integer type) is size_t. - return Owned(new (Context) UnaryExprOrTypeTraitExpr(ExprKind, E, - Context.getSizeType(), - OpLoc, R.getEnd())); + return Owned(new (Context) UnaryExprOrTypeTraitExpr( + ExprKind, E, Context.getSizeType(), OpLoc, + E->getSourceRange().getEnd())); } /// ActOnUnaryExprOrTypeTraitExpr - Handle @c sizeof(type) and @c sizeof @c @@ -3189,10 +3319,7 @@ Sema::ActOnUnaryExprOrTypeTraitExpr(SourceLocation OpLoc, } Expr *ArgEx = (Expr *)TyOrEx; - ExprResult Result - = CreateUnaryExprOrTypeTraitExpr(ArgEx, OpLoc, ExprKind, - ArgEx->getSourceRange()); - + ExprResult Result = CreateUnaryExprOrTypeTraitExpr(ArgEx, OpLoc, ExprKind); return move(Result); } @@ -4211,7 +4338,11 @@ Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr, if (DiagnoseUseOfDecl(PD, MemberLoc)) return ExprError(); - return Owned(new (Context) ObjCPropertyRefExpr(PD, PD->getType(), + QualType T = PD->getType(); + if (ObjCMethodDecl *Getter = PD->getGetterMethodDecl()) + T = getMessageSendResultType(BaseType, Getter, false, false); + + return Owned(new (Context) ObjCPropertyRefExpr(PD, T, VK_LValue, OK_ObjCProperty, MemberLoc, @@ -4229,7 +4360,8 @@ Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr, if (Decl *SDecl = FindGetterSetterNameDecl(OPT, /*Property id*/0, SetterSel, Context)) SMD = dyn_cast<ObjCMethodDecl>(SDecl); - QualType PType = OMD->getSendResultType(); + QualType PType = getMessageSendResultType(BaseType, OMD, false, + false); ExprValueKind VK = VK_LValue; if (!getLangOptions().CPlusPlus && @@ -4297,7 +4429,8 @@ Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr, ExprValueKind VK = VK_LValue; if (Getter) { - PType = Getter->getSendResultType(); + PType = getMessageSendResultType(QualType(OT, 0), Getter, true, + false); if (!getLangOptions().CPlusPlus && IsCForbiddenLValueType(Context, PType)) VK = VK_RValue; @@ -4377,120 +4510,52 @@ Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr, // If the user is trying to apply -> or . to a function name, it's probably // because they forgot parentheses to call that function. - bool TryCall = false; - bool Overloaded = false; - UnresolvedSet<8> AllOverloads; - if (const OverloadExpr *Overloads = dyn_cast<OverloadExpr>(BaseExpr.get())) { - AllOverloads.append(Overloads->decls_begin(), Overloads->decls_end()); - TryCall = true; - Overloaded = true; - } else if (DeclRefExpr *DeclRef = dyn_cast<DeclRefExpr>(BaseExpr.get())) { - if (FunctionDecl* Fun = dyn_cast<FunctionDecl>(DeclRef->getDecl())) { - AllOverloads.addDecl(Fun); - TryCall = true; - } - } - - if (TryCall) { - // Plunder the overload set for something that would make the member - // expression valid. - UnresolvedSet<4> ViableOverloads; - bool HasViableZeroArgOverload = false; - for (OverloadExpr::decls_iterator it = AllOverloads.begin(), - DeclsEnd = AllOverloads.end(); it != DeclsEnd; ++it) { - // Our overload set may include TemplateDecls, which we'll ignore for the - // purposes of determining whether we can issue a '()' fixit. - if (const FunctionDecl *OverloadDecl = dyn_cast<FunctionDecl>(*it)) { - QualType ResultTy = OverloadDecl->getResultType(); - if ((!IsArrow && ResultTy->isRecordType()) || - (IsArrow && ResultTy->isPointerType() && - ResultTy->getPointeeType()->isRecordType())) { - ViableOverloads.addDecl(*it); - if (OverloadDecl->getMinRequiredArguments() == 0) { - HasViableZeroArgOverload = true; - } - } - } - } - - if (!HasViableZeroArgOverload || ViableOverloads.size() != 1) { + QualType ZeroArgCallTy; + UnresolvedSet<4> Overloads; + if (isExprCallable(*BaseExpr.get(), ZeroArgCallTy, Overloads)) { + if (ZeroArgCallTy.isNull()) { Diag(BaseExpr.get()->getExprLoc(), diag::err_member_reference_needs_call) - << (AllOverloads.size() > 1) << 0 - << BaseExpr.get()->getSourceRange(); - int ViableOverloadCount = ViableOverloads.size(); - int I; - for (I = 0; I < ViableOverloadCount; ++I) { - // FIXME: Magic number for max shown overloads stolen from - // OverloadCandidateSet::NoteCandidates. - if (I >= 4 && Diags.getShowOverloads() == Diagnostic::Ovl_Best) { - break; - } - Diag(ViableOverloads[I].getDecl()->getSourceRange().getBegin(), - diag::note_member_ref_possible_intended_overload); - } - if (I != ViableOverloadCount) { - Diag(BaseExpr.get()->getExprLoc(), diag::note_ovl_too_many_candidates) - << int(ViableOverloadCount - I); + << (Overloads.size() > 1) << 0 << BaseExpr.get()->getSourceRange(); + UnresolvedSet<2> PlausibleOverloads; + for (OverloadExpr::decls_iterator It = Overloads.begin(), + DeclsEnd = Overloads.end(); It != DeclsEnd; ++It) { + const FunctionDecl *OverloadDecl = cast<FunctionDecl>(*It); + QualType OverloadResultTy = OverloadDecl->getResultType(); + if ((!IsArrow && OverloadResultTy->isRecordType()) || + (IsArrow && OverloadResultTy->isPointerType() && + OverloadResultTy->getPointeeType()->isRecordType())) + PlausibleOverloads.addDecl(It.getDecl()); } + NoteOverloads(PlausibleOverloads, BaseExpr.get()->getExprLoc()); return ExprError(); } - } else { - // We don't have an expression that's convenient to get a Decl from, but we - // can at least check if the type is "function of 0 arguments which returns - // an acceptable type". - const FunctionType *Fun = NULL; - if (const PointerType *Ptr = BaseType->getAs<PointerType>()) { - if ((Fun = Ptr->getPointeeType()->getAs<FunctionType>())) { - TryCall = true; - } - } else if ((Fun = BaseType->getAs<FunctionType>())) { - TryCall = true; - } else if (BaseType == Context.BoundMemberTy) { - // Look for the bound-member type. If it's still overloaded, - // give up, although we probably should have fallen into the - // OverloadExpr case above if we actually have an overloaded - // bound member. - QualType fnType = Expr::findBoundMemberType(BaseExpr.get()); - if (!fnType.isNull()) { - TryCall = true; - Fun = fnType->castAs<FunctionType>(); - } - } - - if (TryCall) { - if (const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(Fun)) { - if (FPT->getNumArgs() == 0) { - QualType ResultTy = Fun->getResultType(); - TryCall = (!IsArrow && ResultTy->isRecordType()) || - (IsArrow && ResultTy->isPointerType() && - ResultTy->getPointeeType()->isRecordType()); - } - } + if ((!IsArrow && ZeroArgCallTy->isRecordType()) || + (IsArrow && ZeroArgCallTy->isPointerType() && + ZeroArgCallTy->getPointeeType()->isRecordType())) { + // At this point, we know BaseExpr looks like it's potentially callable + // with 0 arguments, and that it returns something of a reasonable type, + // so we can emit a fixit and carry on pretending that BaseExpr was + // actually a CallExpr. + SourceLocation ParenInsertionLoc = + PP.getLocForEndOfToken(BaseExpr.get()->getLocEnd()); + Diag(BaseExpr.get()->getExprLoc(), diag::err_member_reference_needs_call) + << (Overloads.size() > 1) << 1 << BaseExpr.get()->getSourceRange() + << FixItHint::CreateInsertion(ParenInsertionLoc, "()"); + // FIXME: Try this before emitting the fixit, and suppress diagnostics + // while doing so. + ExprResult NewBase = + ActOnCallExpr(0, BaseExpr.take(), ParenInsertionLoc, + MultiExprArg(*this, 0, 0), + ParenInsertionLoc.getFileLocWithOffset(1)); + if (NewBase.isInvalid()) + return ExprError(); + BaseExpr = NewBase; + BaseExpr = DefaultFunctionArrayConversion(BaseExpr.take()); + return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS, + ObjCImpDecl, HasTemplateArgs); } } - if (TryCall) { - // At this point, we know BaseExpr looks like it's potentially callable with - // 0 arguments, and that it returns something of a reasonable type, so we - // can emit a fixit and carry on pretending that BaseExpr was actually a - // CallExpr. - SourceLocation ParenInsertionLoc = - PP.getLocForEndOfToken(BaseExpr.get()->getLocEnd()); - Diag(BaseExpr.get()->getExprLoc(), diag::err_member_reference_needs_call) - << int(Overloaded) << 1 - << BaseExpr.get()->getSourceRange() - << FixItHint::CreateInsertion(ParenInsertionLoc, "()"); - ExprResult NewBase = ActOnCallExpr(0, BaseExpr.take(), ParenInsertionLoc, - MultiExprArg(*this, 0, 0), - ParenInsertionLoc); - if (NewBase.isInvalid()) - return ExprError(); - BaseExpr = NewBase; - BaseExpr = DefaultFunctionArrayConversion(BaseExpr.take()); - return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS, - ObjCImpDecl, HasTemplateArgs); - } - Diag(MemberLoc, diag::err_typecheck_member_reference_struct_union) << BaseType << BaseExpr.get()->getSourceRange(); @@ -4946,6 +5011,26 @@ Sema::ActOnCUDAExecConfigExpr(Scope *S, SourceLocation LLLLoc, return ActOnCallExpr(S, ConfigDR, LLLLoc, execConfig, GGGLoc, 0); } +/// ActOnAsTypeExpr - create a new asType (bitcast) from the arguments. +/// +/// __builtin_astype( value, dst type ) +/// +ExprResult Sema::ActOnAsTypeExpr(Expr *expr, ParsedType destty, + SourceLocation BuiltinLoc, + SourceLocation RParenLoc) { + ExprValueKind VK = VK_RValue; + ExprObjectKind OK = OK_Ordinary; + QualType DstTy = GetTypeFromParser(destty); + QualType SrcTy = expr->getType(); + if (Context.getTypeSize(DstTy) != Context.getTypeSize(SrcTy)) + return ExprError(Diag(BuiltinLoc, + diag::err_invalid_astype_of_different_size) + << DstTy + << SrcTy + << expr->getSourceRange()); + return Owned(new (Context) AsTypeExpr(expr, DstTy, VK, OK, BuiltinLoc, RParenLoc)); +} + /// BuildResolvedCallExpr - Build a call to a resolved expression, /// i.e. an expression not of \p OverloadTy. The expression should /// unary-convert to an expression of function-pointer or @@ -6118,6 +6203,150 @@ QualType Sema::FindCompositeObjCPointerType(ExprResult &LHS, ExprResult &RHS, return QualType(); } +/// SuggestParentheses - Emit a diagnostic together with a fixit hint that wraps +/// ParenRange in parentheses. +static void SuggestParentheses(Sema &Self, SourceLocation Loc, + const PartialDiagnostic &PD, + const PartialDiagnostic &FirstNote, + SourceRange FirstParenRange, + const PartialDiagnostic &SecondNote, + SourceRange SecondParenRange) { + Self.Diag(Loc, PD); + + if (!FirstNote.getDiagID()) + return; + + SourceLocation EndLoc = Self.PP.getLocForEndOfToken(FirstParenRange.getEnd()); + if (!FirstParenRange.getEnd().isFileID() || EndLoc.isInvalid()) { + // We can't display the parentheses, so just return. + return; + } + + Self.Diag(Loc, FirstNote) + << FixItHint::CreateInsertion(FirstParenRange.getBegin(), "(") + << FixItHint::CreateInsertion(EndLoc, ")"); + + if (!SecondNote.getDiagID()) + return; + + EndLoc = Self.PP.getLocForEndOfToken(SecondParenRange.getEnd()); + if (!SecondParenRange.getEnd().isFileID() || EndLoc.isInvalid()) { + // We can't display the parentheses, so just dig the + // warning/error and return. + Self.Diag(Loc, SecondNote); + return; + } + + Self.Diag(Loc, SecondNote) + << FixItHint::CreateInsertion(SecondParenRange.getBegin(), "(") + << FixItHint::CreateInsertion(EndLoc, ")"); +} + +static bool IsArithmeticOp(BinaryOperatorKind Opc) { + return Opc >= BO_Mul && Opc <= BO_Shr; +} + +/// IsArithmeticBinaryExpr - Returns true if E is an arithmetic binary +/// expression, either using a built-in or overloaded operator, +/// and sets *OpCode to the opcode and *RHS to the right-hand side expression. +static bool IsArithmeticBinaryExpr(Expr *E, BinaryOperatorKind *Opcode, + Expr **RHS) { + E = E->IgnoreParenImpCasts(); + E = E->IgnoreConversionOperator(); + E = E->IgnoreParenImpCasts(); + + // Built-in binary operator. + if (BinaryOperator *OP = dyn_cast<BinaryOperator>(E)) { + if (IsArithmeticOp(OP->getOpcode())) { + *Opcode = OP->getOpcode(); + *RHS = OP->getRHS(); + return true; + } + } + + // Overloaded operator. + if (CXXOperatorCallExpr *Call = dyn_cast<CXXOperatorCallExpr>(E)) { + if (Call->getNumArgs() != 2) + return false; + + // Make sure this is really a binary operator that is safe to pass into + // BinaryOperator::getOverloadedOpcode(), e.g. it's not a subscript op. + OverloadedOperatorKind OO = Call->getOperator(); + if (OO < OO_Plus || OO > OO_Arrow) + return false; + + BinaryOperatorKind OpKind = BinaryOperator::getOverloadedOpcode(OO); + if (IsArithmeticOp(OpKind)) { + *Opcode = OpKind; + *RHS = Call->getArg(1); + return true; + } + } + + return false; +} + +static bool IsLogicOp(BinaryOperatorKind Opc) { + return (Opc >= BO_LT && Opc <= BO_NE) || (Opc >= BO_LAnd && Opc <= BO_LOr); +} + +/// ExprLooksBoolean - Returns true if E looks boolean, i.e. it has boolean type +/// or is a logical expression such as (x==y) which has int type, but is +/// commonly interpreted as boolean. +static bool ExprLooksBoolean(Expr *E) { + E = E->IgnoreParenImpCasts(); + + if (E->getType()->isBooleanType()) + return true; + if (BinaryOperator *OP = dyn_cast<BinaryOperator>(E)) + return IsLogicOp(OP->getOpcode()); + if (UnaryOperator *OP = dyn_cast<UnaryOperator>(E)) + return OP->getOpcode() == UO_LNot; + + return false; +} + +/// DiagnoseConditionalPrecedence - Emit a warning when a conditional operator +/// and binary operator are mixed in a way that suggests the programmer assumed +/// the conditional operator has higher precedence, for example: +/// "int x = a + someBinaryCondition ? 1 : 2". +static void DiagnoseConditionalPrecedence(Sema &Self, + SourceLocation OpLoc, + Expr *cond, + Expr *lhs, + Expr *rhs) { + BinaryOperatorKind CondOpcode; + Expr *CondRHS; + + if (!IsArithmeticBinaryExpr(cond, &CondOpcode, &CondRHS)) + return; + if (!ExprLooksBoolean(CondRHS)) + return; + + // The condition is an arithmetic binary expression, with a right- + // hand side that looks boolean, so warn. + + PartialDiagnostic Warn = Self.PDiag(diag::warn_precedence_conditional) + << cond->getSourceRange() + << BinaryOperator::getOpcodeStr(CondOpcode); + + PartialDiagnostic FirstNote = + Self.PDiag(diag::note_precedence_conditional_silence) + << BinaryOperator::getOpcodeStr(CondOpcode); + + SourceRange FirstParenRange(cond->getLocStart(), + cond->getLocEnd()); + + PartialDiagnostic SecondNote = + Self.PDiag(diag::note_precedence_conditional_first); + + SourceRange SecondParenRange(CondRHS->getLocStart(), + rhs->getLocEnd()); + + SuggestParentheses(Self, OpLoc, Warn, FirstNote, FirstParenRange, + SecondNote, SecondParenRange); +} + /// ActOnConditionalOp - Parse a ?: operation. Note that 'LHS' may be null /// in the case of a the GNU conditional expr extension. ExprResult Sema::ActOnConditionalOp(SourceLocation QuestionLoc, @@ -6162,6 +6391,9 @@ ExprResult Sema::ActOnConditionalOp(SourceLocation QuestionLoc, RHS.isInvalid()) return ExprError(); + DiagnoseConditionalPrecedence(*this, QuestionLoc, Cond.get(), LHS.get(), + RHS.get()); + if (!commonExpr) return Owned(new (Context) ConditionalOperator(Cond.take(), QuestionLoc, LHS.take(), ColonLoc, @@ -7487,7 +7719,7 @@ QualType Sema::CheckCompareOperands(ExprResult &lex, ExprResult &rex, SourceLoca // Comparison of pointers with null pointer constants and equality // comparisons of member pointers to null pointer constants. if (RHSIsNull && - ((lType->isPointerType() || lType->isNullPtrType()) || + ((lType->isAnyPointerType() || lType->isNullPtrType()) || (!isRelational && lType->isMemberPointerType()))) { rex = ImpCastExprToType(rex.take(), lType, lType->isMemberPointerType() @@ -7496,7 +7728,7 @@ QualType Sema::CheckCompareOperands(ExprResult &lex, ExprResult &rex, SourceLoca return ResultTy; } if (LHSIsNull && - ((rType->isPointerType() || rType->isNullPtrType()) || + ((rType->isAnyPointerType() || rType->isNullPtrType()) || (!isRelational && rType->isMemberPointerType()))) { lex = ImpCastExprToType(lex.take(), rType, rType->isMemberPointerType() @@ -7748,13 +7980,15 @@ inline QualType Sema::CheckLogicalOperands( // C99 6.5.[13,14] // If the RHS can be constant folded, and if it constant folds to something // that isn't 0 or 1 (which indicate a potential logical operation that // happened to fold to true/false) then warn. + // Parens on the RHS are ignored. Expr::EvalResult Result; - if (rex.get()->Evaluate(Result, Context) && !Result.HasSideEffects && - Result.Val.getInt() != 0 && Result.Val.getInt() != 1) { - Diag(Loc, diag::warn_logical_instead_of_bitwise) - << rex.get()->getSourceRange() - << (Opc == BO_LAnd ? "&&" : "||") - << (Opc == BO_LAnd ? "&" : "|"); + if (rex.get()->Evaluate(Result, Context) && !Result.HasSideEffects) + if ((getLangOptions().Bool && !rex.get()->getType()->isBooleanType()) || + (Result.Val.getInt() != 0 && Result.Val.getInt() != 1)) { + Diag(Loc, diag::warn_logical_instead_of_bitwise) + << rex.get()->getSourceRange() + << (Opc == BO_LAnd ? "&&" : "||") + << (Opc == BO_LAnd ? "&" : "|"); } } @@ -8127,20 +8361,31 @@ ExprResult Sema::ConvertPropertyForRValue(Expr *E) { E->getObjectKind() == OK_ObjCProperty); const ObjCPropertyRefExpr *PRE = E->getObjCProperty(); + QualType T = E->getType(); + QualType ReceiverType; + if (PRE->isObjectReceiver()) + ReceiverType = PRE->getBase()->getType(); + else if (PRE->isSuperReceiver()) + ReceiverType = PRE->getSuperReceiverType(); + else + ReceiverType = Context.getObjCInterfaceType(PRE->getClassReceiver()); + ExprValueKind VK = VK_RValue; if (PRE->isImplicitProperty()) { - if (const ObjCMethodDecl *GetterMethod = + if (ObjCMethodDecl *GetterMethod = PRE->getImplicitPropertyGetter()) { - QualType Result = GetterMethod->getResultType(); - VK = Expr::getValueKindForType(Result); + T = getMessageSendResultType(ReceiverType, GetterMethod, + PRE->isClassReceiver(), + PRE->isSuperReceiver()); + VK = Expr::getValueKindForType(GetterMethod->getResultType()); } else { Diag(PRE->getLocation(), diag::err_getter_not_found) << PRE->getBase()->getType(); } } - - E = ImplicitCastExpr::Create(Context, E->getType(), CK_GetObjCProperty, + + E = ImplicitCastExpr::Create(Context, T, CK_GetObjCProperty, E, 0, VK); ExprResult Result = MaybeBindToTemporary(E); @@ -8404,7 +8649,13 @@ static QualType CheckIndirectionOperand(Sema &S, Expr *Op, ExprValueKind &VK, Op = ConvResult.take(); QualType OpTy = Op->getType(); QualType Result; - + + if (isa<CXXReinterpretCastExpr>(Op)) { + QualType OpOrigType = Op->IgnoreParenCasts()->getType(); + S.CheckCompatibleReinterpretCast(OpOrigType, OpTy, /*IsDereference*/true, + Op->getSourceRange()); + } + // Note that per both C89 and C99, indirection is always legal, even if OpTy // is an incomplete type or void. It would be possible to warn about // dereferencing a void pointer, but it's completely well-defined, and such a @@ -8678,45 +8929,6 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, CompResultTy, OpLoc)); } -/// SuggestParentheses - Emit a diagnostic together with a fixit hint that wraps -/// ParenRange in parentheses. -static void SuggestParentheses(Sema &Self, SourceLocation Loc, - const PartialDiagnostic &PD, - const PartialDiagnostic &FirstNote, - SourceRange FirstParenRange, - const PartialDiagnostic &SecondNote, - SourceRange SecondParenRange) { - Self.Diag(Loc, PD); - - if (!FirstNote.getDiagID()) - return; - - SourceLocation EndLoc = Self.PP.getLocForEndOfToken(FirstParenRange.getEnd()); - if (!FirstParenRange.getEnd().isFileID() || EndLoc.isInvalid()) { - // We can't display the parentheses, so just return. - return; - } - - Self.Diag(Loc, FirstNote) - << FixItHint::CreateInsertion(FirstParenRange.getBegin(), "(") - << FixItHint::CreateInsertion(EndLoc, ")"); - - if (!SecondNote.getDiagID()) - return; - - EndLoc = Self.PP.getLocForEndOfToken(SecondParenRange.getEnd()); - if (!SecondParenRange.getEnd().isFileID() || EndLoc.isInvalid()) { - // We can't display the parentheses, so just dig the - // warning/error and return. - Self.Diag(Loc, SecondNote); - return; - } - - Self.Diag(Loc, SecondNote) - << FixItHint::CreateInsertion(SecondParenRange.getBegin(), "(") - << FixItHint::CreateInsertion(EndLoc, ")"); -} - /// DiagnoseBitwisePrecedence - Emit a warning when bitwise and comparison /// operators are mixed in a way that suggests that the programmer forgot that /// comparison operators have higher precedence. The most typical example of @@ -9666,6 +9878,7 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy, *Complained = false; // Decode the result (notice that AST's are still created for extensions). + bool CheckInferredResultType = false; bool isInvalid = false; unsigned DiagKind; FixItHint Hint; @@ -9682,6 +9895,8 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy, case IncompatiblePointer: MakeObjCStringLiteralFixItHint(*this, DstType, SrcExpr, Hint); DiagKind = diag::ext_typecheck_convert_incompatible_pointer; + CheckInferredResultType = DstType->isObjCObjectPointerType() && + SrcType->isObjCObjectPointerType(); break; case IncompatiblePointerSign: DiagKind = diag::ext_typecheck_convert_incompatible_pointer_sign; @@ -9763,6 +9978,9 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy, Diag(Loc, DiagKind) << FirstType << SecondType << Action << SrcExpr->getSourceRange() << Hint; + if (CheckInferredResultType) + EmitRelatedResultTypeNote(SrcExpr); + if (Complained) *Complained = true; return isInvalid; @@ -9914,26 +10132,25 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) { // Note that this declaration has been used. if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) { - unsigned TypeQuals; - if (Constructor->isImplicit() && Constructor->isDefaultConstructor()) { - if (Constructor->getParent()->hasTrivialConstructor()) + if (Constructor->isDefaulted() && Constructor->isDefaultConstructor()) { + if (Constructor->isTrivial()) return; if (!Constructor->isUsed(false)) DefineImplicitDefaultConstructor(Loc, Constructor); - } else if (Constructor->isImplicit() && - Constructor->isCopyConstructor(TypeQuals)) { + } else if (Constructor->isDefaulted() && + Constructor->isCopyConstructor()) { if (!Constructor->isUsed(false)) - DefineImplicitCopyConstructor(Loc, Constructor, TypeQuals); + DefineImplicitCopyConstructor(Loc, Constructor); } MarkVTableUsed(Loc, Constructor->getParent()); } else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(D)) { - if (Destructor->isImplicit() && !Destructor->isUsed(false)) + if (Destructor->isDefaulted() && !Destructor->isUsed(false)) DefineImplicitDestructor(Loc, Destructor); if (Destructor->isVirtual()) MarkVTableUsed(Loc, Destructor->getParent()); } else if (CXXMethodDecl *MethodDecl = dyn_cast<CXXMethodDecl>(D)) { - if (MethodDecl->isImplicit() && MethodDecl->isOverloadedOperator() && + if (MethodDecl->isDefaulted() && MethodDecl->isOverloadedOperator() && MethodDecl->getOverloadedOperator() == OO_Equal) { if (!MethodDecl->isUsed(false)) DefineImplicitCopyAssignment(Loc, MethodDecl); diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaExprCXX.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaExprCXX.cpp index 7f1bf59..2f5a890 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaExprCXX.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaExprCXX.cpp @@ -17,6 +17,7 @@ #include "clang/Sema/Lookup.h" #include "clang/Sema/ParsedTemplate.h" #include "clang/Sema/ScopeInfo.h" +#include "clang/Sema/Scope.h" #include "clang/Sema/TemplateDeduction.h" #include "clang/AST/ASTContext.h" #include "clang/AST/CXXInheritance.h" @@ -385,13 +386,14 @@ static UuidAttr *GetUuidAttrOfType(QualType QT) { else if (QT->isArrayType()) Ty = cast<ArrayType>(QT)->getElementType().getTypePtr(); - // Loop all class definition and declaration looking for an uuid attribute. + // Loop all record redeclaration looking for an uuid attribute. CXXRecordDecl *RD = Ty->getAsCXXRecordDecl(); - while (RD) { - if (UuidAttr *Uuid = RD->getAttr<UuidAttr>()) + for (CXXRecordDecl::redecl_iterator I = RD->redecls_begin(), + E = RD->redecls_end(); I != E; ++I) { + if (UuidAttr *Uuid = I->getAttr<UuidAttr>()) return Uuid; - RD = RD->getPreviousDeclaration(); } + return 0; } @@ -574,42 +576,54 @@ ExprResult Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *E) { return Owned(E); } -CXXMethodDecl *Sema::tryCaptureCXXThis() { +QualType Sema::getAndCaptureCurrentThisType() { // Ignore block scopes: we can capture through them. // Ignore nested enum scopes: we'll diagnose non-constant expressions // where they're invalid, and other uses are legitimate. // Don't ignore nested class scopes: you can't use 'this' in a local class. DeclContext *DC = CurContext; + unsigned NumBlocks = 0; while (true) { - if (isa<BlockDecl>(DC)) DC = cast<BlockDecl>(DC)->getDeclContext(); - else if (isa<EnumDecl>(DC)) DC = cast<EnumDecl>(DC)->getDeclContext(); + if (isa<BlockDecl>(DC)) { + DC = cast<BlockDecl>(DC)->getDeclContext(); + ++NumBlocks; + } else if (isa<EnumDecl>(DC)) + DC = cast<EnumDecl>(DC)->getDeclContext(); else break; } - // If we're not in an instance method, error out. - CXXMethodDecl *method = dyn_cast<CXXMethodDecl>(DC); - if (!method || !method->isInstance()) - return 0; + QualType ThisTy; + if (CXXMethodDecl *method = dyn_cast<CXXMethodDecl>(DC)) { + if (method && method->isInstance()) + ThisTy = method->getThisType(Context); + } else if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(DC)) { + // C++0x [expr.prim]p4: + // Otherwise, if a member-declarator declares a non-static data member + // of a class X, the expression this is a prvalue of type "pointer to X" + // within the optional brace-or-equal-initializer. + Scope *S = getScopeForContext(DC); + if (!S || S->getFlags() & Scope::ThisScope) + ThisTy = Context.getPointerType(Context.getRecordType(RD)); + } - // Mark that we're closing on 'this' in all the block scopes, if applicable. - for (unsigned idx = FunctionScopes.size() - 1; - isa<BlockScopeInfo>(FunctionScopes[idx]); - --idx) - cast<BlockScopeInfo>(FunctionScopes[idx])->CapturesCXXThis = true; + // Mark that we're closing on 'this' in all the block scopes we ignored. + if (!ThisTy.isNull()) + for (unsigned idx = FunctionScopes.size() - 1; + NumBlocks; --idx, --NumBlocks) + cast<BlockScopeInfo>(FunctionScopes[idx])->CapturesCXXThis = true; - return method; + return ThisTy; } -ExprResult Sema::ActOnCXXThis(SourceLocation loc) { +ExprResult Sema::ActOnCXXThis(SourceLocation Loc) { /// C++ 9.3.2: In the body of a non-static member function, the keyword this /// is a non-lvalue expression whose value is the address of the object for /// which the function is called. - CXXMethodDecl *method = tryCaptureCXXThis(); - if (!method) return Diag(loc, diag::err_invalid_this_use); + QualType ThisTy = getAndCaptureCurrentThisType(); + if (ThisTy.isNull()) return Diag(Loc, diag::err_invalid_this_use); - return Owned(new (Context) CXXThisExpr(loc, method->getThisType(Context), - /*isImplicit=*/false)); + return Owned(new (Context) CXXThisExpr(Loc, ThisTy, /*isImplicit=*/false)); } ExprResult @@ -950,8 +964,8 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, } } - ArraySize = ImpCastExprToType(ArraySize, Context.getSizeType(), - CK_IntegralCast).take(); + // Note that we do *not* convert the argument in any way. It can + // be signed, larger than size_t, whatever. } FunctionDecl *OperatorNew = 0; @@ -1326,11 +1340,12 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range, DeclarationName Name, Expr** Args, unsigned NumArgs, DeclContext *Ctx, - bool AllowMissing, FunctionDecl *&Operator) { + bool AllowMissing, FunctionDecl *&Operator, + bool Diagnose) { LookupResult R(*this, Name, StartLoc, LookupOrdinaryName); LookupQualifiedName(R, Ctx); if (R.empty()) { - if (AllowMissing) + if (AllowMissing || !Diagnose) return false; return Diag(StartLoc, diag::err_ovl_no_viable_function_in_call) << Name << Range; @@ -1374,41 +1389,50 @@ bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range, // Watch out for variadic allocator function. unsigned NumArgsInFnDecl = FnDecl->getNumParams(); for (unsigned i = 0; (i < NumArgs && i < NumArgsInFnDecl); ++i) { + InitializedEntity Entity = InitializedEntity::InitializeParameter(Context, + FnDecl->getParamDecl(i)); + + if (!Diagnose && !CanPerformCopyInitialization(Entity, Owned(Args[i]))) + return true; + ExprResult Result - = PerformCopyInitialization(InitializedEntity::InitializeParameter( - Context, - FnDecl->getParamDecl(i)), - SourceLocation(), - Owned(Args[i])); + = PerformCopyInitialization(Entity, SourceLocation(), Owned(Args[i])); if (Result.isInvalid()) return true; Args[i] = Result.takeAs<Expr>(); } Operator = FnDecl; - CheckAllocationAccess(StartLoc, Range, R.getNamingClass(), Best->FoundDecl); + CheckAllocationAccess(StartLoc, Range, R.getNamingClass(), Best->FoundDecl, + Diagnose); return false; } case OR_No_Viable_Function: - Diag(StartLoc, diag::err_ovl_no_viable_function_in_call) - << Name << Range; - Candidates.NoteCandidates(*this, OCD_AllCandidates, Args, NumArgs); + if (Diagnose) { + Diag(StartLoc, diag::err_ovl_no_viable_function_in_call) + << Name << Range; + Candidates.NoteCandidates(*this, OCD_AllCandidates, Args, NumArgs); + } return true; case OR_Ambiguous: - Diag(StartLoc, diag::err_ovl_ambiguous_call) - << Name << Range; - Candidates.NoteCandidates(*this, OCD_ViableCandidates, Args, NumArgs); + if (Diagnose) { + Diag(StartLoc, diag::err_ovl_ambiguous_call) + << Name << Range; + Candidates.NoteCandidates(*this, OCD_ViableCandidates, Args, NumArgs); + } return true; case OR_Deleted: { - Diag(StartLoc, diag::err_ovl_deleted_call) - << Best->Function->isDeleted() - << Name - << getDeletedOrUnavailableSuffix(Best->Function) - << Range; - Candidates.NoteCandidates(*this, OCD_AllCandidates, Args, NumArgs); + if (Diagnose) { + Diag(StartLoc, diag::err_ovl_deleted_call) + << Best->Function->isDeleted() + << Name + << getDeletedOrUnavailableSuffix(Best->Function) + << Range; + Candidates.NoteCandidates(*this, OCD_AllCandidates, Args, NumArgs); + } return true; } } @@ -1568,7 +1592,7 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name, bool Sema::FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD, DeclarationName Name, - FunctionDecl* &Operator) { + FunctionDecl* &Operator, bool Diagnose) { LookupResult Found(*this, Name, StartLoc, LookupOrdinaryName); // Try to find operator delete/operator delete[] in class scope. LookupQualifiedName(Found, RD); @@ -1595,33 +1619,45 @@ bool Sema::FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD, // There's exactly one suitable operator; pick it. if (Matches.size() == 1) { Operator = cast<CXXMethodDecl>(Matches[0]->getUnderlyingDecl()); + + if (Operator->isDeleted()) { + if (Diagnose) { + Diag(StartLoc, diag::err_deleted_function_use); + Diag(Operator->getLocation(), diag::note_unavailable_here) << true; + } + return true; + } + CheckAllocationAccess(StartLoc, SourceRange(), Found.getNamingClass(), - Matches[0]); + Matches[0], Diagnose); return false; // We found multiple suitable operators; complain about the ambiguity. } else if (!Matches.empty()) { - Diag(StartLoc, diag::err_ambiguous_suitable_delete_member_function_found) - << Name << RD; - - for (llvm::SmallVectorImpl<DeclAccessPair>::iterator - F = Matches.begin(), FEnd = Matches.end(); F != FEnd; ++F) - Diag((*F)->getUnderlyingDecl()->getLocation(), - diag::note_member_declared_here) << Name; + if (Diagnose) { + Diag(StartLoc, diag::err_ambiguous_suitable_delete_member_function_found) + << Name << RD; + + for (llvm::SmallVectorImpl<DeclAccessPair>::iterator + F = Matches.begin(), FEnd = Matches.end(); F != FEnd; ++F) + Diag((*F)->getUnderlyingDecl()->getLocation(), + diag::note_member_declared_here) << Name; + } return true; } // We did find operator delete/operator delete[] declarations, but // none of them were suitable. if (!Found.empty()) { - Diag(StartLoc, diag::err_no_suitable_delete_member_function_found) - << Name << RD; - - for (LookupResult::iterator F = Found.begin(), FEnd = Found.end(); - F != FEnd; ++F) - Diag((*F)->getUnderlyingDecl()->getLocation(), - diag::note_member_declared_here) << Name; - + if (Diagnose) { + Diag(StartLoc, diag::err_no_suitable_delete_member_function_found) + << Name << RD; + + for (LookupResult::iterator F = Found.begin(), FEnd = Found.end(); + F != FEnd; ++F) + Diag((*F)->getUnderlyingDecl()->getLocation(), + diag::note_member_declared_here) << Name; + } return true; } @@ -1633,8 +1669,8 @@ bool Sema::FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD, Expr* DeallocArgs[1]; DeallocArgs[0] = &Null; if (FindAllocationOverload(StartLoc, SourceRange(), Name, - DeallocArgs, 1, TUDecl, /*AllowMissing=*/false, - Operator)) + DeallocArgs, 1, TUDecl, !Diagnose, + Operator, Diagnose)) return true; assert(Operator && "Did not find a deallocation function!"); @@ -1780,6 +1816,20 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, const_cast<CXXDestructorDecl*>(Dtor)); DiagnoseUseOfDecl(Dtor, StartLoc); } + + // C++ [expr.delete]p3: + // In the first alternative (delete object), if the static type of the + // object to be deleted is different from its dynamic type, the static + // type shall be a base class of the dynamic type of the object to be + // deleted and the static type shall have a virtual destructor or the + // behavior is undefined. + // + // Note: a final class cannot be derived from, no issue there + if (!ArrayForm && RD->isPolymorphic() && !RD->hasAttr<FinalAttr>()) { + CXXDestructorDecl *dtor = RD->getDestructor(); + if (!dtor || !dtor->isVirtual()) + Diag(StartLoc, diag::warn_delete_non_virtual_dtor) << PointeeElem; + } } if (!OperatorDelete) { @@ -2174,7 +2224,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, case ICK_Pointer_Conversion: { if (SCS.IncompatibleObjC && Action != AA_Casting) { // Diagnose incompatible Objective-C conversions - if (Action == AA_Initializing) + if (Action == AA_Initializing || Action == AA_Assigning) Diag(From->getSourceRange().getBegin(), diag::ext_typecheck_convert_incompatible_pointer) << ToType << From->getType() << Action @@ -2184,6 +2234,10 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, diag::ext_typecheck_convert_incompatible_pointer) << From->getType() << ToType << Action << From->getSourceRange(); + + if (From->getType()->isObjCObjectPointerType() && + ToType->isObjCObjectPointerType()) + EmitRelatedResultTypeNote(From); } CastKind Kind = CK_Invalid; @@ -2416,6 +2470,7 @@ static bool CheckUnaryTypeTraitTypeCompleteness(Sema &S, // C++0x [meta.unary.prop] Table 49 requires the following traits to be // applied to a complete type. case UTT_IsTrivial: + case UTT_IsTriviallyCopyable: case UTT_IsStandardLayout: case UTT_IsPOD: case UTT_IsLiteral: @@ -2433,7 +2488,7 @@ static bool CheckUnaryTypeTraitTypeCompleteness(Sema &S, case UTT_HasNothrowConstructor: case UTT_HasNothrowCopy: case UTT_HasTrivialAssign: - case UTT_HasTrivialConstructor: + case UTT_HasTrivialDefaultConstructor: case UTT_HasTrivialCopy: case UTT_HasTrivialDestructor: case UTT_HasVirtualDestructor: @@ -2512,6 +2567,8 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT, return T.isVolatileQualified(); case UTT_IsTrivial: return T->isTrivialType(); + case UTT_IsTriviallyCopyable: + return T->isTriviallyCopyableType(); case UTT_IsStandardLayout: return T->isStandardLayoutType(); case UTT_IsPOD: @@ -2543,7 +2600,7 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT, // // 1: http://gcc.gnu/.org/onlinedocs/gcc/Type-Traits.html // 2: http://docwiki.embarcadero.com/RADStudio/XE/en/Type_Trait_Functions_(C%2B%2B0x)_Index - case UTT_HasTrivialConstructor: + case UTT_HasTrivialDefaultConstructor: // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html: // If __is_pod (type) is true then the trait is true, else if type is // a cv class or union type (or array thereof) with a trivial default @@ -2552,7 +2609,7 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT, return true; if (const RecordType *RT = C.getBaseElementType(T)->getAs<RecordType>()) - return cast<CXXRecordDecl>(RT->getDecl())->hasTrivialConstructor(); + return cast<CXXRecordDecl>(RT->getDecl())->hasTrivialDefaultConstructor(); return false; case UTT_HasTrivialCopy: // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html: @@ -2619,7 +2676,6 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT, return true; bool FoundAssign = false; - bool AllNoThrow = true; DeclarationName Name = C.DeclarationNames.getCXXOperatorName(OO_Equal); LookupResult Res(Self, DeclarationNameInfo(Name, KeyLoc), Sema::LookupOrdinaryName); @@ -2631,15 +2687,15 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT, FoundAssign = true; const FunctionProtoType *CPT = Operator->getType()->getAs<FunctionProtoType>(); - if (!CPT->isNothrow(Self.Context)) { - AllNoThrow = false; - break; - } + if (CPT->getExceptionSpecType() == EST_Delayed) + return false; + if (!CPT->isNothrow(Self.Context)) + return false; } } } - return FoundAssign && AllNoThrow; + return FoundAssign; } return false; case UTT_HasNothrowCopy: @@ -2656,7 +2712,6 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT, return true; bool FoundConstructor = false; - bool AllNoThrow = true; unsigned FoundTQs; DeclContext::lookup_const_iterator Con, ConEnd; for (llvm::tie(Con, ConEnd) = Self.LookupConstructors(RD); @@ -2671,16 +2726,16 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT, FoundConstructor = true; const FunctionProtoType *CPT = Constructor->getType()->getAs<FunctionProtoType>(); + if (CPT->getExceptionSpecType() == EST_Delayed) + return false; // FIXME: check whether evaluating default arguments can throw. // For now, we'll be conservative and assume that they can throw. - if (!CPT->isNothrow(Self.Context) || CPT->getNumArgs() > 1) { - AllNoThrow = false; - break; - } + if (!CPT->isNothrow(Self.Context) || CPT->getNumArgs() > 1) + return false; } } - return FoundConstructor && AllNoThrow; + return FoundConstructor; } return false; case UTT_HasNothrowConstructor: @@ -2693,7 +2748,7 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT, return true; if (const RecordType *RT = C.getBaseElementType(T)->getAs<RecordType>()) { CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); - if (RD->hasTrivialConstructor()) + if (RD->hasTrivialDefaultConstructor()) return true; DeclContext::lookup_const_iterator Con, ConEnd; @@ -2706,6 +2761,8 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT, if (Constructor->isDefaultConstructor()) { const FunctionProtoType *CPT = Constructor->getType()->getAs<FunctionProtoType>(); + if (CPT->getExceptionSpecType() == EST_Delayed) + return false; // TODO: check whether evaluating default arguments can throw. // For now, we'll be conservative and assume that they can throw. return CPT->isNothrow(Self.Context) && CPT->getNumArgs() == 0; @@ -2852,7 +2909,7 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, BinaryTypeTrait BTT, Sema::SFINAETrap SFINAE(Self, /*AccessCheckingSFINAE=*/true); Sema::ContextRAII TUContext(Self, Self.Context.getTranslationUnitDecl()); InitializationSequence Init(Self, To, Kind, &FromPtr, 1); - if (Init.getKind() == InitializationSequence::FailedSequence) + if (Init.Failed()) return false; ExprResult Result = Init.Perform(Self, To, Kind, MultiExprArg(&FromPtr, 1)); @@ -3213,7 +3270,7 @@ static bool TryClassUnification(Sema &Self, Expr *From, Expr *To, if (TTy.isAtLeastAsQualifiedAs(FTy)) { InitializedEntity Entity = InitializedEntity::InitializeTemporary(TTy); InitializationSequence InitSeq(Self, Entity, Kind, &From, 1); - if (InitSeq.getKind() != InitializationSequence::FailedSequence) { + if (InitSeq) { HaveConversion = true; return false; } @@ -3238,7 +3295,7 @@ static bool TryClassUnification(Sema &Self, Expr *From, Expr *To, InitializedEntity Entity = InitializedEntity::InitializeTemporary(TTy); InitializationSequence InitSeq(Self, Entity, Kind, &From, 1); - HaveConversion = InitSeq.getKind() != InitializationSequence::FailedSequence; + HaveConversion = !InitSeq.Failed(); ToType = TTy; if (InitSeq.isAmbiguous()) return InitSeq.Diagnose(Self, Entity, Kind, &From, 1); @@ -4295,3 +4352,18 @@ StmtResult Sema::ActOnFinishFullStmt(Stmt *FullStmt) { return MaybeCreateStmtWithCleanups(FullStmt); } + +bool Sema::CheckMicrosoftIfExistsSymbol(CXXScopeSpec &SS, + UnqualifiedId &Name) { + DeclarationNameInfo TargetNameInfo = GetNameFromUnqualifiedId(Name); + DeclarationName TargetName = TargetNameInfo.getName(); + if (!TargetName) + return false; + + // Do the redeclaration lookup in the current scope. + LookupResult R(*this, TargetNameInfo, Sema::LookupAnyName, + Sema::NotForRedeclaration); + R.suppressDiagnostics(); + LookupParsedName(R, getCurScope(), &SS); + return !R.empty(); +} diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaExprObjC.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaExprObjC.cpp index 2a262f0..cb5c1e0 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaExprObjC.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaExprObjC.cpp @@ -119,7 +119,7 @@ ExprResult Sema::ParseObjCStringLiteral(SourceLocation *AtLocs, return new (Context) ObjCStringLiteral(S, Ty, AtLocs[0]); } -Expr *Sema::BuildObjCEncodeExpression(SourceLocation AtLoc, +ExprResult Sema::BuildObjCEncodeExpression(SourceLocation AtLoc, TypeSourceInfo *EncodedTypeInfo, SourceLocation RParenLoc) { QualType EncodedType = EncodedTypeInfo->getType(); @@ -127,6 +127,12 @@ Expr *Sema::BuildObjCEncodeExpression(SourceLocation AtLoc, if (EncodedType->isDependentType()) StrTy = Context.DependentTy; else { + if (!EncodedType->getAsArrayTypeUnsafe()) // Incomplete array is handled. + if (RequireCompleteType(AtLoc, EncodedType, + PDiag(diag::err_incomplete_type_objc_at_encode) + << EncodedTypeInfo->getTypeLoc().getSourceRange())) + return ExprError(); + std::string Str; Context.getObjCEncodingForType(EncodedType, Str); @@ -235,10 +241,72 @@ ObjCMethodDecl *Sema::tryCaptureObjCSelf() { return method; } +QualType Sema::getMessageSendResultType(QualType ReceiverType, + ObjCMethodDecl *Method, + bool isClassMessage, bool isSuperMessage) { + assert(Method && "Must have a method"); + if (!Method->hasRelatedResultType()) + return Method->getSendResultType(); + + // If a method has a related return type: + // - if the method found is an instance method, but the message send + // was a class message send, T is the declared return type of the method + // found + if (Method->isInstanceMethod() && isClassMessage) + return Method->getSendResultType(); + + // - if the receiver is super, T is a pointer to the class of the + // enclosing method definition + if (isSuperMessage) { + if (ObjCMethodDecl *CurMethod = getCurMethodDecl()) + if (ObjCInterfaceDecl *Class = CurMethod->getClassInterface()) + return Context.getObjCObjectPointerType( + Context.getObjCInterfaceType(Class)); + } + + // - if the receiver is the name of a class U, T is a pointer to U + if (ReceiverType->getAs<ObjCInterfaceType>() || + ReceiverType->isObjCQualifiedInterfaceType()) + return Context.getObjCObjectPointerType(ReceiverType); + // - if the receiver is of type Class or qualified Class type, + // T is the declared return type of the method. + if (ReceiverType->isObjCClassType() || + ReceiverType->isObjCQualifiedClassType()) + return Method->getSendResultType(); + + // - if the receiver is id, qualified id, Class, or qualified Class, T + // is the receiver type, otherwise + // - T is the type of the receiver expression. + return ReceiverType; +} + +void Sema::EmitRelatedResultTypeNote(const Expr *E) { + E = E->IgnoreParenImpCasts(); + const ObjCMessageExpr *MsgSend = dyn_cast<ObjCMessageExpr>(E); + if (!MsgSend) + return; + + const ObjCMethodDecl *Method = MsgSend->getMethodDecl(); + if (!Method) + return; + + if (!Method->hasRelatedResultType()) + return; + + if (Context.hasSameUnqualifiedType(Method->getResultType() + .getNonReferenceType(), + MsgSend->getType())) + return; + + Diag(Method->getLocation(), diag::note_related_result_type_inferred) + << Method->isInstanceMethod() << Method->getSelector() + << MsgSend->getType(); +} -bool Sema::CheckMessageArgumentTypes(Expr **Args, unsigned NumArgs, +bool Sema::CheckMessageArgumentTypes(QualType ReceiverType, + Expr **Args, unsigned NumArgs, Selector Sel, ObjCMethodDecl *Method, - bool isClassMessage, + bool isClassMessage, bool isSuperMessage, SourceLocation lbrac, SourceLocation rbrac, QualType &ReturnType, ExprValueKind &VK) { if (!Method) { @@ -262,7 +330,8 @@ bool Sema::CheckMessageArgumentTypes(Expr **Args, unsigned NumArgs, return false; } - ReturnType = Method->getSendResultType(); + ReturnType = getMessageSendResultType(ReceiverType, Method, isClassMessage, + isSuperMessage); VK = Expr::getValueKindForType(Method->getResultType()); unsigned NumNamedArgs = Sel.getNumArgs(); @@ -450,9 +519,12 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT, ResTy = ResTy.getNonLValueExprType(Context); Selector Sel = PP.getSelectorTable().getNullarySelector(Member); ObjCMethodDecl *Getter = IFace->lookupInstanceMethod(Sel); - if (DiagnosePropertyAccessorMismatch(PD, Getter, MemberLoc)) - ResTy = Getter->getResultType(); - + if (Getter && + (Getter->hasRelatedResultType() + || DiagnosePropertyAccessorMismatch(PD, Getter, MemberLoc))) + ResTy = getMessageSendResultType(QualType(OPT, 0), Getter, false, + Super); + if (Super) return Owned(new (Context) ObjCPropertyRefExpr(PD, ResTy, VK_LValue, OK_ObjCProperty, @@ -470,14 +542,18 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT, // Check whether we can reference this property. if (DiagnoseUseOfDecl(PD, MemberLoc)) return ExprError(); + + QualType T = PD->getType(); + if (ObjCMethodDecl *Getter = PD->getGetterMethodDecl()) + T = getMessageSendResultType(QualType(OPT, 0), Getter, false, Super); if (Super) - return Owned(new (Context) ObjCPropertyRefExpr(PD, PD->getType(), + return Owned(new (Context) ObjCPropertyRefExpr(PD, T, VK_LValue, OK_ObjCProperty, MemberLoc, SuperLoc, SuperType)); else - return Owned(new (Context) ObjCPropertyRefExpr(PD, PD->getType(), + return Owned(new (Context) ObjCPropertyRefExpr(PD, T, VK_LValue, OK_ObjCProperty, MemberLoc, @@ -534,7 +610,7 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT, if (Getter || Setter) { QualType PType; if (Getter) - PType = Getter->getSendResultType(); + PType = getMessageSendResultType(QualType(OPT, 0), Getter, false, Super); else { ParmVarDecl *ArgDecl = *Setter->param_begin(); PType = ArgDecl->getType(); @@ -608,10 +684,14 @@ ActOnClassPropertyRefExpr(IdentifierInfo &receiverName, IdentifierInfo *receiverNamePtr = &receiverName; ObjCInterfaceDecl *IFace = getObjCInterfaceDecl(receiverNamePtr, receiverNameLoc); + + bool IsSuper = false; if (IFace == 0) { // If the "receiver" is 'super' in a method, handle it as an expression-like // property reference. if (receiverNamePtr->isStr("super")) { + IsSuper = true; + if (ObjCMethodDecl *CurMethod = tryCaptureObjCSelf()) { if (CurMethod->isInstanceMethod()) { QualType T = @@ -680,7 +760,9 @@ ActOnClassPropertyRefExpr(IdentifierInfo &receiverName, ExprValueKind VK = VK_LValue; if (Getter) { - PType = Getter->getSendResultType(); + PType = getMessageSendResultType(Context.getObjCInterfaceType(IFace), + Getter, true, + receiverNamePtr->isStr("super")); if (!getLangOptions().CPlusPlus && !PType.hasQualifiers() && PType->isVoidType()) VK = VK_RValue; @@ -693,6 +775,13 @@ ActOnClassPropertyRefExpr(IdentifierInfo &receiverName, ExprObjectKind OK = (VK == VK_RValue ? OK_Ordinary : OK_ObjCProperty); + if (IsSuper) + return Owned(new (Context) ObjCPropertyRefExpr(Getter, Setter, + PType, VK, OK, + propertyNameLoc, + receiverNameLoc, + Context.getObjCInterfaceType(IFace))); + return Owned(new (Context) ObjCPropertyRefExpr(Getter, Setter, PType, VK, OK, propertyNameLoc, @@ -949,8 +1038,9 @@ ExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo, unsigned NumArgs = ArgsIn.size(); Expr **Args = reinterpret_cast<Expr **>(ArgsIn.release()); - if (CheckMessageArgumentTypes(Args, NumArgs, Sel, Method, true, - LBracLoc, RBracLoc, ReturnType, VK)) + if (CheckMessageArgumentTypes(ReceiverType, Args, NumArgs, Sel, Method, true, + SuperLoc.isValid(), LBracLoc, RBracLoc, + ReturnType, VK)) return ExprError(); if (Method && !Method->getResultType()->isVoidType() && @@ -1232,7 +1322,8 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, ExprValueKind VK = VK_RValue; bool ClassMessage = (ReceiverType->isObjCClassType() || ReceiverType->isObjCQualifiedClassType()); - if (CheckMessageArgumentTypes(Args, NumArgs, Sel, Method, ClassMessage, + if (CheckMessageArgumentTypes(ReceiverType, Args, NumArgs, Sel, Method, + ClassMessage, SuperLoc.isValid(), LBracLoc, RBracLoc, ReturnType, VK)) return ExprError(); diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaInit.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaInit.cpp index ca3fd6d..a33f5d0 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaInit.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaInit.cpp @@ -296,8 +296,7 @@ void InitListChecker::FillInValueInitForField(unsigned Init, FieldDecl *Field, // Do nothing } else if (Init < NumInits) { ILE->setInit(Init, MemberInit.takeAs<Expr>()); - } else if (InitSeq.getKind() - == InitializationSequence::ConstructorInitialization) { + } else if (InitSeq.isConstructorInitialization()) { // Value-initialization requires a constructor call, so // extend the initializer list to include the constructor // call and make a note that we'll need to take another pass @@ -418,8 +417,7 @@ InitListChecker::FillInValueInitializations(const InitializedEntity &Entity, return; } - if (InitSeq.getKind() - == InitializationSequence::ConstructorInitialization) { + if (InitSeq.isConstructorInitialization()) { // Value-initialization requires a constructor call, so // extend the initializer list to include the constructor // call and make a note that we'll need to take another pass @@ -2137,7 +2135,7 @@ bool InitializationSequence::isDirectReferenceBinding() const { } bool InitializationSequence::isAmbiguous() const { - if (getKind() != FailedSequence) + if (!Failed()) return false; switch (getFailureKind()) { @@ -2310,7 +2308,7 @@ void InitializationSequence::AddArrayInitStep(QualType T) { void InitializationSequence::SetOverloadFailure(FailureKind Failure, OverloadingResult Result) { - SequenceKind = FailedSequence; + setSequenceKind(FailedSequence); this->Failure = Failure; this->FailedOverloadResult = Result; } @@ -2331,7 +2329,6 @@ static void TryListInitialization(Sema &S, // well-formed. When we actually "perform" list initialization, we'll // do all of the necessary checking. C++0x initializer lists will // force us to perform more checking here. - Sequence.setSequenceKind(InitializationSequence::ListInitialization); QualType DestType = Entity.getType(); @@ -2800,7 +2797,6 @@ static void TryStringLiteralInitialization(Sema &S, const InitializationKind &Kind, Expr *Initializer, InitializationSequence &Sequence) { - Sequence.setSequenceKind(InitializationSequence::StringInit); Sequence.AddStringInitStep(Entity.getType()); } @@ -2813,8 +2809,6 @@ static void TryConstructorInitialization(Sema &S, Expr **Args, unsigned NumArgs, QualType DestType, InitializationSequence &Sequence) { - Sequence.setSequenceKind(InitializationSequence::ConstructorInitialization); - // Build the candidate set directly in the initialization sequence // structure, so that it will persist if we fail. OverloadCandidateSet &CandidateSet = Sequence.getFailedCandidateSet(); @@ -2947,7 +2941,6 @@ static void TryValueInitialization(Sema &S, } Sequence.AddZeroInitializationStep(Entity.getType()); - Sequence.setSequenceKind(InitializationSequence::ZeroInitialization); } /// \brief Attempt default initialization (C++ [dcl.init]p6). @@ -2973,7 +2966,6 @@ static void TryDefaultInitialization(Sema &S, } // - otherwise, no initialization is performed. - Sequence.setSequenceKind(InitializationSequence::NoInitialization); // If a program calls for the default initialization of an object of // a const-qualified type T, T shall be a class type with a user-provided @@ -2990,8 +2982,6 @@ static void TryUserDefinedConversion(Sema &S, const InitializationKind &Kind, Expr *Initializer, InitializationSequence &Sequence) { - Sequence.setSequenceKind(InitializationSequence::UserDefinedConversion); - QualType DestType = Entity.getType(); assert(!DestType->isReferenceType() && "References are handled elsewhere"); QualType SourceType = Initializer->getType(); @@ -3176,6 +3166,9 @@ InitializationSequence::InitializationSequence(Sema &S, return; } + // Almost everything is a normal sequence. + setSequenceKind(NormalSequence); + for (unsigned I = 0; I != NumArgs; ++I) if (Args[I]->getObjectKind() == OK_ObjCProperty) { ExprResult Result = S.ConvertPropertyForRValue(Args[I]); @@ -3252,7 +3245,6 @@ InitializationSequence::InitializationSequence(Sema &S, else if (Initializer->HasSideEffects(S.Context)) SetFailed(FK_NonConstantArrayInit); else { - setSequenceKind(ArrayInit); AddArrayInitStep(DestType); } } else if (DestAT->getElementType()->isAnyCharacterType()) @@ -3265,7 +3257,6 @@ InitializationSequence::InitializationSequence(Sema &S, // Handle initialization in C if (!S.getLangOptions().CPlusPlus) { - setSequenceKind(CAssignment); AddCAssignmentStep(DestType); return; } @@ -3325,8 +3316,6 @@ InitializationSequence::InitializationSequence(Sema &S, else SetFailed(InitializationSequence::FK_ConversionFailed); } - else - setSequenceKind(StandardConversion); } InitializationSequence::~InitializationSequence() { @@ -3650,13 +3639,13 @@ InitializationSequence::Perform(Sema &S, const InitializationKind &Kind, MultiExprArg Args, QualType *ResultType) { - if (SequenceKind == FailedSequence) { + if (Failed()) { unsigned NumArgs = Args.size(); Diagnose(S, Entity, Kind, (Expr **)Args.release(), NumArgs); return ExprError(); } - if (SequenceKind == DependentSequence) { + if (getKind() == DependentSequence) { // If the declaration is a non-dependent, incomplete array type // that has an initializer, then its type will be completed once // the initializer is instantiated. @@ -3710,7 +3699,8 @@ InitializationSequence::Perform(Sema &S, SourceLocation())); } - if (SequenceKind == NoInitialization) + // No steps means no initialization. + if (Steps.empty()) return S.Owned((Expr *)0); QualType DestType = Entity.getType().getNonReferenceType(); @@ -3723,8 +3713,6 @@ InitializationSequence::Perform(Sema &S, ExprResult CurInit = S.Owned((Expr *)0); - assert(!Steps.empty() && "Cannot have an empty initialization sequence"); - // For initialization steps that start with a single initializer, // grab the only argument out the Args and place it into the "current" // initializer. @@ -4019,8 +4007,9 @@ InitializationSequence::Perform(Sema &S, // the definition for completely trivial constructors. CXXRecordDecl *ClassDecl = Constructor->getParent(); assert(ClassDecl && "No parent class for constructor."); - if (Constructor->isImplicit() && Constructor->isDefaultConstructor() && - ClassDecl->hasTrivialConstructor() && !Constructor->isUsed(false)) + if (Constructor->isDefaulted() && Constructor->isDefaultConstructor() && + ClassDecl->hasTrivialDefaultConstructor() && + !Constructor->isUsed(false)) S.DefineImplicitDefaultConstructor(Loc, Constructor); } @@ -4060,8 +4049,7 @@ InitializationSequence::Perform(Sema &S, ConstructKind = Entity.getBaseSpecifier()->isVirtual() ? CXXConstructExpr::CK_VirtualBase : CXXConstructExpr::CK_NonVirtualBase; - } - if (Entity.getKind() == InitializedEntity::EK_Delegating) { + } else if (Entity.getKind() == InitializedEntity::EK_Delegating) { ConstructKind = CXXConstructExpr::CK_Delegating; } @@ -4216,7 +4204,7 @@ bool InitializationSequence::Diagnose(Sema &S, const InitializedEntity &Entity, const InitializationKind &Kind, Expr **Args, unsigned NumArgs) { - if (SequenceKind != FailedSequence) + if (!Failed()) return false; QualType DestType = Entity.getType(); @@ -4334,6 +4322,9 @@ bool InitializationSequence::Diagnose(Sema &S, << Args[0]->isLValue() << Args[0]->getType() << Args[0]->getSourceRange(); + if (DestType.getNonReferenceType()->isObjCObjectPointerType() && + Args[0]->getType()->isObjCObjectPointerType()) + S.EmitRelatedResultTypeNote(Args[0]); break; case FK_ConversionFailed: { @@ -4344,6 +4335,9 @@ bool InitializationSequence::Diagnose(Sema &S, << Args[0]->isLValue() << FromType << Args[0]->getSourceRange(); + if (DestType.getNonReferenceType()->isObjCObjectPointerType() && + Args[0]->getType()->isObjCObjectPointerType()) + S.EmitRelatedResultTypeNote(Args[0]); break; } @@ -4587,48 +4581,16 @@ void InitializationSequence::dump(llvm::raw_ostream &OS) const { } case DependentSequence: - OS << "Dependent sequence: "; + OS << "Dependent sequence\n"; return; - case UserDefinedConversion: - OS << "User-defined conversion sequence: "; - break; - - case ConstructorInitialization: - OS << "Constructor initialization sequence: "; + case NormalSequence: + OS << "Normal sequence: "; break; case ReferenceBinding: OS << "Reference binding: "; break; - - case ListInitialization: - OS << "List initialization: "; - break; - - case ZeroInitialization: - OS << "Zero initialization\n"; - return; - - case NoInitialization: - OS << "No initialization\n"; - return; - - case StandardConversion: - OS << "Standard conversion: "; - break; - - case CAssignment: - OS << "C assignment: "; - break; - - case StringInit: - OS << "String initialization: "; - break; - - case ArrayInit: - OS << "Array initialization: "; - break; } for (step_iterator S = step_begin(), SEnd = step_end(); S != SEnd; ++S) { @@ -4723,6 +4685,21 @@ void InitializationSequence::dump() const { //===----------------------------------------------------------------------===// // Initialization helper functions //===----------------------------------------------------------------------===// +bool +Sema::CanPerformCopyInitialization(const InitializedEntity &Entity, + ExprResult Init) { + if (Init.isInvalid()) + return false; + + Expr *InitE = Init.get(); + assert(InitE && "No initialization expression"); + + InitializationKind Kind = InitializationKind::CreateCopy(SourceLocation(), + SourceLocation()); + InitializationSequence Seq(*this, Entity, Kind, &InitE, 1); + return !Seq.Failed(); +} + ExprResult Sema::PerformCopyInitialization(const InitializedEntity &Entity, SourceLocation EqualLoc, diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaLookup.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaLookup.cpp index 309c771..92ade1e 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaLookup.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaLookup.cpp @@ -14,6 +14,7 @@ #include "clang/Sema/Sema.h" #include "clang/Sema/SemaInternal.h" #include "clang/Sema/Lookup.h" +#include "clang/Sema/Overload.h" #include "clang/Sema/DeclSpec.h" #include "clang/Sema/Scope.h" #include "clang/Sema/ScopeInfo.h" @@ -534,7 +535,7 @@ void Sema::ForceDeclarationOfImplicitMembers(CXXRecordDecl *Class) { return; // If the default constructor has not yet been declared, do so now. - if (!Class->hasDeclaredDefaultConstructor()) + if (Class->needsImplicitDefaultConstructor()) DeclareImplicitDefaultConstructor(Class); // If the copy constructor has not yet been declared, do so now. @@ -581,7 +582,7 @@ static void DeclareImplicitMemberFunctionsWithName(Sema &S, if (const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(DC)) if (Record->getDefinition() && CanDeclareSpecialMemberFunction(S.Context, Record)) { - if (!Record->hasDeclaredDefaultConstructor()) + if (Record->needsImplicitDefaultConstructor()) S.DeclareImplicitDefaultConstructor( const_cast<CXXRecordDecl *>(Record)); if (!Record->hasDeclaredCopyConstructor()) @@ -2136,11 +2137,200 @@ void Sema::LookupOverloadedOperatorName(OverloadedOperatorKind Op, Scope *S, } } +Sema::SpecialMemberOverloadResult *Sema::LookupSpecialMember(CXXRecordDecl *D, + CXXSpecialMember SM, + bool ConstArg, + bool VolatileArg, + bool RValueThis, + bool ConstThis, + bool VolatileThis) { + D = D->getDefinition(); + assert((D && !D->isBeingDefined()) && + "doing special member lookup into record that isn't fully complete"); + if (RValueThis || ConstThis || VolatileThis) + assert((SM == CXXCopyAssignment || SM == CXXMoveAssignment) && + "constructors and destructors always have unqualified lvalue this"); + if (ConstArg || VolatileArg) + assert((SM != CXXDefaultConstructor && SM != CXXDestructor) && + "parameter-less special members can't have qualified arguments"); + + llvm::FoldingSetNodeID ID; + ID.AddPointer(D); + ID.AddInteger(SM); + ID.AddInteger(ConstArg); + ID.AddInteger(VolatileArg); + ID.AddInteger(RValueThis); + ID.AddInteger(ConstThis); + ID.AddInteger(VolatileThis); + + void *InsertPoint; + SpecialMemberOverloadResult *Result = + SpecialMemberCache.FindNodeOrInsertPos(ID, InsertPoint); + + // This was already cached + if (Result) + return Result; + + Result = BumpAlloc.Allocate<SpecialMemberOverloadResult>(); + Result = new (Result) SpecialMemberOverloadResult(ID); + SpecialMemberCache.InsertNode(Result, InsertPoint); + + if (SM == CXXDestructor) { + if (!D->hasDeclaredDestructor()) + DeclareImplicitDestructor(D); + CXXDestructorDecl *DD = D->getDestructor(); + assert(DD && "record without a destructor"); + Result->setMethod(DD); + Result->setSuccess(DD->isDeleted()); + Result->setConstParamMatch(false); + return Result; + } + + // Prepare for overload resolution. Here we construct a synthetic argument + // if necessary and make sure that implicit functions are declared. + CanQualType CanTy = Context.getCanonicalType(Context.getTagDeclType(D)); + DeclarationName Name; + Expr *Arg = 0; + unsigned NumArgs; + + if (SM == CXXDefaultConstructor) { + Name = Context.DeclarationNames.getCXXConstructorName(CanTy); + NumArgs = 0; + if (D->needsImplicitDefaultConstructor()) + DeclareImplicitDefaultConstructor(D); + } else { + if (SM == CXXCopyConstructor || SM == CXXMoveConstructor) { + Name = Context.DeclarationNames.getCXXConstructorName(CanTy); + if (!D->hasDeclaredCopyConstructor()) + DeclareImplicitCopyConstructor(D); + // TODO: Move constructors + } else { + Name = Context.DeclarationNames.getCXXOperatorName(OO_Equal); + if (!D->hasDeclaredCopyAssignment()) + DeclareImplicitCopyAssignment(D); + // TODO: Move assignment + } + + QualType ArgType = CanTy; + if (ConstArg) + ArgType.addConst(); + if (VolatileArg) + ArgType.addVolatile(); + + // This isn't /really/ specified by the standard, but it's implied + // we should be working from an RValue in the case of move to ensure + // that we prefer to bind to rvalue references, and an LValue in the + // case of copy to ensure we don't bind to rvalue references. + // Possibly an XValue is actually correct in the case of move, but + // there is no semantic difference for class types in this restricted + // case. + ExprValueKind VK; + if (SM == CXXCopyAssignment || SM == CXXMoveAssignment) + VK = VK_LValue; + else + VK = VK_RValue; + + NumArgs = 1; + Arg = new (Context) OpaqueValueExpr(SourceLocation(), ArgType, VK); + } + + // Create the object argument + QualType ThisTy = CanTy; + if (ConstThis) + ThisTy.addConst(); + if (VolatileThis) + ThisTy.addVolatile(); + Expr::Classification ObjectClassification = + (new (Context) OpaqueValueExpr(SourceLocation(), ThisTy, + RValueThis ? VK_RValue : VK_LValue))-> + Classify(Context); + + // Now we perform lookup on the name we computed earlier and do overload + // resolution. Lookup is only performed directly into the class since there + // will always be a (possibly implicit) declaration to shadow any others. + OverloadCandidateSet OCS((SourceLocation())); + DeclContext::lookup_iterator I, E; + Result->setConstParamMatch(false); + + llvm::tie(I, E) = D->lookup(Name); + assert((I != E) && + "lookup for a constructor or assignment operator was empty"); + for ( ; I != E; ++I) { + if ((*I)->isInvalidDecl()) + continue; + + if (CXXMethodDecl *M = dyn_cast<CXXMethodDecl>(*I)) { + AddOverloadCandidate(M, DeclAccessPair::make(M, AS_public), &Arg, NumArgs, + OCS, true); + + // Here we're looking for a const parameter to speed up creation of + // implicit copy methods. + if ((SM == CXXCopyAssignment && M->isCopyAssignmentOperator()) || + (SM == CXXCopyConstructor && + cast<CXXConstructorDecl>(M)->isCopyConstructor())) { + QualType ArgType = M->getType()->getAs<FunctionProtoType>()->getArgType(0); + if (ArgType->getPointeeType().isConstQualified()) + Result->setConstParamMatch(true); + } + } else { + FunctionTemplateDecl *Tmpl = cast<FunctionTemplateDecl>(*I); + AddTemplateOverloadCandidate(Tmpl, DeclAccessPair::make(Tmpl, AS_public), + 0, &Arg, NumArgs, OCS, true); + } + } + + OverloadCandidateSet::iterator Best; + switch (OCS.BestViableFunction(*this, SourceLocation(), Best)) { + case OR_Success: + Result->setMethod(cast<CXXMethodDecl>(Best->Function)); + Result->setSuccess(true); + break; + + case OR_Deleted: + Result->setMethod(cast<CXXMethodDecl>(Best->Function)); + Result->setSuccess(false); + break; + + case OR_Ambiguous: + case OR_No_Viable_Function: + Result->setMethod(0); + Result->setSuccess(false); + break; + } + + return Result; +} + +/// \brief Look up the default constructor for the given class. +CXXConstructorDecl *Sema::LookupDefaultConstructor(CXXRecordDecl *Class) { + SpecialMemberOverloadResult *Result = + LookupSpecialMember(Class, CXXDefaultConstructor, false, false, false, + false, false); + + return cast_or_null<CXXConstructorDecl>(Result->getMethod()); +} + +/// \brief Look up the copy constructor for the given class. +CXXConstructorDecl *Sema::LookupCopyConstructor(CXXRecordDecl *Class, + unsigned Quals, + bool *ConstParamMatch) { + assert(!(Quals & ~(Qualifiers::Const | Qualifiers::Volatile)) && + "non-const, non-volatile qualifiers for copy ctor arg"); + SpecialMemberOverloadResult *Result = + LookupSpecialMember(Class, CXXCopyConstructor, Quals & Qualifiers::Const, + Quals & Qualifiers::Volatile, false, false, false); + + if (ConstParamMatch) + *ConstParamMatch = Result->hasConstParamMatch(); + + return cast_or_null<CXXConstructorDecl>(Result->getMethod()); +} + /// \brief Look up the constructors for the given class. DeclContext::lookup_result Sema::LookupConstructors(CXXRecordDecl *Class) { - // If the copy constructor has not yet been declared, do so now. + // If the implicit constructors have not yet been declared, do so now. if (CanDeclareSpecialMemberFunction(Context, Class)) { - if (!Class->hasDeclaredDefaultConstructor()) + if (Class->needsImplicitDefaultConstructor()) DeclareImplicitDefaultConstructor(Class); if (!Class->hasDeclaredCopyConstructor()) DeclareImplicitCopyConstructor(Class); @@ -2158,12 +2348,9 @@ DeclContext::lookup_result Sema::LookupConstructors(CXXRecordDecl *Class) { /// /// \returns The destructor for this class. CXXDestructorDecl *Sema::LookupDestructor(CXXRecordDecl *Class) { - // If the destructor has not yet been declared, do so now. - if (CanDeclareSpecialMemberFunction(Context, Class) && - !Class->hasDeclaredDestructor()) - DeclareImplicitDestructor(Class); - - return Class->getDestructor(); + return cast<CXXDestructorDecl>(LookupSpecialMember(Class, CXXDestructor, + false, false, false, + false, false)->getMethod()); } void ADLResult::insert(NamedDecl *New) { @@ -2410,8 +2597,8 @@ VisibleDeclsRecord::ShadowMapEntry::end() { if (DeclOrVector.isNull()) return 0; - if (DeclOrVector.dyn_cast<NamedDecl *>()) - return &reinterpret_cast<NamedDecl*&>(DeclOrVector) + 1; + if (DeclOrVector.is<NamedDecl *>()) + return DeclOrVector.getAddrOf<NamedDecl *>() + 1; return DeclOrVector.get<DeclVector *>()->end(); } diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaOverload.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaOverload.cpp index 3f3ed0e..4bba6f8 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaOverload.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaOverload.cpp @@ -1628,6 +1628,15 @@ bool Sema::IsPointerConversion(Expr *From, QualType FromType, QualType ToType, return true; } + // MSVC allows implicit function to void* type conversion. + if (getLangOptions().Microsoft && FromPointeeType->isFunctionType() && + ToPointeeType->isVoidType()) { + ConvertedType = BuildSimilarlyQualifiedPointerType(FromTypePtr, + ToPointeeType, + ToType, Context); + return true; + } + // When we're overloading in C, we allow a special kind of pointer // conversion for compatible-but-not-identical pointee types. if (!getLangOptions().CPlusPlus && @@ -2197,6 +2206,13 @@ Sema::IsQualificationConversion(QualType FromType, QualType ToType, Qualifiers FromQuals = FromType.getQualifiers(); Qualifiers ToQuals = ToType.getQualifiers(); + // Allow addition/removal of GC attributes but not changing GC attributes. + if (FromQuals.getObjCGCAttr() != ToQuals.getObjCGCAttr() && + (!FromQuals.hasObjCGCAttr() || !ToQuals.hasObjCGCAttr())) { + FromQuals.removeObjCGCAttr(); + ToQuals.removeObjCGCAttr(); + } + // -- for every j > 0, if const is in cv 1,j then const is in cv // 2,j, and similarly for volatile. if (!CStyle && !ToQuals.compatiblyIncludes(FromQuals)) @@ -2507,12 +2523,10 @@ compareStandardConversionSubsets(ASTContext &Context, // the identity conversion sequence is considered to be a subsequence of // any non-identity conversion sequence - if (SCS1.ReferenceBinding == SCS2.ReferenceBinding) { - if (SCS1.isIdentityConversion() && !SCS2.isIdentityConversion()) - return ImplicitConversionSequence::Better; - else if (!SCS1.isIdentityConversion() && SCS2.isIdentityConversion()) - return ImplicitConversionSequence::Worse; - } + if (SCS1.isIdentityConversion() && !SCS2.isIdentityConversion()) + return ImplicitConversionSequence::Better; + else if (!SCS1.isIdentityConversion() && SCS2.isIdentityConversion()) + return ImplicitConversionSequence::Worse; if (SCS1.Second != SCS2.Second) { if (SCS1.Second == ICK_Identity) @@ -4689,6 +4703,10 @@ class BuiltinCandidateTypeSet { /// were present in the candidate set. bool HasArithmeticOrEnumeralTypes; + /// \brief A flag indicating whether the nullptr type was present in the + /// candidate set. + bool HasNullPtrType; + /// Sema - The semantic analysis instance where we are building the /// candidate type set. Sema &SemaRef; @@ -4707,6 +4725,7 @@ public: BuiltinCandidateTypeSet(Sema &SemaRef) : HasNonRecordTypes(false), HasArithmeticOrEnumeralTypes(false), + HasNullPtrType(false), SemaRef(SemaRef), Context(SemaRef.Context) { } @@ -4739,6 +4758,7 @@ public: bool hasNonRecordTypes() { return HasNonRecordTypes; } bool hasArithmeticOrEnumeralTypes() { return HasArithmeticOrEnumeralTypes; } + bool hasNullPtrType() const { return HasNullPtrType; } }; /// AddPointerWithMoreQualifiedTypeVariants - Add the pointer type @p Ty to @@ -4899,6 +4919,8 @@ BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty, // extension. HasArithmeticOrEnumeralTypes = true; VectorTypes.insert(Ty); + } else if (Ty->isNullPtrType()) { + HasNullPtrType = true; } else if (AllowUserConversions && TyRec) { // No conversion functions in incomplete types. if (SemaRef.RequireCompleteType(Loc, Ty, 0)) @@ -5358,8 +5380,8 @@ public: // C++ [over.built]p15: // - // For every pointer or enumeration type T, there exist - // candidate operator functions of the form + // For every T, where T is an enumeration type, a pointer type, or + // std::nullptr_t, there exist candidate operator functions of the form // // bool operator<(T, T); // bool operator>(T, T); @@ -5444,6 +5466,17 @@ public: S.AddBuiltinCandidate(S.Context.BoolTy, ParamTypes, Args, 2, CandidateSet); } + + if (CandidateTypes[ArgIdx].hasNullPtrType()) { + CanQualType NullPtrTy = S.Context.getCanonicalType(S.Context.NullPtrTy); + if (AddedTypes.insert(NullPtrTy) && + !UserDefinedBinaryOperators.count(std::make_pair(NullPtrTy, + NullPtrTy))) { + QualType ParamTypes[2] = { NullPtrTy, NullPtrTy }; + S.AddBuiltinCandidate(S.Context.BoolTy, ParamTypes, Args, 2, + CandidateSet); + } + } } } @@ -6401,7 +6434,9 @@ enum OverloadCandidateKind { oc_constructor_template, oc_implicit_default_constructor, oc_implicit_copy_constructor, + oc_implicit_move_constructor, oc_implicit_copy_assignment, + oc_implicit_move_assignment, oc_implicit_inherited_constructor }; @@ -6423,8 +6458,15 @@ OverloadCandidateKind ClassifyOverloadCandidate(Sema &S, if (Ctor->getInheritedConstructor()) return oc_implicit_inherited_constructor; - return Ctor->isCopyConstructor() ? oc_implicit_copy_constructor - : oc_implicit_default_constructor; + if (Ctor->isDefaultConstructor()) + return oc_implicit_default_constructor; + + if (Ctor->isMoveConstructor()) + return oc_implicit_move_constructor; + + assert(Ctor->isCopyConstructor() && + "unexpected sort of implicit constructor"); + return oc_implicit_copy_constructor; } if (CXXMethodDecl *Meth = dyn_cast<CXXMethodDecl>(Fn)) { @@ -6433,6 +6475,9 @@ OverloadCandidateKind ClassifyOverloadCandidate(Sema &S, if (!Meth->isImplicit()) return isTemplate ? oc_method_template : oc_method; + if (Meth->isMoveAssignmentOperator()) + return oc_implicit_move_assignment; + assert(Meth->isCopyAssignmentOperator() && "implicit method is not copy assignment operator?"); return oc_implicit_copy_assignment; @@ -6676,6 +6721,15 @@ void DiagnoseArityMismatch(Sema &S, OverloadCandidate *Cand, unsigned MinParams = Fn->getMinRequiredArguments(); + // With invalid overloaded operators, it's possible that we think we + // have an arity mismatch when it fact it looks like we have the + // right number of arguments, because only overloaded operators have + // the weird behavior of overloading member and non-member functions. + // Just don't report anything. + if (Fn->isInvalidDecl() && + Fn->getDeclName().getNameKind() == DeclarationName::CXXOperatorName) + return; + // at least / at most / exactly unsigned mode, modeCount; if (NumFormalArgs < MinParams) { @@ -7772,6 +7826,111 @@ void Sema::AddOverloadedCallCandidates(UnresolvedLookupExpr *ULE, ULE->isStdAssociatedNamespace()); } +/// Attempt to recover from an ill-formed use of a non-dependent name in a +/// template, where the non-dependent name was declared after the template +/// was defined. This is common in code written for a compilers which do not +/// correctly implement two-stage name lookup. +/// +/// Returns true if a viable candidate was found and a diagnostic was issued. +static bool +DiagnoseTwoPhaseLookup(Sema &SemaRef, SourceLocation FnLoc, + const CXXScopeSpec &SS, LookupResult &R, + TemplateArgumentListInfo *ExplicitTemplateArgs, + Expr **Args, unsigned NumArgs) { + if (SemaRef.ActiveTemplateInstantiations.empty() || !SS.isEmpty()) + return false; + + for (DeclContext *DC = SemaRef.CurContext; DC; DC = DC->getParent()) { + SemaRef.LookupQualifiedName(R, DC); + + if (!R.empty()) { + R.suppressDiagnostics(); + + if (isa<CXXRecordDecl>(DC)) { + // Don't diagnose names we find in classes; we get much better + // diagnostics for these from DiagnoseEmptyLookup. + R.clear(); + return false; + } + + OverloadCandidateSet Candidates(FnLoc); + for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) + AddOverloadedCallCandidate(SemaRef, I.getPair(), + ExplicitTemplateArgs, Args, NumArgs, + Candidates, false); + + OverloadCandidateSet::iterator Best; + if (Candidates.BestViableFunction(SemaRef, FnLoc, Best) != OR_Success) + // No viable functions. Don't bother the user with notes for functions + // which don't work and shouldn't be found anyway. + return false; + + // Find the namespaces where ADL would have looked, and suggest + // declaring the function there instead. + Sema::AssociatedNamespaceSet AssociatedNamespaces; + Sema::AssociatedClassSet AssociatedClasses; + SemaRef.FindAssociatedClassesAndNamespaces(Args, NumArgs, + AssociatedNamespaces, + AssociatedClasses); + // Never suggest declaring a function within namespace 'std'. + Sema::AssociatedNamespaceSet SuggestedNamespaces; + if (DeclContext *Std = SemaRef.getStdNamespace()) { + for (Sema::AssociatedNamespaceSet::iterator + it = AssociatedNamespaces.begin(), + end = AssociatedNamespaces.end(); it != end; ++it) { + if (!Std->Encloses(*it)) + SuggestedNamespaces.insert(*it); + } + } else { + // Lacking the 'std::' namespace, use all of the associated namespaces. + SuggestedNamespaces = AssociatedNamespaces; + } + + SemaRef.Diag(R.getNameLoc(), diag::err_not_found_by_two_phase_lookup) + << R.getLookupName(); + if (SuggestedNamespaces.empty()) { + SemaRef.Diag(Best->Function->getLocation(), + diag::note_not_found_by_two_phase_lookup) + << R.getLookupName() << 0; + } else if (SuggestedNamespaces.size() == 1) { + SemaRef.Diag(Best->Function->getLocation(), + diag::note_not_found_by_two_phase_lookup) + << R.getLookupName() << 1 << *SuggestedNamespaces.begin(); + } else { + // FIXME: It would be useful to list the associated namespaces here, + // but the diagnostics infrastructure doesn't provide a way to produce + // a localized representation of a list of items. + SemaRef.Diag(Best->Function->getLocation(), + diag::note_not_found_by_two_phase_lookup) + << R.getLookupName() << 2; + } + + // Try to recover by calling this function. + return true; + } + + R.clear(); + } + + return false; +} + +/// Attempt to recover from ill-formed use of a non-dependent operator in a +/// template, where the non-dependent operator was declared after the template +/// was defined. +/// +/// Returns true if a viable candidate was found and a diagnostic was issued. +static bool +DiagnoseTwoPhaseOperatorLookup(Sema &SemaRef, OverloadedOperatorKind Op, + SourceLocation OpLoc, + Expr **Args, unsigned NumArgs) { + DeclarationName OpName = + SemaRef.Context.DeclarationNames.getCXXOperatorName(Op); + LookupResult R(SemaRef, OpName, OpLoc, Sema::LookupOperatorName); + return DiagnoseTwoPhaseLookup(SemaRef, OpLoc, CXXScopeSpec(), R, + /*ExplicitTemplateArgs=*/0, Args, NumArgs); +} + /// Attempts to recover from a call where no functions were found. /// /// Returns true if new candidates were found. @@ -7780,13 +7939,14 @@ BuildRecoveryCallExpr(Sema &SemaRef, Scope *S, Expr *Fn, UnresolvedLookupExpr *ULE, SourceLocation LParenLoc, Expr **Args, unsigned NumArgs, - SourceLocation RParenLoc) { + SourceLocation RParenLoc, + bool EmptyLookup) { CXXScopeSpec SS; SS.Adopt(ULE->getQualifierLoc()); TemplateArgumentListInfo TABuffer; - const TemplateArgumentListInfo *ExplicitTemplateArgs = 0; + TemplateArgumentListInfo *ExplicitTemplateArgs = 0; if (ULE->hasExplicitTemplateArgs()) { ULE->copyTemplateArgumentsInto(TABuffer); ExplicitTemplateArgs = &TABuffer; @@ -7794,7 +7954,10 @@ BuildRecoveryCallExpr(Sema &SemaRef, Scope *S, Expr *Fn, LookupResult R(SemaRef, ULE->getName(), ULE->getNameLoc(), Sema::LookupOrdinaryName); - if (SemaRef.DiagnoseEmptyLookup(S, SS, R, Sema::CTC_Expression)) + if (!DiagnoseTwoPhaseLookup(SemaRef, Fn->getExprLoc(), SS, R, + ExplicitTemplateArgs, Args, NumArgs) && + (!EmptyLookup || + SemaRef.DiagnoseEmptyLookup(S, SS, R, Sema::CTC_Expression))) return ExprError(); assert(!R.empty() && "lookup results empty despite recovery"); @@ -7814,7 +7977,7 @@ BuildRecoveryCallExpr(Sema &SemaRef, Scope *S, Expr *Fn, return ExprError(); // This shouldn't cause an infinite loop because we're giving it - // an expression with non-empty lookup results, which should never + // an expression with viable lookup results, which should never // end up here. return SemaRef.ActOnCallExpr(/*Scope*/ 0, NewFn.take(), LParenLoc, MultiExprArg(Args, NumArgs), RParenLoc); @@ -7860,11 +8023,11 @@ Sema::BuildOverloadedCallExpr(Scope *S, Expr *Fn, UnresolvedLookupExpr *ULE, AddOverloadedCallCandidates(ULE, Args, NumArgs, CandidateSet); // If we found nothing, try to recover. - // AddRecoveryCallCandidates diagnoses the error itself, so we just - // bailout out if it fails. + // BuildRecoveryCallExpr diagnoses the error itself, so we just bail + // out if it fails. if (CandidateSet.empty()) return BuildRecoveryCallExpr(*this, S, Fn, ULE, LParenLoc, Args, NumArgs, - RParenLoc); + RParenLoc, /*EmptyLookup=*/true); OverloadCandidateSet::iterator Best; switch (CandidateSet.BestViableFunction(*this, Fn->getLocStart(), Best)) { @@ -7879,12 +8042,21 @@ Sema::BuildOverloadedCallExpr(Scope *S, Expr *Fn, UnresolvedLookupExpr *ULE, ExecConfig); } - case OR_No_Viable_Function: + case OR_No_Viable_Function: { + // Try to recover by looking for viable functions which the user might + // have meant to call. + ExprResult Recovery = BuildRecoveryCallExpr(*this, S, Fn, ULE, LParenLoc, + Args, NumArgs, RParenLoc, + /*EmptyLookup=*/false); + if (!Recovery.isInvalid()) + return Recovery; + Diag(Fn->getSourceRange().getBegin(), diag::err_ovl_no_viable_function_in_call) << ULE->getName() << Fn->getSourceRange(); CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args, NumArgs); break; + } case OR_Ambiguous: Diag(Fn->getSourceRange().getBegin(), diag::err_ovl_ambiguous_call) @@ -8073,6 +8245,13 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn, } case OR_No_Viable_Function: + // This is an erroneous use of an operator which can be overloaded by + // a non-member function. Check for non-member operators which were + // defined too late to be candidates. + if (DiagnoseTwoPhaseOperatorLookup(*this, Op, OpLoc, Args, NumArgs)) + // FIXME: Recover by calling the found function. + return ExprError(); + // No viable function; fall through to handling this as a // built-in operator, which will produce an error message for us. break; @@ -8354,6 +8533,13 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, << BinaryOperator::getOpcodeStr(Opc) << Args[0]->getSourceRange() << Args[1]->getSourceRange(); } else { + // This is an erroneous use of an operator which can be overloaded by + // a non-member function. Check for non-member operators which were + // defined too late to be candidates. + if (DiagnoseTwoPhaseOperatorLookup(*this, Op, OpLoc, Args, 2)) + // FIXME: Recover by calling the found function. + return ExprError(); + // No viable function; try to create a built-in operation, which will // produce an error. Then, show the non-viable candidates. Result = CreateBuiltinBinOp(OpLoc, Opc, Args[0], Args[1]); @@ -8772,6 +8958,19 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, if (CheckFunctionCall(Method, TheCall)) return ExprError(); + if ((isa<CXXConstructorDecl>(CurContext) || + isa<CXXDestructorDecl>(CurContext)) && + TheCall->getMethodDecl()->isPure()) { + const CXXMethodDecl *MD = TheCall->getMethodDecl(); + + if (isa<CXXThisExpr>(MemExpr->getBase()->IgnoreParenCasts())) + Diag(MemExpr->getLocStart(), + diag::warn_call_to_pure_virtual_member_function_from_ctor_dtor) + << MD->getDeclName() << isa<CXXDestructorDecl>(CurContext) + << MD->getParent()->getDeclName(); + + Diag(MD->getLocStart(), diag::note_previous_decl) << MD->getDeclName(); + } return MaybeBindToTemporary(TheCall); } diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaStmt.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaStmt.cpp index 65cea7a..d7c0a54 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaStmt.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaStmt.cpp @@ -501,7 +501,8 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, = CondExpr->isTypeDependent() || CondExpr->isValueDependent(); unsigned CondWidth = HasDependentValue ? 0 : Context.getIntWidth(CondTypeBeforePromotion); - bool CondIsSigned = CondTypeBeforePromotion->isSignedIntegerType(); + bool CondIsSigned + = CondTypeBeforePromotion->isSignedIntegerOrEnumerationType(); // Accumulate all of the case values in a vector so that we can sort them // and detect duplicates. This vector contains the APInt for the case after @@ -723,7 +724,8 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, // If switch has default case, then ignore it. if (!CaseListIsErroneous && !HasConstantCond && ET) { const EnumDecl *ED = ET->getDecl(); - typedef llvm::SmallVector<std::pair<llvm::APSInt, EnumConstantDecl*>, 64> EnumValsTy; + typedef llvm::SmallVector<std::pair<llvm::APSInt, EnumConstantDecl*>, 64> + EnumValsTy; EnumValsTy EnumVals; // Gather all enum values, set their type and sort them, @@ -1252,7 +1254,8 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc, ExprResult BoundExpr; if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(UnqAT)) BoundExpr = Owned(IntegerLiteral::Create(Context, CAT->getSize(), - Context.IntTy, RangeLoc)); + Context.getPointerDiffType(), + RangeLoc)); else if (const VariableArrayType *VAT = dyn_cast<VariableArrayType>(UnqAT)) BoundExpr = VAT->getSizeExpr(); @@ -1455,7 +1458,10 @@ Sema::ActOnBreakStmt(SourceLocation BreakLoc, Scope *CurScope) { /// \param E The expression being returned from the function or block, or /// being thrown. /// -/// \param AllowFunctionParameter +/// \param AllowFunctionParameter Whether we allow function parameters to +/// be considered NRVO candidates. C++ prohibits this for NRVO itself, but +/// we re-use this logic to determine whether we should try to move as part of +/// a return or throw (which does allow function parameters). /// /// \returns The NRVO candidate variable, if the return statement may use the /// NRVO, or NULL if there is no such candidate. @@ -1525,12 +1531,11 @@ Sema::PerformMoveOrCopyInitialization(const InitializedEntity &Entity, // parameter of the selected constructor is not an rvalue reference // to the object's type (possibly cv-qualified), overload resolution // is performed again, considering the object as an lvalue. - if (Seq.getKind() != InitializationSequence::FailedSequence) { + if (Seq) { for (InitializationSequence::step_iterator Step = Seq.step_begin(), StepEnd = Seq.step_end(); Step != StepEnd; ++Step) { - if (Step->Kind - != InitializationSequence::SK_ConstructorInitialization) + if (Step->Kind != InitializationSequence::SK_ConstructorInitialization) continue; CXXConstructorDecl *Constructor @@ -1583,14 +1588,18 @@ Sema::ActOnBlockReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { if (Result.isInvalid()) return StmtError(); RetValExp = Result.take(); - CurBlock->ReturnType = RetValExp->getType(); - if (BlockDeclRefExpr *CDRE = dyn_cast<BlockDeclRefExpr>(RetValExp)) { - // We have to remove a 'const' added to copied-in variable which was - // part of the implementation spec. and not the actual qualifier for - // the variable. - if (CDRE->isConstQualAdded()) - CurBlock->ReturnType.removeLocalConst(); // FIXME: local??? - } + + if (!RetValExp->isTypeDependent()) { + CurBlock->ReturnType = RetValExp->getType(); + if (BlockDeclRefExpr *CDRE = dyn_cast<BlockDeclRefExpr>(RetValExp)) { + // We have to remove a 'const' added to copied-in variable which was + // part of the implementation spec. and not the actual qualifier for + // the variable. + if (CDRE->isConstQualAdded()) + CurBlock->ReturnType.removeLocalConst(); // FIXME: local??? + } + } else + CurBlock->ReturnType = Context.DependentTy; } else CurBlock->ReturnType = Context.VoidTy; } @@ -1607,13 +1616,17 @@ Sema::ActOnBlockReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { // compatibility to worry about here. ReturnStmt *Result = 0; if (CurBlock->ReturnType->isVoidType()) { - if (RetValExp) { + if (RetValExp && !RetValExp->isTypeDependent() && + (!getLangOptions().CPlusPlus || !RetValExp->getType()->isVoidType())) { Diag(ReturnLoc, diag::err_return_block_has_expr); RetValExp = 0; } Result = new (Context) ReturnStmt(ReturnLoc, RetValExp, 0); } else if (!RetValExp) { - return StmtError(Diag(ReturnLoc, diag::err_block_return_missing_expr)); + if (!CurBlock->ReturnType->isDependentType()) + return StmtError(Diag(ReturnLoc, diag::err_block_return_missing_expr)); + + Result = new (Context) ReturnStmt(ReturnLoc, 0, 0); } else { const VarDecl *NRVOCandidate = 0; @@ -1652,7 +1665,7 @@ Sema::ActOnBlockReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { // If we need to check for the named return value optimization, save the // return statement in our scope for later processing. - if (getLangOptions().CPlusPlus && FnRetType->isRecordType() && + if (getLangOptions().CPlusPlus && FnRetType->isRecordType() && !CurContext->isDependentContext()) FunctionScopes.back()->Returns.push_back(Result); @@ -1661,44 +1674,62 @@ Sema::ActOnBlockReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { StmtResult Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { + // Check for unexpanded parameter packs. + if (RetValExp && DiagnoseUnexpandedParameterPack(RetValExp)) + return StmtError(); + if (getCurBlock()) return ActOnBlockReturnStmt(ReturnLoc, RetValExp); QualType FnRetType; + QualType DeclaredRetType; if (const FunctionDecl *FD = getCurFunctionDecl()) { FnRetType = FD->getResultType(); + DeclaredRetType = FnRetType; if (FD->hasAttr<NoReturnAttr>() || FD->getType()->getAs<FunctionType>()->getNoReturnAttr()) Diag(ReturnLoc, diag::warn_noreturn_function_has_return_expr) << getCurFunctionOrMethodDecl()->getDeclName(); - } else if (ObjCMethodDecl *MD = getCurMethodDecl()) - FnRetType = MD->getResultType(); - else // If we don't have a function/method context, bail. + } else if (ObjCMethodDecl *MD = getCurMethodDecl()) { + DeclaredRetType = MD->getResultType(); + if (MD->hasRelatedResultType() && MD->getClassInterface()) { + // In the implementation of a method with a related return type, the + // type used to type-check the validity of return statements within the + // method body is a pointer to the type of the class being implemented. + FnRetType = Context.getObjCInterfaceType(MD->getClassInterface()); + FnRetType = Context.getObjCObjectPointerType(FnRetType); + } else { + FnRetType = DeclaredRetType; + } + } else // If we don't have a function/method context, bail. return StmtError(); ReturnStmt *Result = 0; if (FnRetType->isVoidType()) { - if (RetValExp && !RetValExp->isTypeDependent()) { - // C99 6.8.6.4p1 (ext_ since GCC warns) - unsigned D = diag::ext_return_has_expr; - if (RetValExp->getType()->isVoidType()) - D = diag::ext_return_has_void_expr; - else { - ExprResult Result = Owned(RetValExp); - Result = IgnoredValueConversions(Result.take()); - if (Result.isInvalid()) - return StmtError(); - RetValExp = Result.take(); - RetValExp = ImpCastExprToType(RetValExp, Context.VoidTy, CK_ToVoid).take(); - } + if (RetValExp) { + if (!RetValExp->isTypeDependent()) { + // C99 6.8.6.4p1 (ext_ since GCC warns) + unsigned D = diag::ext_return_has_expr; + if (RetValExp->getType()->isVoidType()) + D = diag::ext_return_has_void_expr; + else { + ExprResult Result = Owned(RetValExp); + Result = IgnoredValueConversions(Result.take()); + if (Result.isInvalid()) + return StmtError(); + RetValExp = Result.take(); + RetValExp = ImpCastExprToType(RetValExp, + Context.VoidTy, CK_ToVoid).take(); + } - // return (some void expression); is legal in C++. - if (D != diag::ext_return_has_void_expr || - !getLangOptions().CPlusPlus) { - NamedDecl *CurDecl = getCurFunctionOrMethodDecl(); - Diag(ReturnLoc, D) - << CurDecl->getDeclName() << isa<ObjCMethodDecl>(CurDecl) - << RetValExp->getSourceRange(); + // return (some void expression); is legal in C++. + if (D != diag::ext_return_has_void_expr || + !getLangOptions().CPlusPlus) { + NamedDecl *CurDecl = getCurFunctionOrMethodDecl(); + Diag(ReturnLoc, D) + << CurDecl->getDeclName() << isa<ObjCMethodDecl>(CurDecl) + << RetValExp->getSourceRange(); + } } CheckImplicitConversions(RetValExp, ReturnLoc); @@ -1730,7 +1761,7 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { NRVOCandidate = getCopyElisionCandidate(FnRetType, RetValExp, false); InitializedEntity Entity = InitializedEntity::InitializeResult(ReturnLoc, FnRetType, - NRVOCandidate != 0); + NRVOCandidate != 0); ExprResult Res = PerformMoveOrCopyInitialization(Entity, NRVOCandidate, FnRetType, RetValExp); if (Res.isInvalid()) { @@ -1744,6 +1775,17 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { } if (RetValExp) { + // If we type-checked an Objective-C method's return type based + // on a related return type, we may need to adjust the return + // type again. Do so now. + if (DeclaredRetType != FnRetType) { + ExprResult result = PerformImplicitConversion(RetValExp, + DeclaredRetType, + AA_Returning); + if (result.isInvalid()) return StmtError(); + RetValExp = result.take(); + } + CheckImplicitConversions(RetValExp, ReturnLoc); RetValExp = MaybeCreateExprWithCleanups(RetValExp); } @@ -2015,7 +2057,9 @@ StmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc, bool IsSimple, if (InputDomain == AD_Int && OutputDomain == AD_Int && !isOperandMentioned(InputOpNo, Pieces) && InputExpr->isEvaluatable(Context)) { - InputExpr = ImpCastExprToType(InputExpr, OutTy, CK_IntegralCast).take(); + CastKind castKind = + (OutTy->isBooleanType() ? CK_IntegralToBoolean : CK_IntegralCast); + InputExpr = ImpCastExprToType(InputExpr, OutTy, castKind).take(); Exprs[InputOpNo] = InputExpr; NS->setInputExpr(i, InputExpr); continue; @@ -2251,7 +2295,9 @@ Sema::ActOnSEHExceptBlock(SourceLocation Loc, assert(FilterExpr && Block); if(!FilterExpr->getType()->isIntegerType()) { - return StmtError(Diag(FilterExpr->getExprLoc(), diag::err_filter_expression_integral) << FilterExpr->getType()); + return StmtError(Diag(FilterExpr->getExprLoc(), + diag::err_filter_expression_integral) + << FilterExpr->getType()); } return Owned(SEHExceptStmt::Create(Context,Loc,FilterExpr,Block)); diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaTemplate.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaTemplate.cpp index ef09124..5d4caac 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaTemplate.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaTemplate.cpp @@ -92,11 +92,9 @@ void Sema::FilterAcceptableTemplateNames(LookupResult &R) { // ambiguity in certain cases (for example, if it is found in more than // one base class). If all of the injected-class-names that are found // refer to specializations of the same class template, and if the name - // is followed by a template-argument-list, the reference refers to the - // class template itself and not a specialization thereof, and is not + // is used as a template-name, the reference refers to the class + // template itself and not a specialization thereof, and is not // ambiguous. - // - // FIXME: Will we eventually have to do the same for alias templates? if (ClassTemplateDecl *ClassTmpl = dyn_cast<ClassTemplateDecl>(Repl)) if (!ClassTemplates.insert(ClassTmpl)) { filter.erase(); @@ -199,7 +197,8 @@ TemplateNameKind Sema::isTemplateName(Scope *S, // We'll do this lookup again later. R.suppressDiagnostics(); } else { - assert(isa<ClassTemplateDecl>(TD) || isa<TemplateTemplateParmDecl>(TD)); + assert(isa<ClassTemplateDecl>(TD) || isa<TemplateTemplateParmDecl>(TD) || + isa<TypeAliasTemplateDecl>(TD)); TemplateKind = TNK_Type_template; } } @@ -603,8 +602,10 @@ Sema::CheckNonTypeTemplateParameterType(QualType T, SourceLocation Loc) { T->isPointerType() || // -- reference to object or reference to function, T->isReferenceType() || - // -- pointer to member. + // -- pointer to member, T->isMemberPointerType() || + // -- std::nullptr_t. + T->isNullPtrType() || // If T is a dependent type, we can't do the check now, so we // assume that it is well-formed. T->isDependentType()) @@ -919,7 +920,8 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, // the class-key shall agree in kind with the original class // template declaration (7.1.5.3). RecordDecl *PrevRecordDecl = PrevClassTemplate->getTemplatedDecl(); - if (!isAcceptableTagRedeclaration(PrevRecordDecl, Kind, KWLoc, *Name)) { + if (!isAcceptableTagRedeclaration(PrevRecordDecl, Kind, + TUK == TUK_Definition, KWLoc, *Name)) { Diag(KWLoc, diag::err_use_with_wrong_tag) << Name << FixItHint::CreateReplacement(KWLoc, PrevRecordDecl->getKindName()); @@ -1062,6 +1064,7 @@ static bool DiagnoseDefaultTemplateArgument(Sema &S, SourceRange DefArgRange) { switch (TPC) { case Sema::TPC_ClassTemplate: + case Sema::TPC_TypeAliasTemplate: return false; case Sema::TPC_FunctionTemplate: @@ -1187,9 +1190,10 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams, bool MissingDefaultArg = false; // C++0x [temp.param]p11: - // If a template parameter of a primary class template is a template - // parameter pack, it shall be the last template parameter. - if (SawParameterPack && TPC == TPC_ClassTemplate) { + // If a template parameter of a primary class template or alias template + // is a template parameter pack, it shall be the last template parameter. + if (SawParameterPack && + (TPC == TPC_ClassTemplate || TPC == TPC_TypeAliasTemplate)) { Diag(ParameterPackLoc, diag::err_template_param_pack_must_be_last_template_parameter); Invalid = true; @@ -1429,19 +1433,41 @@ struct DependencyChecker : RecursiveASTVisitor<DependencyChecker> { } return super::VisitDeclRefExpr(E); } + + bool TraverseInjectedClassNameType(const InjectedClassNameType *T) { + return TraverseType(T->getInjectedSpecializationType()); + } }; } -/// Determines whether a template-id depends on the given parameter +/// Determines whether a given type depends on the given parameter /// list. static bool -DependsOnTemplateParameters(const TemplateSpecializationType *TemplateId, - TemplateParameterList *Params) { +DependsOnTemplateParameters(QualType T, TemplateParameterList *Params) { DependencyChecker Checker(Params); - Checker.TraverseType(QualType(TemplateId, 0)); + Checker.TraverseType(T); return Checker.Match; } +// Find the source range corresponding to the named type in the given +// nested-name-specifier, if any. +static SourceRange getRangeOfTypeInNestedNameSpecifier(ASTContext &Context, + QualType T, + const CXXScopeSpec &SS) { + NestedNameSpecifierLoc NNSLoc(SS.getScopeRep(), SS.location_data()); + while (NestedNameSpecifier *NNS = NNSLoc.getNestedNameSpecifier()) { + if (const Type *CurType = NNS->getAsType()) { + if (Context.hasSameUnqualifiedType(T, QualType(CurType, 0))) + return NNSLoc.getTypeLoc().getSourceRange(); + } else + break; + + NNSLoc = NNSLoc.getPrefix(); + } + + return SourceRange(); +} + /// \brief Match the given template parameter lists to the given scope /// specifier, returning the template parameter list that applies to the /// name. @@ -1449,6 +1475,8 @@ DependsOnTemplateParameters(const TemplateSpecializationType *TemplateId, /// \param DeclStartLoc the start of the declaration that has a scope /// specifier or a template parameter list. /// +/// \param DeclLoc The location of the declaration itself. +/// /// \param SS the scope specifier that will be matched to the given template /// parameter lists. This scope specifier precedes a qualified name that is /// being declared. @@ -1473,6 +1501,7 @@ DependsOnTemplateParameters(const TemplateSpecializationType *TemplateId, /// itself a template). TemplateParameterList * Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc, + SourceLocation DeclLoc, const CXXScopeSpec &SS, TemplateParameterList **ParamLists, unsigned NumParamLists, @@ -1480,138 +1509,268 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc, bool &IsExplicitSpecialization, bool &Invalid) { IsExplicitSpecialization = false; - - // Find the template-ids that occur within the nested-name-specifier. These - // template-ids will match up with the template parameter lists. - llvm::SmallVector<const TemplateSpecializationType *, 4> - TemplateIdsInSpecifier; - llvm::SmallVector<ClassTemplateSpecializationDecl *, 4> - ExplicitSpecializationsInSpecifier; - for (NestedNameSpecifier *NNS = (NestedNameSpecifier *)SS.getScopeRep(); - NNS; NNS = NNS->getPrefix()) { - const Type *T = NNS->getAsType(); - if (!T) break; - - // C++0x [temp.expl.spec]p17: - // A member or a member template may be nested within many - // enclosing class templates. In an explicit specialization for - // such a member, the member declaration shall be preceded by a - // template<> for each enclosing class template that is - // explicitly specialized. - // - // Following the existing practice of GNU and EDG, we allow a typedef of a - // template specialization type. - while (const TypedefType *TT = dyn_cast<TypedefType>(T)) - T = TT->getDecl()->getUnderlyingType().getTypePtr(); - - if (const TemplateSpecializationType *SpecType - = dyn_cast<TemplateSpecializationType>(T)) { - TemplateDecl *Template = SpecType->getTemplateName().getAsTemplateDecl(); - if (!Template) - continue; // FIXME: should this be an error? probably... - - if (const RecordType *Record = SpecType->getAs<RecordType>()) { - ClassTemplateSpecializationDecl *SpecDecl - = cast<ClassTemplateSpecializationDecl>(Record->getDecl()); - // If the nested name specifier refers to an explicit specialization, - // we don't need a template<> header. - if (SpecDecl->getSpecializationKind() == TSK_ExplicitSpecialization) { - ExplicitSpecializationsInSpecifier.push_back(SpecDecl); - continue; + Invalid = false; + + // The sequence of nested types to which we will match up the template + // parameter lists. We first build this list by starting with the type named + // by the nested-name-specifier and walking out until we run out of types. + llvm::SmallVector<QualType, 4> NestedTypes; + QualType T; + if (SS.getScopeRep()) { + if (CXXRecordDecl *Record + = dyn_cast_or_null<CXXRecordDecl>(computeDeclContext(SS, true))) + T = Context.getTypeDeclType(Record); + else + T = QualType(SS.getScopeRep()->getAsType(), 0); + } + + // If we found an explicit specialization that prevents us from needing + // 'template<>' headers, this will be set to the location of that + // explicit specialization. + SourceLocation ExplicitSpecLoc; + + while (!T.isNull()) { + NestedTypes.push_back(T); + + // Retrieve the parent of a record type. + if (CXXRecordDecl *Record = T->getAsCXXRecordDecl()) { + // If this type is an explicit specialization, we're done. + if (ClassTemplateSpecializationDecl *Spec + = dyn_cast<ClassTemplateSpecializationDecl>(Record)) { + if (!isa<ClassTemplatePartialSpecializationDecl>(Spec) && + Spec->getSpecializationKind() == TSK_ExplicitSpecialization) { + ExplicitSpecLoc = Spec->getLocation(); + break; } + } else if (Record->getTemplateSpecializationKind() + == TSK_ExplicitSpecialization) { + ExplicitSpecLoc = Record->getLocation(); + break; + } + + if (TypeDecl *Parent = dyn_cast<TypeDecl>(Record->getParent())) + T = Context.getTypeDeclType(Parent); + else + T = QualType(); + continue; + } + + if (const TemplateSpecializationType *TST + = T->getAs<TemplateSpecializationType>()) { + if (TemplateDecl *Template = TST->getTemplateName().getAsTemplateDecl()) { + if (TypeDecl *Parent = dyn_cast<TypeDecl>(Template->getDeclContext())) + T = Context.getTypeDeclType(Parent); + else + T = QualType(); + continue; } - - TemplateIdsInSpecifier.push_back(SpecType); } - } - - // Reverse the list of template-ids in the scope specifier, so that we can - // more easily match up the template-ids and the template parameter lists. - std::reverse(TemplateIdsInSpecifier.begin(), TemplateIdsInSpecifier.end()); - - SourceLocation FirstTemplateLoc = DeclStartLoc; - if (NumParamLists) - FirstTemplateLoc = ParamLists[0]->getTemplateLoc(); - - // Match the template-ids found in the specifier to the template parameter - // lists. - unsigned ParamIdx = 0, TemplateIdx = 0; - for (unsigned NumTemplateIds = TemplateIdsInSpecifier.size(); - TemplateIdx != NumTemplateIds; ++TemplateIdx) { - const TemplateSpecializationType *TemplateId - = TemplateIdsInSpecifier[TemplateIdx]; - bool DependentTemplateId = TemplateId->isDependentType(); - - // In friend declarations we can have template-ids which don't - // depend on the corresponding template parameter lists. But - // assume that empty parameter lists are supposed to match this - // template-id. - if (IsFriend && ParamIdx < NumParamLists && ParamLists[ParamIdx]->size()) { - if (!DependentTemplateId || - !DependsOnTemplateParameters(TemplateId, ParamLists[ParamIdx])) - continue; + + // Look one step prior in a dependent template specialization type. + if (const DependentTemplateSpecializationType *DependentTST + = T->getAs<DependentTemplateSpecializationType>()) { + if (NestedNameSpecifier *NNS = DependentTST->getQualifier()) + T = QualType(NNS->getAsType(), 0); + else + T = QualType(); + continue; + } + + // Look one step prior in a dependent name type. + if (const DependentNameType *DependentName = T->getAs<DependentNameType>()){ + if (NestedNameSpecifier *NNS = DependentName->getQualifier()) + T = QualType(NNS->getAsType(), 0); + else + T = QualType(); + continue; + } + + // Retrieve the parent of an enumeration type. + if (const EnumType *EnumT = T->getAs<EnumType>()) { + // FIXME: Forward-declared enums require a TSK_ExplicitSpecialization + // check here. + EnumDecl *Enum = EnumT->getDecl(); + + // Get to the parent type. + if (TypeDecl *Parent = dyn_cast<TypeDecl>(Enum->getParent())) + T = Context.getTypeDeclType(Parent); + else + T = QualType(); + continue; } - if (ParamIdx >= NumParamLists) { - // We have a template-id without a corresponding template parameter - // list. + T = QualType(); + } + // Reverse the nested types list, since we want to traverse from the outermost + // to the innermost while checking template-parameter-lists. + std::reverse(NestedTypes.begin(), NestedTypes.end()); + + // C++0x [temp.expl.spec]p17: + // A member or a member template may be nested within many + // enclosing class templates. In an explicit specialization for + // such a member, the member declaration shall be preceded by a + // template<> for each enclosing class template that is + // explicitly specialized. + bool SawNonEmptyTemplateParameterList = false; + unsigned ParamIdx = 0; + for (unsigned TypeIdx = 0, NumTypes = NestedTypes.size(); TypeIdx != NumTypes; + ++TypeIdx) { + T = NestedTypes[TypeIdx]; + + // Whether we expect a 'template<>' header. + bool NeedEmptyTemplateHeader = false; - // ...which is fine if this is a friend declaration. - if (IsFriend) { - IsExplicitSpecialization = true; - break; + // Whether we expect a template header with parameters. + bool NeedNonemptyTemplateHeader = false; + + // For a dependent type, the set of template parameters that we + // expect to see. + TemplateParameterList *ExpectedTemplateParams = 0; + + // C++0x [temp.expl.spec]p15: + // A member or a member template may be nested within many enclosing + // class templates. In an explicit specialization for such a member, the + // member declaration shall be preceded by a template<> for each + // enclosing class template that is explicitly specialized. + if (CXXRecordDecl *Record = T->getAsCXXRecordDecl()) { + if (ClassTemplatePartialSpecializationDecl *Partial + = dyn_cast<ClassTemplatePartialSpecializationDecl>(Record)) { + ExpectedTemplateParams = Partial->getTemplateParameters(); + NeedNonemptyTemplateHeader = true; + } else if (Record->isDependentType()) { + if (Record->getDescribedClassTemplate()) { + ExpectedTemplateParams = Record->getDescribedClassTemplate() + ->getTemplateParameters(); + NeedNonemptyTemplateHeader = true; + } + } else if (ClassTemplateSpecializationDecl *Spec + = dyn_cast<ClassTemplateSpecializationDecl>(Record)) { + // C++0x [temp.expl.spec]p4: + // Members of an explicitly specialized class template are defined + // in the same manner as members of normal classes, and not using + // the template<> syntax. + if (Spec->getSpecializationKind() != TSK_ExplicitSpecialization) + NeedEmptyTemplateHeader = true; + else + continue; + } else if (Record->getTemplateSpecializationKind()) { + if (Record->getTemplateSpecializationKind() + != TSK_ExplicitSpecialization && + TypeIdx == NumTypes - 1) + IsExplicitSpecialization = true; + + continue; } - - if (DependentTemplateId) { - // FIXME: the location information here isn't great. - Diag(SS.getRange().getBegin(), - diag::err_template_spec_needs_template_parameters) - << QualType(TemplateId, 0) - << SS.getRange(); - Invalid = true; - } else { - Diag(SS.getRange().getBegin(), diag::err_template_spec_needs_header) - << SS.getRange() - << FixItHint::CreateInsertion(FirstTemplateLoc, "template<> "); - IsExplicitSpecialization = true; + } else if (const TemplateSpecializationType *TST + = T->getAs<TemplateSpecializationType>()) { + if (TemplateDecl *Template = TST->getTemplateName().getAsTemplateDecl()) { + ExpectedTemplateParams = Template->getTemplateParameters(); + NeedNonemptyTemplateHeader = true; } - return 0; + } else if (T->getAs<DependentTemplateSpecializationType>()) { + // FIXME: We actually could/should check the template arguments here + // against the corresponding template parameter list. + NeedNonemptyTemplateHeader = false; + } + + // C++ [temp.expl.spec]p16: + // In an explicit specialization declaration for a member of a class + // template or a member template that ap- pears in namespace scope, the + // member template and some of its enclosing class templates may remain + // unspecialized, except that the declaration shall not explicitly + // specialize a class member template if its en- closing class templates + // are not explicitly specialized as well. + if (ParamIdx < NumParamLists) { + if (ParamLists[ParamIdx]->size() == 0) { + if (SawNonEmptyTemplateParameterList) { + Diag(DeclLoc, diag::err_specialize_member_of_template) + << ParamLists[ParamIdx]->getSourceRange(); + Invalid = true; + IsExplicitSpecialization = false; + return 0; + } + } else + SawNonEmptyTemplateParameterList = true; } - - // Check the template parameter list against its corresponding template-id. - if (DependentTemplateId) { - TemplateParameterList *ExpectedTemplateParams = 0; - - // Are there cases in (e.g.) friends where this won't match? - if (const InjectedClassNameType *Injected - = TemplateId->getAs<InjectedClassNameType>()) { - CXXRecordDecl *Record = Injected->getDecl(); - if (ClassTemplatePartialSpecializationDecl *Partial = - dyn_cast<ClassTemplatePartialSpecializationDecl>(Record)) - ExpectedTemplateParams = Partial->getTemplateParameters(); + + if (NeedEmptyTemplateHeader) { + // If we're on the last of the types, and we need a 'template<>' header + // here, then it's an explicit specialization. + if (TypeIdx == NumTypes - 1) + IsExplicitSpecialization = true; + + if (ParamIdx < NumParamLists) { + if (ParamLists[ParamIdx]->size() > 0) { + // The header has template parameters when it shouldn't. Complain. + Diag(ParamLists[ParamIdx]->getTemplateLoc(), + diag::err_template_param_list_matches_nontemplate) + << T + << SourceRange(ParamLists[ParamIdx]->getLAngleLoc(), + ParamLists[ParamIdx]->getRAngleLoc()) + << getRangeOfTypeInNestedNameSpecifier(Context, T, SS); + Invalid = true; + return 0; + } + + // Consume this template header. + ++ParamIdx; + continue; + } + + if (!IsFriend) { + // We don't have a template header, but we should. + SourceLocation ExpectedTemplateLoc; + if (NumParamLists > 0) + ExpectedTemplateLoc = ParamLists[0]->getTemplateLoc(); else - ExpectedTemplateParams = Record->getDescribedClassTemplate() - ->getTemplateParameters(); - } + ExpectedTemplateLoc = DeclStartLoc; - if (ExpectedTemplateParams) - TemplateParameterListsAreEqual(ParamLists[ParamIdx], - ExpectedTemplateParams, - true, TPL_TemplateMatch); - - CheckTemplateParameterList(ParamLists[ParamIdx], 0, - TPC_ClassTemplateMember); - } else if (ParamLists[ParamIdx]->size() > 0) - Diag(ParamLists[ParamIdx]->getTemplateLoc(), - diag::err_template_param_list_matches_nontemplate) - << TemplateId - << ParamLists[ParamIdx]->getSourceRange(); - else - IsExplicitSpecialization = true; + Diag(DeclLoc, diag::err_template_spec_needs_header) + << getRangeOfTypeInNestedNameSpecifier(Context, T, SS) + << FixItHint::CreateInsertion(ExpectedTemplateLoc, "template<> "); + } + + continue; + } + + if (NeedNonemptyTemplateHeader) { + // In friend declarations we can have template-ids which don't + // depend on the corresponding template parameter lists. But + // assume that empty parameter lists are supposed to match this + // template-id. + if (IsFriend && T->isDependentType()) { + if (ParamIdx < NumParamLists && + DependsOnTemplateParameters(T, ParamLists[ParamIdx])) + ExpectedTemplateParams = 0; + else + continue; + } - ++ParamIdx; + if (ParamIdx < NumParamLists) { + // Check the template parameter list, if we can. + if (ExpectedTemplateParams && + !TemplateParameterListsAreEqual(ParamLists[ParamIdx], + ExpectedTemplateParams, + true, TPL_TemplateMatch)) + Invalid = true; + + if (!Invalid && + CheckTemplateParameterList(ParamLists[ParamIdx], 0, + TPC_ClassTemplateMember)) + Invalid = true; + + ++ParamIdx; + continue; + } + + Diag(DeclLoc, diag::err_template_spec_needs_template_parameters) + << T + << getRangeOfTypeInNestedNameSpecifier(Context, T, SS); + Invalid = true; + continue; + } } - + // If there were at least as many template-ids as there were template // parameter lists, then there are no template parameter lists remaining for // the declaration itself. @@ -1619,32 +1778,53 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc, return 0; // If there were too many template parameter lists, complain about that now. - if (ParamIdx != NumParamLists - 1) { - while (ParamIdx < NumParamLists - 1) { - bool isExplicitSpecHeader = ParamLists[ParamIdx]->size() == 0; - Diag(ParamLists[ParamIdx]->getTemplateLoc(), - isExplicitSpecHeader? diag::warn_template_spec_extra_headers - : diag::err_template_spec_extra_headers) - << SourceRange(ParamLists[ParamIdx]->getTemplateLoc(), - ParamLists[ParamIdx]->getRAngleLoc()); - - if (isExplicitSpecHeader && !ExplicitSpecializationsInSpecifier.empty()) { - Diag(ExplicitSpecializationsInSpecifier.back()->getLocation(), - diag::note_explicit_template_spec_does_not_need_header) - << ExplicitSpecializationsInSpecifier.back(); - ExplicitSpecializationsInSpecifier.pop_back(); - } - - // We have a template parameter list with no corresponding scope, which - // means that the resulting template declaration can't be instantiated - // properly (we'll end up with dependent nodes when we shouldn't). - if (!isExplicitSpecHeader) - Invalid = true; - - ++ParamIdx; + if (ParamIdx < NumParamLists - 1) { + bool HasAnyExplicitSpecHeader = false; + bool AllExplicitSpecHeaders = true; + for (unsigned I = ParamIdx; I != NumParamLists - 1; ++I) { + if (ParamLists[I]->size() == 0) + HasAnyExplicitSpecHeader = true; + else + AllExplicitSpecHeaders = false; } + + Diag(ParamLists[ParamIdx]->getTemplateLoc(), + AllExplicitSpecHeaders? diag::warn_template_spec_extra_headers + : diag::err_template_spec_extra_headers) + << SourceRange(ParamLists[ParamIdx]->getTemplateLoc(), + ParamLists[NumParamLists - 2]->getRAngleLoc()); + + // If there was a specialization somewhere, such that 'template<>' is + // not required, and there were any 'template<>' headers, note where the + // specialization occurred. + if (ExplicitSpecLoc.isValid() && HasAnyExplicitSpecHeader) + Diag(ExplicitSpecLoc, + diag::note_explicit_template_spec_does_not_need_header) + << NestedTypes.back(); + + // We have a template parameter list with no corresponding scope, which + // means that the resulting template declaration can't be instantiated + // properly (we'll end up with dependent nodes when we shouldn't). + if (!AllExplicitSpecHeaders) + Invalid = true; } + // C++ [temp.expl.spec]p16: + // In an explicit specialization declaration for a member of a class + // template or a member template that ap- pears in namespace scope, the + // member template and some of its enclosing class templates may remain + // unspecialized, except that the declaration shall not explicitly + // specialize a class member template if its en- closing class templates + // are not explicitly specialized as well. + if (ParamLists[NumParamLists - 1]->size() == 0 && + SawNonEmptyTemplateParameterList) { + Diag(DeclLoc, diag::err_specialize_member_of_template) + << ParamLists[ParamIdx]->getSourceRange(); + Invalid = true; + IsExplicitSpecialization = false; + return 0; + } + // Return the last template parameter list, which corresponds to the // entity being declared. return ParamLists[NumParamLists - 1]; @@ -1655,7 +1835,8 @@ void Sema::NoteAllFoundTemplates(TemplateName Name) { Diag(Template->getLocation(), diag::note_template_declared_here) << (isa<FunctionTemplateDecl>(Template)? 0 : isa<ClassTemplateDecl>(Template)? 1 - : 2) + : isa<TypeAliasTemplateDecl>(Template)? 2 + : 3) << Template->getDeclName(); return; } @@ -1675,13 +1856,24 @@ void Sema::NoteAllFoundTemplates(TemplateName Name) { QualType Sema::CheckTemplateIdType(TemplateName Name, SourceLocation TemplateLoc, TemplateArgumentListInfo &TemplateArgs) { + DependentTemplateName *DTN = Name.getAsDependentTemplateName(); + if (DTN && DTN->isIdentifier()) + // When building a template-id where the template-name is dependent, + // assume the template is a type template. Either our assumption is + // correct, or the code is ill-formed and will be diagnosed when the + // dependent name is substituted. + return Context.getDependentTemplateSpecializationType(ETK_None, + DTN->getQualifier(), + DTN->getIdentifier(), + TemplateArgs); + TemplateDecl *Template = Name.getAsTemplateDecl(); if (!Template || isa<FunctionTemplateDecl>(Template)) { // We might have a substituted template template parameter pack. If so, // build a template specialization type for it. if (Name.getAsSubstTemplateTemplateParmPack()) return Context.getTemplateSpecializationType(Name, TemplateArgs); - + Diag(TemplateLoc, diag::err_template_id_not_a_type) << Name; NoteAllFoundTemplates(Name); @@ -1700,9 +1892,32 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, QualType CanonType; - if (Name.isDependent() || - TemplateSpecializationType::anyDependentTemplateArguments( - TemplateArgs)) { + if (TypeAliasTemplateDecl *AliasTemplate + = dyn_cast<TypeAliasTemplateDecl>(Template)) { + // Find the canonical type for this type alias template specialization. + TypeAliasDecl *Pattern = AliasTemplate->getTemplatedDecl(); + if (Pattern->isInvalidDecl()) + return QualType(); + + TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, + Converted.data(), Converted.size()); + + // Only substitute for the innermost template argument list. + MultiLevelTemplateArgumentList TemplateArgLists; + TemplateArgLists.addOuterTemplateArguments(&TemplateArgs); + unsigned Depth = AliasTemplate->getTemplateParameters()->getDepth(); + for (unsigned I = 0; I < Depth; ++I) + TemplateArgLists.addOuterTemplateArguments(0, 0); + + InstantiatingTemplate Inst(*this, TemplateLoc, Template); + CanonType = SubstType(Pattern->getUnderlyingType(), + TemplateArgLists, AliasTemplate->getLocation(), + AliasTemplate->getDeclName()); + if (CanonType.isNull()) + return QualType(); + } else if (Name.isDependent() || + TemplateSpecializationType::anyDependentTemplateArguments( + TemplateArgs)) { // This class template specialization is a dependent // type. Therefore, its canonical type is another class template // specialization type that contains all of the converted @@ -1894,6 +2109,16 @@ TypeResult Sema::ActOnTagTemplateIdType(TagUseKind TUK, SpecTL.setArgLocInfo(I, TemplateArgs[I].getLocInfo()); return CreateParsedType(T, TLB.getTypeSourceInfo(Context, T)); } + + if (TypeAliasTemplateDecl *TAT = + dyn_cast_or_null<TypeAliasTemplateDecl>(Template.getAsTemplateDecl())) { + // C++0x [dcl.type.elab]p2: + // If the identifier resolves to a typedef-name or the simple-template-id + // resolves to an alias template specialization, the + // elaborated-type-specifier is ill-formed. + Diag(TemplateLoc, diag::err_tag_reference_non_tag) << 4; + Diag(TAT->getLocation(), diag::note_declared_at); + } QualType Result = CheckTemplateIdType(Template, TemplateLoc, TemplateArgs); if (Result.isNull()) @@ -1906,7 +2131,8 @@ TypeResult Sema::ActOnTagTemplateIdType(TagUseKind TUK, IdentifierInfo *Id = D->getIdentifier(); assert(Id && "templated class must have an identifier"); - if (!isAcceptableTagRedeclaration(D, TagKind, TagLoc, *Id)) { + if (!isAcceptableTagRedeclaration(D, TagKind, TUK == TUK_Definition, + TagLoc, *Id)) { Diag(TagLoc, diag::err_use_with_wrong_tag) << Result << FixItHint::CreateReplacement(SourceRange(TagLoc), D->getKindName()); @@ -2485,7 +2711,7 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param, } // We have a template argument that actually does refer to a class - // template, template alias, or template template parameter, and + // template, alias template, or template template parameter, and // therefore cannot be a non-type template argument. Diag(Arg.getLocation(), diag::err_template_arg_must_be_expr) << Arg.getSourceRange(); @@ -2562,7 +2788,8 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param, case TemplateArgument::Type: // We have a template template parameter but the template // argument does not refer to a template. - Diag(Arg.getLocation(), diag::err_template_arg_must_be_template); + Diag(Arg.getLocation(), diag::err_template_arg_must_be_template) + << getLangOptions().CPlusPlus0x; return true; case TemplateArgument::Declaration: @@ -2631,9 +2858,6 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, unsigned ArgIdx = 0; LocalInstantiationScope InstScope(*this, true); while (Param != ParamEnd) { - if (ArgIdx > NumArgs && PartialTemplateArgs) - break; - if (ArgIdx < NumArgs) { // If we have an expanded parameter pack, make sure we don't have too // many arguments. @@ -2674,11 +2898,31 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, continue; } + // If we're checking a partial template argument list, we're done. + if (PartialTemplateArgs) { + if ((*Param)->isTemplateParameterPack() && !ArgumentPack.empty()) + Converted.push_back(TemplateArgument::CreatePackCopy(Context, + ArgumentPack.data(), + ArgumentPack.size())); + + return Invalid; + } + // If we have a template parameter pack with no more corresponding // arguments, just break out now and we'll fill in the argument pack below. if ((*Param)->isTemplateParameterPack()) break; + // If our template is a template template parameter that hasn't acquired + // its proper context yet (e.g., because we're using the template template + // parameter in the signature of a function template, before we've built + // the function template itself), don't attempt substitution of default + // template arguments at this point: we don't have enough context to + // do it properly. + if (isTemplateTemplateParameter && + Template->getDeclContext()->isTranslationUnit()) + break; + // We have a default template argument that we will use. TemplateArgumentLoc Arg; @@ -2689,7 +2933,7 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, // the default argument. if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(*Param)) { if (!TTP->hasDefaultArgument()) { - assert((Invalid || PartialTemplateArgs) && "Missing default argument"); + assert(Invalid && "Missing default argument"); break; } @@ -2707,7 +2951,7 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, } else if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(*Param)) { if (!NTTP->hasDefaultArgument()) { - assert((Invalid || PartialTemplateArgs) && "Missing default argument"); + assert(Invalid && "Missing default argument"); break; } @@ -2726,7 +2970,7 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, = cast<TemplateTemplateParmDecl>(*Param); if (!TempParm->hasDefaultArgument()) { - assert((Invalid || PartialTemplateArgs) && "Missing default argument"); + assert(Invalid && "Missing default argument"); break; } @@ -2772,9 +3016,7 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, // in arguments for non-template parameter packs. if ((*Param)->isTemplateParameterPack()) { - if (PartialTemplateArgs && ArgumentPack.empty()) { - Converted.push_back(TemplateArgument()); - } else if (ArgumentPack.empty()) + if (ArgumentPack.empty()) Converted.push_back(TemplateArgument(0, 0)); else { Converted.push_back(TemplateArgument::CreatePackCopy(Context, @@ -2918,6 +3160,11 @@ bool UnnamedLocalNoLinkageFinder::VisitDecltypeType(const DecltypeType*) { return false; } +bool UnnamedLocalNoLinkageFinder::VisitUnaryTransformType( + const UnaryTransformType*) { + return false; +} + bool UnnamedLocalNoLinkageFinder::VisitAutoType(const AutoType *T) { return Visit(T->getDeducedType()); } @@ -3501,32 +3748,49 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, return ExprError(); } + // Add the value of this argument to the list of converted + // arguments. We use the bitwidth and signedness of the template + // parameter. + if (Arg->isValueDependent()) { + // The argument is value-dependent. Create a new + // TemplateArgument with the converted expression. + Converted = TemplateArgument(Arg); + return Owned(Arg); + } + QualType IntegerType = Context.getCanonicalType(ParamType); if (const EnumType *Enum = IntegerType->getAs<EnumType>()) IntegerType = Context.getCanonicalType(Enum->getDecl()->getIntegerType()); - if (!Arg->isValueDependent()) { + if (ParamType->isBooleanType()) { + // Value must be zero or one. + Value = Value != 0; + unsigned AllowedBits = Context.getTypeSize(IntegerType); + if (Value.getBitWidth() != AllowedBits) + Value = Value.extOrTrunc(AllowedBits); + Value.setIsSigned(IntegerType->isSignedIntegerOrEnumerationType()); + } else { llvm::APSInt OldValue = Value; - + // Coerce the template argument's value to the value it will have // based on the template parameter's type. unsigned AllowedBits = Context.getTypeSize(IntegerType); if (Value.getBitWidth() != AllowedBits) Value = Value.extOrTrunc(AllowedBits); - Value.setIsSigned(IntegerType->isSignedIntegerType()); - + Value.setIsSigned(IntegerType->isSignedIntegerOrEnumerationType()); + // Complain if an unsigned parameter received a negative value. - if (IntegerType->isUnsignedIntegerType() - && (OldValue.isSigned() && OldValue.isNegative())) { + if (IntegerType->isUnsignedIntegerOrEnumerationType() + && (OldValue.isSigned() && OldValue.isNegative())) { Diag(Arg->getSourceRange().getBegin(), diag::warn_template_arg_negative) << OldValue.toString(10) << Value.toString(10) << Param->getType() << Arg->getSourceRange(); Diag(Param->getLocation(), diag::note_template_param_here); } - + // Complain if we overflowed the template parameter's type. unsigned RequiredBits; - if (IntegerType->isUnsignedIntegerType()) + if (IntegerType->isUnsignedIntegerOrEnumerationType()) RequiredBits = OldValue.getActiveBits(); else if (OldValue.isUnsigned()) RequiredBits = OldValue.getActiveBits() + 1; @@ -3541,16 +3805,6 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, } } - // Add the value of this argument to the list of converted - // arguments. We use the bitwidth and signedness of the template - // parameter. - if (Arg->isValueDependent()) { - // The argument is value-dependent. Create a new - // TemplateArgument with the converted expression. - Converted = TemplateArgument(Arg); - return Owned(Arg); - } - Converted = TemplateArgument(Value, ParamType->isEnumeralType() ? ParamType : IntegerType); @@ -3563,10 +3817,17 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, // from a template argument of type std::nullptr_t to a non-type // template parameter of type pointer to object, pointer to // function, or pointer-to-member, respectively. - if (ArgType->isNullPtrType() && - (ParamType->isPointerType() || ParamType->isMemberPointerType())) { - Converted = TemplateArgument((NamedDecl *)0); - return Owned(Arg); + if (ArgType->isNullPtrType()) { + if (ParamType->isPointerType() || ParamType->isMemberPointerType()) { + Converted = TemplateArgument((NamedDecl *)0); + return Owned(Arg); + } + + if (ParamType->isNullPtrType()) { + llvm::APSInt Zero(Context.getTypeSize(Context.NullPtrTy), true); + Converted = TemplateArgument(Zero, Context.NullPtrTy); + return Owned(Arg); + } } // Handle pointer-to-function, reference-to-function, and @@ -3715,9 +3976,10 @@ bool Sema::CheckTemplateArgument(TemplateTemplateParmDecl *Param, return false; } - // C++ [temp.arg.template]p1: + // C++0x [temp.arg.template]p1: // A template-argument for a template template-parameter shall be - // the name of a class template, expressed as id-expression. Only + // the name of a class template or an alias template, expressed as an + // id-expression. When the template-argument names a class template, only // primary class templates are considered when matching the // template template argument with the corresponding parameter; // partial specializations are not considered even if their @@ -3727,7 +3989,8 @@ bool Sema::CheckTemplateArgument(TemplateTemplateParmDecl *Param, // will happen when we are dealing with, e.g., class template // partial specializations. if (!isa<ClassTemplateDecl>(Template) && - !isa<TemplateTemplateParmDecl>(Template)) { + !isa<TemplateTemplateParmDecl>(Template) && + !isa<TypeAliasTemplateDecl>(Template)) { assert(isa<FunctionTemplateDecl>(Template) && "Only function templates are possible here"); Diag(Arg.getLocation(), diag::err_template_arg_not_class_template); @@ -3858,6 +4121,9 @@ Sema::BuildExpressionFromIntegralTemplateArgument(const TemplateArgument &Arg, Arg.getAsIntegral()->getBoolValue(), T, Loc)); + if (T->isNullPtrType()) + return Owned(new (Context) CXXNullPtrLiteralExpr(Context.NullPtrTy, Loc)); + // If this is an enum type that we're instantiating, we need to use an integer // type the same size as the enumerator. We don't want to build an // IntegerLiteral with enum type. @@ -4044,7 +4310,7 @@ Sema::TemplateParameterListsAreEqual(TemplateParameterList *New, // C++0x [temp.arg.template]p3: // A template-argument matches a template template-parameter (call it P) // when each of the template parameters in the template-parameter-list of - // the template-argument's corresponding class template or template alias + // the template-argument's corresponding class template or alias template // (call it A) matches the corresponding template parameter in the // template-parameter-list of P. [...] TemplateParameterList::iterator NewParm = New->begin(); @@ -4442,7 +4708,9 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, // friend declarations. bool Invalid = false; TemplateParameterList *TemplateParams - = MatchTemplateParametersToScopeSpecifier(TemplateNameLoc, SS, + = MatchTemplateParametersToScopeSpecifier(TemplateNameLoc, + TemplateNameLoc, + SS, (TemplateParameterList**)TemplateParameterLists.get(), TemplateParameterLists.size(), TUK == TUK_Friend, @@ -4509,7 +4777,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagTypeKind Kind = TypeWithKeyword::getTagTypeKindForTypeSpec(TagSpec); assert(Kind != TTK_Enum && "Invalid enum tag in class template spec!"); if (!isAcceptableTagRedeclaration(ClassTemplate->getTemplatedDecl(), - Kind, KWLoc, + Kind, TUK == TUK_Definition, KWLoc, *ClassTemplate->getIdentifier())) { Diag(KWLoc, diag::err_use_with_wrong_tag) << ClassTemplate @@ -5180,7 +5448,7 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD, SpecInfo->getPointOfInstantiation(), HasNoEffect)) return true; - + // Mark the prior declaration as an explicit specialization, so that later // clients know that this is an explicit specialization. if (!isFriend) { @@ -5200,7 +5468,8 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD, TemplArgs, /*InsertPos=*/0, SpecInfo->getTemplateSpecializationKind(), TemplArgsAsWritten); - + FD->setStorageClass(Specialization->getStorageClass()); + // The "previous declaration" for this function template specialization is // the prior function template specialization. Previous.clear(); @@ -5479,7 +5748,7 @@ Sema::ActOnExplicitInstantiation(Scope *S, assert(Kind != TTK_Enum && "Invalid enum tag in class template explicit instantiation!"); if (!isAcceptableTagRedeclaration(ClassTemplate->getTemplatedDecl(), - Kind, KWLoc, + Kind, /*isDefinition*/false, KWLoc, *ClassTemplate->getIdentifier())) { Diag(KWLoc, diag::err_use_with_wrong_tag) << ClassTemplate @@ -5801,11 +6070,20 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S, if (R.isNull()) return true; + // C++ [dcl.stc]p1: + // A storage-class-specifier shall not be specified in [...] an explicit + // instantiation (14.7.2) directive. if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef) { - // Cannot explicitly instantiate a typedef. Diag(D.getIdentifierLoc(), diag::err_explicit_instantiation_of_typedef) << Name; return true; + } else if (D.getDeclSpec().getStorageClassSpec() + != DeclSpec::SCS_unspecified) { + // Complain about then remove the storage class specifier. + Diag(D.getIdentifierLoc(), diag::err_explicit_instantiation_storage_class) + << FixItHint::CreateRemoval(D.getDeclSpec().getStorageClassSpecLoc()); + + D.getMutableDeclSpec().ClearStorageClassSpecs(); } // C++0x [temp.explicit]p1: diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaTemplateDeduction.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaTemplateDeduction.cpp index 235af04..7d0ce8b 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -2314,7 +2314,7 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, FunctionTemplate->getLocation(), FunctionTemplate->getSourceRange().getEnd(), 0, Builder, - CTAK_Deduced)) { + CTAK_Specified)) { Info.Param = makeTemplateParameter( const_cast<NamedDecl *>(TemplateParams->getParam(I))); // FIXME: These template arguments are temporary. Free them! @@ -2500,6 +2500,12 @@ static bool AdjustFunctionParmAndArgTypesForDeduction(Sema &S, if (ParamRefType) { QualType PointeeType = ParamRefType->getPointeeType(); + // If the argument has incomplete array type, try to complete it's type. + if (ArgType->isIncompleteArrayType() && + !S.RequireCompleteExprType(Arg, S.PDiag(), + std::make_pair(SourceLocation(), S.PDiag()))) + ArgType = Arg->getType(); + // [C++0x] If P is an rvalue reference to a cv-unqualified // template parameter and the argument is an lvalue, the type // "lvalue reference to A" is used in place of A for type @@ -2507,7 +2513,9 @@ static bool AdjustFunctionParmAndArgTypesForDeduction(Sema &S, if (isa<RValueReferenceType>(ParamType)) { if (!PointeeType.getQualifiers() && isa<TemplateTypeParmType>(PointeeType) && - Arg->Classify(S.Context).isLValue()) + Arg->Classify(S.Context).isLValue() && + Arg->getType() != S.Context.OverloadTy && + Arg->getType() != S.Context.BoundMemberTy) ArgType = S.Context.getLValueReferenceType(ArgType); } @@ -3884,6 +3892,13 @@ MarkUsedTemplateParameters(Sema &SemaRef, QualType T, OnlyDeduced, Depth, Used); break; + case Type::UnaryTransform: + if (!OnlyDeduced) + MarkUsedTemplateParameters(SemaRef, + cast<UnaryTransformType>(T)->getUnderlyingType(), + OnlyDeduced, Depth, Used); + break; + case Type::PackExpansion: MarkUsedTemplateParameters(SemaRef, cast<PackExpansionType>(T)->getPattern(), diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaTemplateInstantiate.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaTemplateInstantiate.cpp index 92ba095..3c19641 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -13,6 +13,7 @@ #include "clang/Sema/SemaInternal.h" #include "TreeTransform.h" #include "clang/Sema/DeclSpec.h" +#include "clang/Sema/Initialization.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/Template.h" #include "clang/Sema/TemplateDeduction.h" @@ -58,9 +59,13 @@ Sema::getTemplateInstantiationArgs(NamedDecl *D, Result.addOuterTemplateArguments(Innermost); DeclContext *Ctx = dyn_cast<DeclContext>(D); - if (!Ctx) + if (!Ctx) { Ctx = D->getDeclContext(); - + + assert((!D->isTemplateParameter() || !Ctx->isTranslationUnit()) && + "Template parameter doesn't have its context yet!"); + } + while (!Ctx->isFileContext()) { // Add template arguments from a class template instantiation. if (ClassTemplateSpecializationDecl *Spec @@ -446,10 +451,15 @@ void Sema::PrintInstantiationStack() { Diags.Report(Active->PointOfInstantiation, DiagID) << Function << Active->InstantiationRange; - } else { + } else if (VarDecl *VD = dyn_cast<VarDecl>(D)) { Diags.Report(Active->PointOfInstantiation, diag::note_template_static_data_member_def_here) - << cast<VarDecl>(D) + << VD + << Active->InstantiationRange; + } else { + Diags.Report(Active->PointOfInstantiation, + diag::note_template_type_alias_instantiation_here) + << cast<TypeAliasTemplateDecl>(D) << Active->InstantiationRange; } break; @@ -918,7 +928,8 @@ TemplateInstantiator::RebuildElaboratedType(SourceLocation KeywordLoc, // like it's likely to produce a lot of spurious errors. if (Keyword != ETK_None && Keyword != ETK_Typename) { TagTypeKind Kind = TypeWithKeyword::getTagTypeKindForKeyword(Keyword); - if (!SemaRef.isAcceptableTagRedeclaration(TD, Kind, TagLocation, *Id)) { + if (!SemaRef.isAcceptableTagRedeclaration(TD, Kind, /*isDefinition*/false, + TagLocation, *Id)) { SemaRef.Diag(TagLocation, diag::err_use_with_wrong_tag) << Id << FixItHint::CreateReplacement(SourceRange(TagLocation), @@ -968,8 +979,7 @@ TemplateName TemplateInstantiator::TransformTemplateName(CXXScopeSpec &SS, } TemplateName Template = Arg.getAsTemplate(); - assert(!Template.isNull() && Template.getAsTemplateDecl() && - "Wrong kind of template template argument"); + assert(!Template.isNull() && "Null template template argument"); // We don't ever want to substitute for a qualified template name, since // the qualifier is handled separately. So, look through the qualified @@ -1384,6 +1394,12 @@ static bool NeedsInstantiationAsFunctionType(TypeSourceInfo *T) { for (unsigned I = 0, E = FP.getNumArgs(); I != E; ++I) { ParmVarDecl *P = FP.getArg(I); + // The parameter's type as written might be dependent even if the + // decayed type was not dependent. + if (TypeSourceInfo *TSInfo = P->getTypeSourceInfo()) + if (TSInfo->getType()->isDependentType()) + return true; + // TODO: currently we always rebuild expressions. When we // properly get lazier about this, we should use the same // logic to avoid rebuilding prototypes here. @@ -1729,6 +1745,8 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, TemplateDeclInstantiator Instantiator(*this, Instantiation, TemplateArgs); llvm::SmallVector<Decl*, 4> Fields; + llvm::SmallVector<std::pair<FieldDecl*, FieldDecl*>, 4> + FieldsWithMemberInitializers; for (RecordDecl::decl_iterator Member = Pattern->decls_begin(), MemberEnd = Pattern->decls_end(); Member != MemberEnd; ++Member) { @@ -1751,9 +1769,13 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, Decl *NewMember = Instantiator.Visit(*Member); if (NewMember) { - if (FieldDecl *Field = dyn_cast<FieldDecl>(NewMember)) + if (FieldDecl *Field = dyn_cast<FieldDecl>(NewMember)) { Fields.push_back(Field); - else if (NewMember->isInvalidDecl()) + FieldDecl *OldField = cast<FieldDecl>(*Member); + if (OldField->getInClassInitializer()) + FieldsWithMemberInitializers.push_back(std::make_pair(OldField, + Field)); + } else if (NewMember->isInvalidDecl()) Invalid = true; } else { // FIXME: Eventually, a NULL return will mean that one of the @@ -1767,6 +1789,43 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, Fields.data(), Fields.size(), SourceLocation(), SourceLocation(), 0); CheckCompletedCXXClass(Instantiation); + + // Attach any in-class member initializers now the class is complete. + for (unsigned I = 0, N = FieldsWithMemberInitializers.size(); I != N; ++I) { + FieldDecl *OldField = FieldsWithMemberInitializers[I].first; + FieldDecl *NewField = FieldsWithMemberInitializers[I].second; + Expr *OldInit = OldField->getInClassInitializer(); + ExprResult NewInit = SubstExpr(OldInit, TemplateArgs); + + // If the initialization is no longer dependent, check it now. + if ((OldField->getType()->isDependentType() || OldInit->isTypeDependent()) + && !NewField->getType()->isDependentType() + && !NewInit.get()->isTypeDependent()) { + // FIXME: handle list-initialization + SourceLocation EqualLoc = NewField->getLocation(); + NewInit = PerformCopyInitialization( + InitializedEntity::InitializeMember(NewField), EqualLoc, + NewInit.release()); + + if (!NewInit.isInvalid()) { + CheckImplicitConversions(NewInit.get(), EqualLoc); + + // C++0x [class.base.init]p7: + // The initialization of each base and member constitutes a + // full-expression. + NewInit = MaybeCreateExprWithCleanups(NewInit); + } + } + + if (NewInit.isInvalid()) + NewField->setInvalidDecl(); + else + NewField->setInClassInitializer(NewInit.release()); + } + + if (!FieldsWithMemberInitializers.empty()) + ActOnFinishDelayedMemberInitializers(Instantiation); + if (Instantiation->isInvalidDecl()) Invalid = true; else { @@ -2009,7 +2068,7 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation, SuppressNew) continue; - if (Function->hasBody()) + if (Function->isDefined()) continue; if (TSK == TSK_ExplicitInstantiationDefinition) { @@ -2019,7 +2078,7 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation, // specialization and is only an explicit instantiation definition // of members whose definition is visible at the point of // instantiation. - if (!Pattern->hasBody()) + if (!Pattern->isDefined()) continue; Function->setTemplateSpecializationKind(TSK, PointOfInstantiation); diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 6e11ef5..e78aa29 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -128,8 +128,8 @@ TemplateDeclInstantiator::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) { return Inst; } -Decl *TemplateDeclInstantiator::VisitTypedefNameDecl(TypedefNameDecl *D, - bool IsTypeAlias) { +Decl *TemplateDeclInstantiator::InstantiateTypedefNameDecl(TypedefNameDecl *D, + bool IsTypeAlias) { bool Invalid = false; TypeSourceInfo *DI = D->getTypeSourceInfo(); if (DI->getType()->isDependentType() || @@ -178,17 +178,62 @@ Decl *TemplateDeclInstantiator::VisitTypedefNameDecl(TypedefNameDecl *D, SemaRef.InstantiateAttrs(TemplateArgs, D, Typedef); Typedef->setAccess(D->getAccess()); - Owner->addDecl(Typedef); return Typedef; } Decl *TemplateDeclInstantiator::VisitTypedefDecl(TypedefDecl *D) { - return VisitTypedefNameDecl(D, /*IsTypeAlias=*/false); + Decl *Typedef = InstantiateTypedefNameDecl(D, /*IsTypeAlias=*/false); + Owner->addDecl(Typedef); + return Typedef; } Decl *TemplateDeclInstantiator::VisitTypeAliasDecl(TypeAliasDecl *D) { - return VisitTypedefNameDecl(D, /*IsTypeAlias=*/true); + Decl *Typedef = InstantiateTypedefNameDecl(D, /*IsTypeAlias=*/true); + Owner->addDecl(Typedef); + return Typedef; +} + +Decl * +TemplateDeclInstantiator::VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) { + // Create a local instantiation scope for this type alias template, which + // will contain the instantiations of the template parameters. + LocalInstantiationScope Scope(SemaRef); + + TemplateParameterList *TempParams = D->getTemplateParameters(); + TemplateParameterList *InstParams = SubstTemplateParams(TempParams); + if (!InstParams) + return 0; + + TypeAliasDecl *Pattern = D->getTemplatedDecl(); + + TypeAliasTemplateDecl *PrevAliasTemplate = 0; + if (Pattern->getPreviousDeclaration()) { + DeclContext::lookup_result Found = Owner->lookup(Pattern->getDeclName()); + if (Found.first != Found.second) { + PrevAliasTemplate = dyn_cast<TypeAliasTemplateDecl>(*Found.first); + } + } + + TypeAliasDecl *AliasInst = cast_or_null<TypeAliasDecl>( + InstantiateTypedefNameDecl(Pattern, /*IsTypeAlias=*/true)); + if (!AliasInst) + return 0; + + TypeAliasTemplateDecl *Inst + = TypeAliasTemplateDecl::Create(SemaRef.Context, Owner, D->getLocation(), + D->getDeclName(), InstParams, AliasInst); + if (PrevAliasTemplate) + Inst->setPreviousDeclaration(PrevAliasTemplate); + + Inst->setAccess(D->getAccess()); + + if (!PrevAliasTemplate) + Inst->setInstantiatedFromMemberTemplate(D); + + Owner->addDecl(Inst); + + return Inst; } /// \brief Instantiate an initializer, breaking it into separate @@ -432,6 +477,7 @@ Decl *TemplateDeclInstantiator::VisitFieldDecl(FieldDecl *D) { D->getLocation(), D->isMutable(), BitWidth, + D->hasInClassInitializer(), D->getTypeSpecStartLoc(), D->getAccess(), 0); @@ -1171,7 +1217,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, D->isThisDeclarationADefinition()) { // Check for a function body. const FunctionDecl *Definition = 0; - if (Function->hasBody(Definition) && + if (Function->isDefined(Definition) && Definition->getTemplateSpecializationKind() == TSK_Undeclared) { SemaRef.Diag(Function->getLocation(), diag::err_redefinition) << Function->getDeclName(); @@ -1203,7 +1249,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, default: if (const FunctionDecl *RPattern = R->getTemplateInstantiationPattern()) - if (RPattern->hasBody(RPattern)) { + if (RPattern->isDefined(RPattern)) { SemaRef.Diag(Function->getLocation(), diag::err_redefinition) << Function->getDeclName(); SemaRef.Diag(R->getLocation(), diag::note_previous_definition); @@ -1219,6 +1265,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, PrincipalDecl->isInIdentifierNamespace(Decl::IDNS_Ordinary)) PrincipalDecl->setNonMemberOperator(); + assert(!D->isDefaulted() && "only methods should be defaulted"); return Function; } @@ -1451,7 +1498,14 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, else Owner->addDecl(DeclToAdd); } - + + if (D->isExplicitlyDefaulted()) { + SemaRef.SetDeclDefaulted(Method, Method->getLocation()); + } else { + assert(!D->isDefaulted() && + "should not implicitly default uninstantiated function"); + } + return Method; } @@ -2079,8 +2133,8 @@ TemplateDeclInstantiator::SubstFunctionType(FunctionDecl *D, bool TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New, FunctionDecl *Tmpl) { - if (Tmpl->isDeleted()) - New->setDeleted(); + if (Tmpl->isDeletedAsWritten()) + New->setDeletedAsWritten(); // If we are performing substituting explicitly-specified template arguments // or deduced template arguments into a function template and we reach this @@ -2186,6 +2240,7 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New, } Expr *NoexceptExpr = 0; if (Expr *OldNoexceptExpr = Proto->getNoexceptExpr()) { + EnterExpressionEvaluationContext Unevaluated(SemaRef, Sema::Unevaluated); ExprResult E = SemaRef.SubstExpr(OldNoexceptExpr, TemplateArgs); if (E.isUsable()) NoexceptExpr = E.take(); @@ -2255,7 +2310,7 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, FunctionDecl *Function, bool Recursive, bool DefinitionRequired) { - if (Function->isInvalidDecl() || Function->hasBody()) + if (Function->isInvalidDecl() || Function->isDefined()) return; // Never instantiate an explicit specialization. @@ -2264,12 +2319,19 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, // Find the function body that we'll be substituting. const FunctionDecl *PatternDecl = Function->getTemplateInstantiationPattern(); - Stmt *Pattern = 0; - if (PatternDecl) - Pattern = PatternDecl->getBody(PatternDecl); + assert(PatternDecl && "instantiating a non-template"); + + Stmt *Pattern = PatternDecl->getBody(PatternDecl); + assert(PatternDecl && "template definition is not a template"); + if (!Pattern) { + // Try to find a defaulted definition + PatternDecl->isDefined(PatternDecl); + } + assert(PatternDecl && "template definition is not a template"); // Postpone late parsed template instantiations. - if (PatternDecl->isLateTemplateParsed() && !LateTemplateParser) { + if (PatternDecl->isLateTemplateParsed() && + !LateTemplateParser) { PendingInstantiations.push_back( std::make_pair(Function, PointOfInstantiation)); return; @@ -2277,13 +2339,13 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, // Call the LateTemplateParser callback if there a need to late parse // a templated function definition. - if (!Pattern && PatternDecl && PatternDecl->isLateTemplateParsed() && + if (!Pattern && PatternDecl->isLateTemplateParsed() && LateTemplateParser) { LateTemplateParser(OpaqueParser, PatternDecl); Pattern = PatternDecl->getBody(PatternDecl); } - if (!Pattern) { + if (!Pattern && !PatternDecl->isDefaulted()) { if (DefinitionRequired) { if (Function->getPrimaryTemplate()) Diag(PointOfInstantiation, @@ -2378,21 +2440,27 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, MultiLevelTemplateArgumentList TemplateArgs = getTemplateInstantiationArgs(Function, 0, false, PatternDecl); - // If this is a constructor, instantiate the member initializers. - if (const CXXConstructorDecl *Ctor = - dyn_cast<CXXConstructorDecl>(PatternDecl)) { - InstantiateMemInitializers(cast<CXXConstructorDecl>(Function), Ctor, - TemplateArgs); - } + if (PatternDecl->isDefaulted()) { + ActOnFinishFunctionBody(Function, 0, /*IsInstantiation=*/true); - // Instantiate the function body. - StmtResult Body = SubstStmt(Pattern, TemplateArgs); + SetDeclDefaulted(Function, PatternDecl->getLocation()); + } else { + // If this is a constructor, instantiate the member initializers. + if (const CXXConstructorDecl *Ctor = + dyn_cast<CXXConstructorDecl>(PatternDecl)) { + InstantiateMemInitializers(cast<CXXConstructorDecl>(Function), Ctor, + TemplateArgs); + } - if (Body.isInvalid()) - Function->setInvalidDecl(); - - ActOnFinishFunctionBody(Function, Body.get(), - /*IsInstantiation=*/true); + // Instantiate the function body. + StmtResult Body = SubstStmt(Pattern, TemplateArgs); + + if (Body.isInvalid()) + Function->setInvalidDecl(); + + ActOnFinishFunctionBody(Function, Body.get(), + /*IsInstantiation=*/true); + } PerformDependentDiagnostics(PatternDecl, TemplateArgs); @@ -2415,9 +2483,13 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, PerformPendingInstantiations(); // Restore the set of pending vtables. + assert(VTableUses.empty() && + "VTableUses should be empty before it is discarded."); VTableUses.swap(SavedVTableUses); // Restore the set of pending implicit instantiations. + assert(PendingInstantiations.empty() && + "PendingInstantiations should be empty before it is discarded."); PendingInstantiations.swap(SavedPendingInstantiations); } } @@ -2484,6 +2556,10 @@ void Sema::InstantiateStaticDataMemberDefinition( == TSK_ExplicitInstantiationDeclaration) return; + // If we already have a definition, we're done. + if (Var->getDefinition()) + return; + InstantiatingTemplate Inst(*this, PointOfInstantiation, Var); if (Inst) return; @@ -2491,9 +2567,12 @@ void Sema::InstantiateStaticDataMemberDefinition( // If we're performing recursive template instantiation, create our own // queue of pending implicit instantiations that we will instantiate later, // while we're still within our own instantiation context. + llvm::SmallVector<VTableUse, 16> SavedVTableUses; std::deque<PendingImplicitInstantiation> SavedPendingInstantiations; - if (Recursive) + if (Recursive) { + VTableUses.swap(SavedVTableUses); PendingInstantiations.swap(SavedPendingInstantiations); + } // Enter the scope of this instantiation. We don't use // PushDeclContext because we don't have a scope. @@ -2515,11 +2594,23 @@ void Sema::InstantiateStaticDataMemberDefinition( } if (Recursive) { + // Define any newly required vtables. + DefineUsedVTables(); + // Instantiate any pending implicit instantiations found during the // instantiation of this template. PerformPendingInstantiations(); + // Restore the set of pending vtables. + assert(VTableUses.empty() && + "VTableUses should be empty before it is discarded, " + "while instantiating static data member."); + VTableUses.swap(SavedVTableUses); + // Restore the set of pending implicit instantiations. + assert(PendingInstantiations.empty() && + "PendingInstantiations should be empty before it is discarded, " + "while instantiating static data member."); PendingInstantiations.swap(SavedPendingInstantiations); } } @@ -3115,10 +3206,7 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D, /// \brief Performs template instantiation for all implicit template /// instantiations we have seen until this point. -/// -/// \returns true if anything was instantiated. -bool Sema::PerformPendingInstantiations(bool LocalOnly) { - bool InstantiatedAnything = false; +void Sema::PerformPendingInstantiations(bool LocalOnly) { while (!PendingLocalImplicitInstantiations.empty() || (!LocalOnly && !PendingInstantiations.empty())) { PendingImplicitInstantiation Inst; @@ -3139,7 +3227,6 @@ bool Sema::PerformPendingInstantiations(bool LocalOnly) { TSK_ExplicitInstantiationDefinition; InstantiateFunctionDefinition(/*FIXME:*/Inst.second, Function, true, DefinitionRequired); - InstantiatedAnything = true; continue; } @@ -3176,10 +3263,7 @@ bool Sema::PerformPendingInstantiations(bool LocalOnly) { TSK_ExplicitInstantiationDefinition; InstantiateStaticDataMemberDefinition(/*FIXME:*/Inst.second, Var, true, DefinitionRequired); - InstantiatedAnything = true; } - - return InstantiatedAnything; } void Sema::PerformDependentDiagnostics(const DeclContext *Pattern, diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaTemplateVariadic.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaTemplateVariadic.cpp index 096d353..86d3bc1 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaTemplateVariadic.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaTemplateVariadic.cpp @@ -617,7 +617,8 @@ bool Sema::containsUnexpandedParameterPacks(Declarator &D) { const DeclSpec &DS = D.getDeclSpec(); switch (DS.getTypeSpecType()) { case TST_typename: - case TST_typeofType: { + case TST_typeofType: + case TST_underlyingType: { QualType T = DS.getRepAsType().get(); if (!T.isNull() && T->containsUnexpandedParameterPack()) return true; diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaType.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaType.cpp index 00ac1d6..5fd8afa 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaType.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaType.cpp @@ -15,6 +15,7 @@ #include "clang/Sema/Template.h" #include "clang/Basic/OpenCL.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/ASTMutationListener.h" #include "clang/AST/CXXInheritance.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" @@ -836,6 +837,18 @@ static QualType ConvertDeclSpecToType(Sema &S, TypeProcessingState &state) { } break; } + case DeclSpec::TST_underlyingType: + Result = S.GetTypeFromParser(DS.getRepAsType()); + assert(!Result.isNull() && "Didn't get a type for __underlying_type?"); + Result = S.BuildUnaryTransformType(Result, + UnaryTransformType::EnumUnderlyingType, + DS.getTypeSpecTypeLoc()); + if (Result.isNull()) { + Result = Context.IntTy; + declarator.setInvalidType(true); + } + break; + case DeclSpec::TST_auto: { // TypeQuals handled by caller. Result = Context.getAutoType(QualType()); @@ -1048,6 +1061,9 @@ QualType Sema::BuildPointerType(QualType T, QualType Sema::BuildReferenceType(QualType T, bool SpelledAsLValue, SourceLocation Loc, DeclarationName Entity) { + assert(Context.getCanonicalType(T) != Context.OverloadTy && + "Unresolved overloaded function type"); + // C++0x [dcl.ref]p6: // If a typedef (7.1.3), a type template-parameter (14.3.1), or a // decltype-specifier (7.1.6.2) denotes a type TR that is a reference to a @@ -1464,41 +1480,37 @@ static void DiagnoseIgnoredQualifiers(unsigned Quals, FixItHint VolatileFixIt; FixItHint RestrictFixIt; + const SourceManager &SM = S.getSourceManager(); + // FIXME: The locations here are set kind of arbitrarily. It'd be nicer to // find a range and grow it to encompass all the qualifiers, regardless of // the order in which they textually appear. if (Quals & Qualifiers::Const) { ConstFixIt = FixItHint::CreateRemoval(ConstQualLoc); - Loc = ConstQualLoc; - ++NumQuals; QualStr = "const"; + ++NumQuals; + if (!Loc.isValid() || SM.isBeforeInTranslationUnit(ConstQualLoc, Loc)) + Loc = ConstQualLoc; } if (Quals & Qualifiers::Volatile) { VolatileFixIt = FixItHint::CreateRemoval(VolatileQualLoc); - if (NumQuals == 0) { - Loc = VolatileQualLoc; - QualStr = "volatile"; - } else { - QualStr += " volatile"; - } + QualStr += (NumQuals == 0 ? "volatile" : " volatile"); ++NumQuals; + if (!Loc.isValid() || SM.isBeforeInTranslationUnit(VolatileQualLoc, Loc)) + Loc = VolatileQualLoc; } if (Quals & Qualifiers::Restrict) { RestrictFixIt = FixItHint::CreateRemoval(RestrictQualLoc); - if (NumQuals == 0) { - Loc = RestrictQualLoc; - QualStr = "restrict"; - } else { - QualStr += " restrict"; - } + QualStr += (NumQuals == 0 ? "restrict" : " restrict"); ++NumQuals; + if (!Loc.isValid() || SM.isBeforeInTranslationUnit(RestrictQualLoc, Loc)) + Loc = RestrictQualLoc; } assert(NumQuals > 0 && "No known qualifiers?"); S.Diag(Loc, diag::warn_qual_return_type) - << QualStr << NumQuals - << ConstFixIt << VolatileFixIt << RestrictFixIt; + << QualStr << NumQuals << ConstFixIt << VolatileFixIt << RestrictFixIt; } /// GetTypeForDeclarator - Convert the type for the specified @@ -1581,6 +1593,8 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, Error = 0; // Function prototype break; case Declarator::MemberContext: + if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static) + break; switch (cast<TagDecl>(CurContext)->getTagKind()) { case TTK_Enum: assert(0 && "unhandled tag kind"); break; case TTK_Struct: Error = 1; /* Struct member */ break; @@ -1601,6 +1615,7 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, Error = 7; // Template type argument break; case Declarator::AliasDeclContext: + case Declarator::AliasTemplateContext: Error = 9; // Type alias break; case Declarator::TypeNameContext: @@ -1659,7 +1674,8 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, // Does this declaration declare a typedef-name? bool IsTypedefName = D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef || - D.getContext() == Declarator::AliasDeclContext; + D.getContext() == Declarator::AliasDeclContext || + D.getContext() == Declarator::AliasTemplateContext; // Walk the DeclTypeInfo, building the recursive type as we go. // DeclTypeInfos are ordered from the identifier out, which is @@ -1839,7 +1855,8 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, // anyway. if (IsTypedefName && FTI.getExceptionSpecType()) Diag(FTI.getExceptionSpecLoc(), diag::err_exception_spec_in_typedef) - << (D.getContext() == Declarator::AliasDeclContext); + << (D.getContext() == Declarator::AliasDeclContext || + D.getContext() == Declarator::AliasTemplateContext); if (!FTI.NumArgs && !FTI.isVariadic && !getLangOptions().CPlusPlus) { // Simple void foo(), where the incoming T is the result type. @@ -2204,6 +2221,7 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, case Declarator::ObjCPrototypeContext: // FIXME: special diagnostic here? case Declarator::TypeNameContext: case Declarator::AliasDeclContext: + case Declarator::AliasTemplateContext: case Declarator::MemberContext: case Declarator::BlockContext: case Declarator::ForContext: @@ -2367,6 +2385,16 @@ namespace { Sema::GetTypeFromParser(DS.getRepAsType(), &TInfo); TL.setUnderlyingTInfo(TInfo); } + void VisitUnaryTransformTypeLoc(UnaryTransformTypeLoc TL) { + // FIXME: This holds only because we only have one unary transform. + assert(DS.getTypeSpecType() == DeclSpec::TST_underlyingType); + TL.setKWLoc(DS.getTypeSpecTypeLoc()); + TL.setParensRange(DS.getTypeofParensRange()); + assert(DS.getRepAsType()); + TypeSourceInfo *TInfo = 0; + Sema::GetTypeFromParser(DS.getRepAsType(), &TInfo); + TL.setUnderlyingTInfo(TInfo); + } void VisitBuiltinTypeLoc(BuiltinTypeLoc TL) { // By default, use the source location of the type specifier. TL.setBuiltinLoc(DS.getTypeSpecTypeLoc()); @@ -2640,13 +2668,17 @@ TypeResult Sema::ActOnTypeName(Scope *S, Declarator &D) { CheckExtraCXXDefaultArguments(D); // C++0x [dcl.type]p3: - // A type-specifier-seq shall not define a class or enumeration - // unless it appears in the type-id of an alias-declaration - // (7.1.3). - if (OwnedTag && OwnedTag->isDefinition() && - D.getContext() != Declarator::AliasDeclContext) - Diag(OwnedTag->getLocation(), diag::err_type_defined_in_type_specifier) - << Context.getTypeDeclType(OwnedTag); + // A type-specifier-seq shall not define a class or enumeration unless + // it appears in the type-id of an alias-declaration (7.1.3) that is not + // the declaration of a template-declaration. + if (OwnedTag && OwnedTag->isDefinition()) { + if (D.getContext() == Declarator::AliasTemplateContext) + Diag(OwnedTag->getLocation(), diag::err_type_defined_in_alias_template) + << Context.getTypeDeclType(OwnedTag); + else if (D.getContext() != Declarator::AliasDeclContext) + Diag(OwnedTag->getLocation(), diag::err_type_defined_in_type_specifier) + << Context.getTypeDeclType(OwnedTag); + } } return CreateParsedType(T, TInfo); @@ -3213,6 +3245,82 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type, } while ((attrs = next)); } +/// \brief Ensure that the type of the given expression is complete. +/// +/// This routine checks whether the expression \p E has a complete type. If the +/// expression refers to an instantiable construct, that instantiation is +/// performed as needed to complete its type. Furthermore +/// Sema::RequireCompleteType is called for the expression's type (or in the +/// case of a reference type, the referred-to type). +/// +/// \param E The expression whose type is required to be complete. +/// \param PD The partial diagnostic that will be printed out if the type cannot +/// be completed. +/// +/// \returns \c true if the type of \p E is incomplete and diagnosed, \c false +/// otherwise. +bool Sema::RequireCompleteExprType(Expr *E, const PartialDiagnostic &PD, + std::pair<SourceLocation, + PartialDiagnostic> Note) { + QualType T = E->getType(); + + // Fast path the case where the type is already complete. + if (!T->isIncompleteType()) + return false; + + // Incomplete array types may be completed by the initializer attached to + // their definitions. For static data members of class templates we need to + // instantiate the definition to get this initializer and complete the type. + if (T->isIncompleteArrayType()) { + if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParens())) { + if (VarDecl *Var = dyn_cast<VarDecl>(DRE->getDecl())) { + if (Var->isStaticDataMember() && + Var->getInstantiatedFromStaticDataMember()) { + + MemberSpecializationInfo *MSInfo = Var->getMemberSpecializationInfo(); + assert(MSInfo && "Missing member specialization information?"); + if (MSInfo->getTemplateSpecializationKind() + != TSK_ExplicitSpecialization) { + // If we don't already have a point of instantiation, this is it. + if (MSInfo->getPointOfInstantiation().isInvalid()) { + MSInfo->setPointOfInstantiation(E->getLocStart()); + + // This is a modification of an existing AST node. Notify + // listeners. + if (ASTMutationListener *L = getASTMutationListener()) + L->StaticDataMemberInstantiated(Var); + } + + InstantiateStaticDataMemberDefinition(E->getExprLoc(), Var); + + // Update the type to the newly instantiated definition's type both + // here and within the expression. + if (VarDecl *Def = Var->getDefinition()) { + DRE->setDecl(Def); + T = Def->getType(); + DRE->setType(T); + E->setType(T); + } + } + + // We still go on to try to complete the type independently, as it + // may also require instantiations or diagnostics if it remains + // incomplete. + } + } + } + } + + // FIXME: Are there other cases which require instantiating something other + // than the type to complete the type of an expression? + + // Look through reference types and complete the referred type. + if (const ReferenceType *Ref = T->getAs<ReferenceType>()) + T = Ref->getPointeeType(); + + return RequireCompleteType(E->getExprLoc(), T, PD, Note); +} + /// @brief Ensure that the type T is a complete type. /// /// This routine checks whether the type @p T is complete in any @@ -3363,3 +3471,27 @@ QualType Sema::BuildDecltypeType(Expr *E, SourceLocation Loc) { return Context.getDecltypeType(E); } + +QualType Sema::BuildUnaryTransformType(QualType BaseType, + UnaryTransformType::UTTKind UKind, + SourceLocation Loc) { + switch (UKind) { + case UnaryTransformType::EnumUnderlyingType: + if (!BaseType->isDependentType() && !BaseType->isEnumeralType()) { + Diag(Loc, diag::err_only_enums_have_underlying_types); + return QualType(); + } else { + QualType Underlying = BaseType; + if (!BaseType->isDependentType()) { + EnumDecl *ED = BaseType->getAs<EnumType>()->getDecl(); + assert(ED && "EnumType has no EnumDecl"); + DiagnoseUseOfDecl(ED, Loc); + Underlying = ED->getIntegerType(); + } + assert(!Underlying.isNull()); + return Context.getUnaryTransformType(BaseType, Underlying, + UnaryTransformType::EnumUnderlyingType); + } + } + llvm_unreachable("unknown unary transform type"); +} diff --git a/contrib/llvm/tools/clang/lib/Sema/TreeTransform.h b/contrib/llvm/tools/clang/lib/Sema/TreeTransform.h index 2a71e14..ff2e46a 100644 --- a/contrib/llvm/tools/clang/lib/Sema/TreeTransform.h +++ b/contrib/llvm/tools/clang/lib/Sema/TreeTransform.h @@ -21,6 +21,7 @@ #include "clang/Sema/ScopeInfo.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclTemplate.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" @@ -701,6 +702,11 @@ public: /// By default, builds a new TypeOfType with the given underlying type. QualType RebuildTypeOfType(QualType Underlying); + /// \brief Build a new unary transform type. + QualType RebuildUnaryTransformType(QualType BaseType, + UnaryTransformType::UTTKind UKind, + SourceLocation Loc); + /// \brief Build a new C++0x decltype type. /// /// By default, performs semantic analysis when building the decltype type. @@ -855,7 +861,7 @@ public: case LookupResult::Found: case LookupResult::FoundOverloaded: case LookupResult::FoundUnresolvedValue: { - NamedDecl *SomeDecl = Result.getRepresentativeDecl(); + NamedDecl *SomeDecl = Result.getRepresentativeDecl(); unsigned Kind = 0; if (isa<TypedefDecl>(SomeDecl)) Kind = 1; else if (isa<TypeAliasDecl>(SomeDecl)) Kind = 2; @@ -863,7 +869,7 @@ public: SemaRef.Diag(IdLoc, diag::err_tag_reference_non_tag) << Kind; SemaRef.Diag(SomeDecl->getLocation(), diag::note_declared_at); break; - } + } default: // FIXME: Would be nice to highlight just the source range. SemaRef.Diag(IdLoc, diag::err_not_tag_in_scope) @@ -873,7 +879,8 @@ public: return QualType(); } - if (!SemaRef.isAcceptableTagRedeclaration(Tag, Kind, IdLoc, *Id)) { + if (!SemaRef.isAcceptableTagRedeclaration(Tag, Kind, /*isDefinition*/false, + IdLoc, *Id)) { SemaRef.Diag(KeywordLoc, diag::err_use_with_wrong_tag) << Id; SemaRef.Diag(Tag->getLocation(), diag::note_previous_use); return QualType(); @@ -1372,7 +1379,7 @@ public: UnaryExprOrTypeTrait ExprKind, SourceRange R) { ExprResult Result - = getSema().CreateUnaryExprOrTypeTraitExpr(SubExpr, OpLoc, ExprKind, R); + = getSema().CreateUnaryExprOrTypeTraitExpr(SubExpr, OpLoc, ExprKind); if (Result.isInvalid()) return ExprError(); @@ -2567,9 +2574,13 @@ TreeTransform<Derived>::TransformNestedNameSpecifierLoc( Q.getLocalEndLoc()); break; } - - SemaRef.Diag(TL.getBeginLoc(), diag::err_nested_name_spec_non_tag) - << TL.getType() << SS.getRange(); + // If the nested-name-specifier is an invalid type def, don't emit an + // error because a previous error should have already been emitted. + TypedefTypeLoc* TTL = dyn_cast<TypedefTypeLoc>(&TL); + if (!TTL || !TTL->getTypedefNameDecl()->isInvalidDecl()) { + SemaRef.Diag(TL.getBeginLoc(), diag::err_nested_name_spec_non_tag) + << TL.getType() << SS.getRange(); + } return NestedNameSpecifierLoc(); } } @@ -4154,6 +4165,29 @@ QualType TreeTransform<Derived>::TransformDecltypeType(TypeLocBuilder &TLB, } template<typename Derived> +QualType TreeTransform<Derived>::TransformUnaryTransformType( + TypeLocBuilder &TLB, + UnaryTransformTypeLoc TL) { + QualType Result = TL.getType(); + if (Result->isDependentType()) { + const UnaryTransformType *T = TL.getTypePtr(); + QualType NewBase = + getDerived().TransformType(TL.getUnderlyingTInfo())->getType(); + Result = getDerived().RebuildUnaryTransformType(NewBase, + T->getUTTKind(), + TL.getKWLoc()); + if (Result.isNull()) + return QualType(); + } + + UnaryTransformTypeLoc NewTL = TLB.push<UnaryTransformTypeLoc>(Result); + NewTL.setKWLoc(TL.getKWLoc()); + NewTL.setParensRange(TL.getParensRange()); + NewTL.setUnderlyingTInfo(TL.getUnderlyingTInfo()); + return Result; +} + +template<typename Derived> QualType TreeTransform<Derived>::TransformAutoType(TypeLocBuilder &TLB, AutoTypeLoc TL) { const AutoType *T = TL.getTypePtr(); @@ -4389,6 +4423,23 @@ QualType TreeTransform<Derived>::TransformTemplateSpecializationType( NewTemplateArgs); if (!Result.isNull()) { + // Specializations of template template parameters are represented as + // TemplateSpecializationTypes, and substitution of type alias templates + // within a dependent context can transform them into + // DependentTemplateSpecializationTypes. + if (isa<DependentTemplateSpecializationType>(Result)) { + DependentTemplateSpecializationTypeLoc NewTL + = TLB.push<DependentTemplateSpecializationTypeLoc>(Result); + NewTL.setKeywordLoc(TL.getTemplateNameLoc()); + NewTL.setQualifierLoc(NestedNameSpecifierLoc()); + NewTL.setNameLoc(TL.getTemplateNameLoc()); + NewTL.setLAngleLoc(TL.getLAngleLoc()); + NewTL.setRAngleLoc(TL.getRAngleLoc()); + for (unsigned i = 0, e = NewTemplateArgs.size(); i != e; ++i) + NewTL.setArgLocInfo(i, NewTemplateArgs[i].getLocInfo()); + return Result; + } + TemplateSpecializationTypeLoc NewTL = TLB.push<TemplateSpecializationTypeLoc>(Result); NewTL.setTemplateNameLoc(TL.getTemplateNameLoc()); @@ -4478,6 +4529,23 @@ TreeTransform<Derived>::TransformElaboratedType(TypeLocBuilder &TLB, if (NamedT.isNull()) return QualType(); + // C++0x [dcl.type.elab]p2: + // If the identifier resolves to a typedef-name or the simple-template-id + // resolves to an alias template specialization, the + // elaborated-type-specifier is ill-formed. + if (T->getKeyword() != ETK_None && T->getKeyword() != ETK_Typename) { + if (const TemplateSpecializationType *TST = + NamedT->getAs<TemplateSpecializationType>()) { + TemplateName Template = TST->getTemplateName(); + if (TypeAliasTemplateDecl *TAT = + dyn_cast_or_null<TypeAliasTemplateDecl>(Template.getAsTemplateDecl())) { + SemaRef.Diag(TL.getNamedTypeLoc().getBeginLoc(), + diag::err_tag_reference_non_tag) << 4; + SemaRef.Diag(TAT->getLocation(), diag::note_declared_at); + } + } + } + QualType Result = TL.getType(); if (getDerived().AlwaysRebuild() || QualifierLoc != TL.getQualifierLoc() || @@ -6629,8 +6697,12 @@ template<typename Derived> ExprResult TreeTransform<Derived>::TransformCXXThisExpr(CXXThisExpr *E) { DeclContext *DC = getSema().getFunctionLevelDeclContext(); - CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(DC); - QualType T = MD->getThisType(getSema().Context); + QualType T; + if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(DC)) + T = MD->getThisType(getSema().Context); + else + T = getSema().Context.getPointerType( + getSema().Context.getRecordType(cast<CXXRecordDecl>(DC))); if (!getDerived().AlwaysRebuild() && T == E->getType()) return SemaRef.Owned(E); @@ -7449,6 +7521,7 @@ TreeTransform<Derived>::TransformUnresolvedMemberExpr(UnresolvedMemberExpr *Old) template<typename Derived> ExprResult TreeTransform<Derived>::TransformCXXNoexceptExpr(CXXNoexceptExpr *E) { + EnterExpressionEvaluationContext Unevaluated(SemaRef, Sema::Unevaluated); ExprResult SubExpr = getDerived().TransformExpr(E->getOperand()); if (SubExpr.isInvalid()) return ExprError(); @@ -7700,6 +7773,11 @@ TreeTransform<Derived>::TransformBlockExpr(BlockExpr *E) { BlockScopeInfo *blockScope = SemaRef.getCurBlock(); blockScope->TheDecl->setIsVariadic(oldBlock->isVariadic()); + // We built a new blockScopeInfo in call to ActOnBlockStart + // in above, CapturesCXXThis need be set here from the block + // expression. + blockScope->CapturesCXXThis = oldBlock->capturesCXXThis(); + llvm::SmallVector<ParmVarDecl*, 4> params; llvm::SmallVector<QualType, 4> paramTypes; @@ -7759,22 +7837,21 @@ TreeTransform<Derived>::TransformBlockExpr(BlockExpr *E) { #ifndef NDEBUG // In builds with assertions, make sure that we captured everything we // captured before. + if (!SemaRef.getDiagnostics().hasErrorOccurred()) { + for (BlockDecl::capture_iterator i = oldBlock->capture_begin(), + e = oldBlock->capture_end(); i != e; ++i) { + VarDecl *oldCapture = i->getVariable(); + + // Ignore parameter packs. + if (isa<ParmVarDecl>(oldCapture) && + cast<ParmVarDecl>(oldCapture)->isParameterPack()) + continue; - if (oldBlock->capturesCXXThis()) assert(blockScope->CapturesCXXThis); - - for (BlockDecl::capture_iterator i = oldBlock->capture_begin(), - e = oldBlock->capture_end(); i != e; ++i) { - VarDecl *oldCapture = i->getVariable(); - - // Ignore parameter packs. - if (isa<ParmVarDecl>(oldCapture) && - cast<ParmVarDecl>(oldCapture)->isParameterPack()) - continue; - - VarDecl *newCapture = - cast<VarDecl>(getDerived().TransformDecl(E->getCaretLocation(), - oldCapture)); - assert(blockScope->CaptureMap.count(newCapture)); + VarDecl *newCapture = + cast<VarDecl>(getDerived().TransformDecl(E->getCaretLocation(), + oldCapture)); + assert(blockScope->CaptureMap.count(newCapture)); + } } #endif @@ -7805,6 +7882,13 @@ TreeTransform<Derived>::TransformBlockDeclRefExpr(BlockDeclRefExpr *E) { ND, NameInfo, 0); } +template<typename Derived> +ExprResult +TreeTransform<Derived>::TransformAsTypeExpr(AsTypeExpr *E) { + assert(false && "Cannot transform asType expressions yet"); + return SemaRef.Owned(E); +} + //===----------------------------------------------------------------------===// // Type reconstruction //===----------------------------------------------------------------------===// @@ -8010,6 +8094,13 @@ QualType TreeTransform<Derived>::RebuildDecltypeType(Expr *E, } template<typename Derived> +QualType TreeTransform<Derived>::RebuildUnaryTransformType(QualType BaseType, + UnaryTransformType::UTTKind UKind, + SourceLocation Loc) { + return SemaRef.BuildUnaryTransformType(BaseType, UKind, Loc); +} + +template<typename Derived> QualType TreeTransform<Derived>::RebuildTemplateSpecializationType( TemplateName Template, SourceLocation TemplateNameLoc, diff --git a/contrib/llvm/tools/clang/lib/Serialization/ASTReader.cpp b/contrib/llvm/tools/clang/lib/Serialization/ASTReader.cpp index d2e41a9..8fb20d2 100644 --- a/contrib/llvm/tools/clang/lib/Serialization/ASTReader.cpp +++ b/contrib/llvm/tools/clang/lib/Serialization/ASTReader.cpp @@ -92,6 +92,7 @@ PCHValidator::ReadLanguageOptions(const LangOptions &LangOpts) { PARSE_LANGOPT_IMPORTANT(AppleKext, diag::warn_pch_apple_kext); PARSE_LANGOPT_IMPORTANT(ObjCDefaultSynthProperties, diag::warn_pch_objc_auto_properties); + PARSE_LANGOPT_BENIGN(ObjCInferRelatedResultType) PARSE_LANGOPT_IMPORTANT(NoConstantCFStrings, diag::warn_pch_no_constant_cfstrings); PARSE_LANGOPT_BENIGN(PascalStrings); @@ -1697,7 +1698,8 @@ namespace { using namespace clang::io; HeaderFileInfo HFI; unsigned Flags = *d++; - HFI.isImport = (Flags >> 3) & 0x01; + HFI.isImport = (Flags >> 4) & 0x01; + HFI.isPragmaOnce = (Flags >> 3) & 0x01; HFI.DirInfo = (Flags >> 1) & 0x03; HFI.Resolved = Flags & 0x01; HFI.NumIncludes = ReadUnalignedLE16(d); @@ -1841,6 +1843,22 @@ MacroDefinition *ASTReader::getMacroDefinition(MacroID ID) { return MacroDefinitionsLoaded[ID - 1]; } +const FileEntry *ASTReader::getFileEntry(llvm::StringRef filenameStrRef) { + std::string Filename = filenameStrRef; + MaybeAddSystemRootToFilename(Filename); + const FileEntry *File = FileMgr.getFile(Filename); + if (File == 0 && !OriginalDir.empty() && !CurrentDir.empty() && + OriginalDir != CurrentDir) { + std::string resolved = resolveFileRelativeToOriginalDir(Filename, + OriginalDir, + CurrentDir); + if (!resolved.empty()) + File = FileMgr.getFile(resolved); + } + + return File; +} + /// \brief If we are loading a relocatable PCH file, and the filename is /// not an absolute path, add the system root to the beginning of the file /// name. @@ -2113,15 +2131,6 @@ ASTReader::ReadASTBlock(PerFileData &F) { TotalVisibleDeclContexts += Record[3]; break; - case TENTATIVE_DEFINITIONS: - // Optimization for the first block. - if (TentativeDefinitions.empty()) - TentativeDefinitions.swap(Record); - else - TentativeDefinitions.insert(TentativeDefinitions.end(), - Record.begin(), Record.end()); - break; - case UNUSED_FILESCOPED_DECLS: // Optimization for the first block. if (UnusedFileScopedDecls.empty()) @@ -2131,6 +2140,15 @@ ASTReader::ReadASTBlock(PerFileData &F) { Record.begin(), Record.end()); break; + case DELEGATING_CTORS: + // Optimization for the first block. + if (DelegatingCtorDecls.empty()) + DelegatingCtorDecls.swap(Record); + else + DelegatingCtorDecls.insert(DelegatingCtorDecls.end(), + Record.begin(), Record.end()); + break; + case WEAK_UNDECLARED_IDENTIFIERS: // Later blocks overwrite earlier ones. WeakUndeclaredIdentifiers.swap(Record); @@ -2176,6 +2194,11 @@ ASTReader::ReadASTBlock(PerFileData &F) { F.LocalSLocSize = Record[1]; break; + case FILE_SOURCE_LOCATION_OFFSETS: + F.SLocFileOffsets = (const uint32_t *)BlobStart; + F.LocalNumSLocFileEntries = Record[0]; + break; + case SOURCE_LOCATION_PRELOADS: if (PreloadSLocEntries.empty()) PreloadSLocEntries.swap(Record); @@ -2236,6 +2259,10 @@ ASTReader::ReadASTBlock(PerFileData &F) { MaybeAddSystemRootToFilename(OriginalFileName); break; + case ORIGINAL_FILE_ID: + OriginalFileID = FileID::get(Record[0]); + break; + case ORIGINAL_PCH_DIR: // The primary AST will be the last to get here, so it will be the one // that's used. @@ -2330,6 +2357,15 @@ ASTReader::ReadASTBlock(PerFileData &F) { // Later tables overwrite earlier ones. OpenCLExtensions.swap(Record); break; + + case TENTATIVE_DEFINITIONS: + // Optimization for the first block. + if (TentativeDefinitions.empty()) + TentativeDefinitions.swap(Record); + else + TentativeDefinitions.insert(TentativeDefinitions.end(), + Record.begin(), Record.end()); + break; } First = false; } @@ -2337,6 +2373,75 @@ ASTReader::ReadASTBlock(PerFileData &F) { return Failure; } +ASTReader::ASTReadResult ASTReader::validateFileEntries() { + for (unsigned CI = 0, CN = Chain.size(); CI != CN; ++CI) { + PerFileData *F = Chain[CI]; + llvm::BitstreamCursor &SLocEntryCursor = F->SLocEntryCursor; + + for (unsigned i = 0, e = F->LocalNumSLocFileEntries; i != e; ++i) { + SLocEntryCursor.JumpToBit(F->SLocFileOffsets[i]); + unsigned Code = SLocEntryCursor.ReadCode(); + if (Code == llvm::bitc::END_BLOCK || + Code == llvm::bitc::ENTER_SUBBLOCK || + Code == llvm::bitc::DEFINE_ABBREV) { + Error("incorrectly-formatted source location entry in AST file"); + return Failure; + } + + RecordData Record; + const char *BlobStart; + unsigned BlobLen; + switch (SLocEntryCursor.ReadRecord(Code, Record, &BlobStart, &BlobLen)) { + default: + Error("incorrectly-formatted source location entry in AST file"); + return Failure; + + case SM_SLOC_FILE_ENTRY: { + llvm::StringRef Filename(BlobStart, BlobLen); + const FileEntry *File = getFileEntry(Filename); + + if (File == 0) { + std::string ErrorStr = "could not find file '"; + ErrorStr += Filename; + ErrorStr += "' referenced by AST file"; + Error(ErrorStr.c_str()); + return IgnorePCH; + } + + if (Record.size() < 6) { + Error("source location entry is incorrect"); + return Failure; + } + + // The stat info from the FileEntry came from the cached stat + // info of the PCH, so we cannot trust it. + struct stat StatBuf; + if (::stat(File->getName(), &StatBuf) != 0) { + StatBuf.st_size = File->getSize(); + StatBuf.st_mtime = File->getModificationTime(); + } + + if (((off_t)Record[4] != StatBuf.st_size +#if !defined(LLVM_ON_WIN32) + // In our regression testing, the Windows file system seems to + // have inconsistent modification times that sometimes + // erroneously trigger this error-handling path. + || (time_t)Record[5] != StatBuf.st_mtime +#endif + )) { + Error(diag::err_fe_pch_file_modified, Filename); + return IgnorePCH; + } + + break; + } + } + } + } + + return Success; +} + ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName, ASTFileType Type) { switch(ReadASTCore(FileName, Type)) { @@ -2347,6 +2452,14 @@ ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName, // Here comes stuff that we only do once the entire chain is loaded. + if (!DisableValidation) { + switch(validateFileEntries()) { + case Failure: return Failure; + case IgnorePCH: return IgnorePCH; + case Success: break; + } + } + // Allocate space for loaded slocentries, identifiers, decls and types. unsigned TotalNumIdentifiers = 0, TotalNumTypes = 0, TotalNumDecls = 0, TotalNumPreallocatedPreprocessingEntities = 0, TotalNumMacroDefs = 0, @@ -2372,7 +2485,7 @@ ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName, PP->getHeaderSearchInfo().SetExternalLookup(this); if (TotalNumPreallocatedPreprocessingEntities > 0) { if (!PP->getPreprocessingRecord()) - PP->createPreprocessingRecord(); + PP->createPreprocessingRecord(true); PP->getPreprocessingRecord()->SetExternalSource(*this, TotalNumPreallocatedPreprocessingEntities); } @@ -2441,12 +2554,15 @@ ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName, // the source manager to the file source file from which the preamble was // built. This is the only valid way to use a precompiled preamble. if (Type == Preamble) { - SourceLocation Loc - = SourceMgr.getLocation(FileMgr.getFile(getOriginalSourceFile()), 1, 1); - if (Loc.isValid()) { - std::pair<FileID, unsigned> Decomposed = SourceMgr.getDecomposedLoc(Loc); - SourceMgr.SetPreambleFileID(Decomposed.first); + if (OriginalFileID.isInvalid()) { + SourceLocation Loc + = SourceMgr.getLocation(FileMgr.getFile(getOriginalSourceFile()), 1, 1); + if (Loc.isValid()) + OriginalFileID = SourceMgr.getDecomposedLoc(Loc).first; } + + if (!OriginalFileID.isInvalid()) + SourceMgr.SetPreambleFileID(OriginalFileID); } return Success; @@ -2571,7 +2687,7 @@ void ASTReader::setPreprocessor(Preprocessor &pp) { TotalNum += Chain[I]->NumPreallocatedPreprocessingEntities; if (TotalNum) { if (!PP->getPreprocessingRecord()) - PP->createPreprocessingRecord(); + PP->createPreprocessingRecord(true); PP->getPreprocessingRecord()->SetExternalSource(*this, TotalNum); } } @@ -2819,6 +2935,7 @@ bool ASTReader::ParseLanguageOptions( PARSE_LANGOPT(ObjCNonFragileABI2); PARSE_LANGOPT(AppleKext); PARSE_LANGOPT(ObjCDefaultSynthProperties); + PARSE_LANGOPT(ObjCInferRelatedResultType); PARSE_LANGOPT(NoConstantCFStrings); PARSE_LANGOPT(PascalStrings); PARSE_LANGOPT(WritableStrings); @@ -3182,6 +3299,13 @@ QualType ASTReader::ReadTypeRecord(unsigned Index) { case TYPE_DECLTYPE: return Context->getDecltypeType(ReadExpr(*Loc.F)); + case TYPE_UNARY_TRANSFORM: { + QualType BaseType = GetType(Record[0]); + QualType UnderlyingType = GetType(Record[1]); + UnaryTransformType::UTTKind UKind = (UnaryTransformType::UTTKind)Record[2]; + return Context->getUnaryTransformType(BaseType, UnderlyingType, UKind); + } + case TYPE_AUTO: return Context->getAutoType(GetType(Record[0])); @@ -3356,14 +3480,14 @@ QualType ASTReader::ReadTypeRecord(unsigned Index) { TemplateName Name = ReadTemplateName(*Loc.F, Record, Idx); llvm::SmallVector<TemplateArgument, 8> Args; ReadTemplateArgumentList(Args, *Loc.F, Record, Idx); - QualType Canon = GetType(Record[Idx++]); + QualType Underlying = GetType(Record[Idx++]); QualType T; - if (Canon.isNull()) + if (Underlying.isNull()) T = Context->getCanonicalTemplateSpecializationType(Name, Args.data(), Args.size()); else T = Context->getTemplateSpecializationType(Name, Args.data(), - Args.size(), Canon); + Args.size(), Underlying); const_cast<Type*>(T.getTypePtr())->setDependent(IsDependent); return T; } @@ -3498,6 +3622,12 @@ void TypeLocReader::VisitTypeOfTypeLoc(TypeOfTypeLoc TL) { void TypeLocReader::VisitDecltypeTypeLoc(DecltypeTypeLoc TL) { TL.setNameLoc(ReadSourceLocation(Record, Idx)); } +void TypeLocReader::VisitUnaryTransformTypeLoc(UnaryTransformTypeLoc TL) { + TL.setKWLoc(ReadSourceLocation(Record, Idx)); + TL.setLParenLoc(ReadSourceLocation(Record, Idx)); + TL.setRParenLoc(ReadSourceLocation(Record, Idx)); + TL.setUnderlyingTInfo(Reader.GetTypeSourceInfo(F, Record, Idx)); +} void TypeLocReader::VisitAutoTypeLoc(AutoTypeLoc TL) { TL.setNameLoc(ReadSourceLocation(Record, Idx)); } @@ -4099,6 +4229,13 @@ void ASTReader::InitializeSema(Sema &S) { SemaObj->UnusedFileScopedDecls.push_back(D); } + // If there were any delegating constructors, add them to Sema's list + for (unsigned I = 0, N = DelegatingCtorDecls.size(); I != N; ++I) { + CXXConstructorDecl *D + = cast<CXXConstructorDecl>(GetDecl(DelegatingCtorDecls[I])); + SemaObj->DelegatingCtorDecls.push_back(D); + } + // If there were any locally-scoped external declarations, // deserialize them and add them to Sema's table of locally-scoped // external declarations. @@ -4710,18 +4847,28 @@ ASTReader::ReadCXXCtorInitializers(PerFileData &F, const RecordData &Record, bool IsBaseVirtual = false; FieldDecl *Member = 0; IndirectFieldDecl *IndirectMember = 0; + CXXConstructorDecl *Target = 0; - bool IsBaseInitializer = Record[Idx++]; - if (IsBaseInitializer) { + CtorInitializerType Type = (CtorInitializerType)Record[Idx++]; + switch (Type) { + case CTOR_INITIALIZER_BASE: BaseClassInfo = GetTypeSourceInfo(F, Record, Idx); IsBaseVirtual = Record[Idx++]; - } else { - bool IsIndirectMemberInitializer = Record[Idx++]; - if (IsIndirectMemberInitializer) - IndirectMember = cast<IndirectFieldDecl>(GetDecl(Record[Idx++])); - else - Member = cast<FieldDecl>(GetDecl(Record[Idx++])); + break; + + case CTOR_INITIALIZER_DELEGATING: + Target = cast<CXXConstructorDecl>(GetDecl(Record[Idx++])); + break; + + case CTOR_INITIALIZER_MEMBER: + Member = cast<FieldDecl>(GetDecl(Record[Idx++])); + break; + + case CTOR_INITIALIZER_INDIRECT_MEMBER: + IndirectMember = cast<IndirectFieldDecl>(GetDecl(Record[Idx++])); + break; } + SourceLocation MemberOrEllipsisLoc = ReadSourceLocation(F, Record, Idx); Expr *Init = ReadExpr(F); SourceLocation LParenLoc = ReadSourceLocation(F, Record, Idx); @@ -4739,10 +4886,13 @@ ASTReader::ReadCXXCtorInitializers(PerFileData &F, const RecordData &Record, } CXXCtorInitializer *BOMInit; - if (IsBaseInitializer) { + if (Type == CTOR_INITIALIZER_BASE) { BOMInit = new (C) CXXCtorInitializer(C, BaseClassInfo, IsBaseVirtual, LParenLoc, Init, RParenLoc, MemberOrEllipsisLoc); + } else if (Type == CTOR_INITIALIZER_DELEGATING) { + BOMInit = new (C) CXXCtorInitializer(C, MemberOrEllipsisLoc, LParenLoc, + Target, Init, RParenLoc); } else if (IsWritten) { if (Member) BOMInit = new (C) CXXCtorInitializer(C, Member, MemberOrEllipsisLoc, @@ -5050,7 +5200,8 @@ ASTReader::~ASTReader() { } ASTReader::PerFileData::PerFileData(ASTFileType Ty) - : Type(Ty), SizeInBits(0), LocalNumSLocEntries(0), SLocOffsets(0), LocalSLocSize(0), + : Type(Ty), SizeInBits(0), LocalNumSLocEntries(0), SLocOffsets(0), + SLocFileOffsets(0), LocalSLocSize(0), LocalNumIdentifiers(0), IdentifierOffsets(0), IdentifierTableData(0), IdentifierLookupTable(0), LocalNumMacroDefinitions(0), MacroDefinitionOffsets(0), diff --git a/contrib/llvm/tools/clang/lib/Serialization/ASTReaderDecl.cpp b/contrib/llvm/tools/clang/lib/Serialization/ASTReaderDecl.cpp index 3a825de..fab2069 100644 --- a/contrib/llvm/tools/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/contrib/llvm/tools/clang/lib/Serialization/ASTReaderDecl.cpp @@ -125,6 +125,7 @@ namespace clang { void VisitClassTemplateDecl(ClassTemplateDecl *D); void VisitFunctionTemplateDecl(FunctionTemplateDecl *D); void VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D); + void VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D); void VisitUsingDecl(UsingDecl *D); void VisitUsingShadowDecl(UsingShadowDecl *D); void VisitLinkageSpecDecl(LinkageSpecDecl *D); @@ -173,6 +174,18 @@ uint64_t ASTDeclReader::GetCurrentCursorOffset() { void ASTDeclReader::Visit(Decl *D) { DeclVisitor<ASTDeclReader, void>::Visit(D); + if (DeclaratorDecl *DD = dyn_cast<DeclaratorDecl>(D)) { + if (DD->DeclInfo) { + DeclaratorDecl::ExtInfo *Info = + DD->DeclInfo.get<DeclaratorDecl::ExtInfo *>(); + Info->TInfo = + GetTypeSourceInfo(Record, Idx); + } + else { + DD->DeclInfo = GetTypeSourceInfo(Record, Idx); + } + } + if (TypeDecl *TD = dyn_cast<TypeDecl>(D)) { // if we have a fully initialized TypeDecl, we can safely read its type now. TD->setTypeForDecl(Reader.GetType(TypeIDForTypeDecl).getTypePtrOrNull()); @@ -307,10 +320,8 @@ void ASTDeclReader::VisitDeclaratorDecl(DeclaratorDecl *DD) { DeclaratorDecl::ExtInfo *Info = new (*Reader.getContext()) DeclaratorDecl::ExtInfo(); ReadQualifierInfo(*Info, Record, Idx); - Info->TInfo = GetTypeSourceInfo(Record, Idx); DD->DeclInfo = Info; - } else - DD->DeclInfo = GetTypeSourceInfo(Record, Idx); + } } void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) { @@ -428,6 +439,8 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) { FD->HasWrittenPrototype = Record[Idx++]; FD->IsDeleted = Record[Idx++]; FD->IsTrivial = Record[Idx++]; + FD->IsDefaulted = Record[Idx++]; + FD->IsExplicitlyDefaulted = Record[Idx++]; FD->HasImplicitReturnZero = Record[Idx++]; FD->EndRangeLoc = ReadSourceLocation(Record, Idx); @@ -455,6 +468,7 @@ void ASTDeclReader::VisitObjCMethodDecl(ObjCMethodDecl *MD) { MD->setDefined(Record[Idx++]); MD->setDeclImplementation((ObjCMethodDecl::ImplementationControl)Record[Idx++]); MD->setObjCDeclQualifier((Decl::ObjCDeclQualifier)Record[Idx++]); + MD->SetRelatedResultType(Record[Idx++]); MD->setNumSelectorArgs(unsigned(Record[Idx++])); MD->setResultType(Reader.GetType(Record[Idx++])); MD->setResultTypeSourceInfo(GetTypeSourceInfo(Record, Idx)); @@ -663,8 +677,11 @@ void ASTDeclReader::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) { void ASTDeclReader::VisitFieldDecl(FieldDecl *FD) { VisitDeclaratorDecl(FD); FD->setMutable(Record[Idx++]); - if (Record[Idx++]) + int BitWidthOrInitializer = Record[Idx++]; + if (BitWidthOrInitializer == 1) FD->setBitWidth(Reader.ReadExpr(F)); + else if (BitWidthOrInitializer == 2) + FD->setInClassInitializer(Reader.ReadExpr(F)); if (!FD->getDeclName()) { FieldDecl *Tmpl = cast_or_null<FieldDecl>(Reader.GetDecl(Record[Idx++])); if (Tmpl) @@ -857,7 +874,8 @@ void ASTDeclReader::ReadCXXDefinitionData( Data.HasPrivateFields = Record[Idx++]; Data.HasProtectedFields = Record[Idx++]; Data.HasPublicFields = Record[Idx++]; - Data.HasTrivialConstructor = Record[Idx++]; + Data.HasMutableFields = Record[Idx++]; + Data.HasTrivialDefaultConstructor = Record[Idx++]; Data.HasConstExprNonCopyMoveConstructor = Record[Idx++]; Data.HasTrivialCopyConstructor = Record[Idx++]; Data.HasTrivialMoveConstructor = Record[Idx++]; @@ -866,6 +884,7 @@ void ASTDeclReader::ReadCXXDefinitionData( Data.HasTrivialDestructor = Record[Idx++]; Data.HasNonLiteralTypeFieldsOrBases = Record[Idx++]; Data.ComputedVisibleConversions = Record[Idx++]; + Data.UserProvidedDefaultConstructor = Record[Idx++]; Data.DeclaredDefaultConstructor = Record[Idx++]; Data.DeclaredCopyConstructor = Record[Idx++]; Data.DeclaredCopyAssignment = Record[Idx++]; @@ -1266,6 +1285,10 @@ void ASTDeclReader::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) { D->ParameterPack = Record[Idx++]; } +void ASTDeclReader::VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) { + VisitRedeclarableTemplateDecl(D); +} + void ASTDeclReader::VisitStaticAssertDecl(StaticAssertDecl *D) { VisitDecl(D); D->AssertExpr = Reader.ReadExpr(F); @@ -1380,7 +1403,7 @@ static bool isConsumerInterestedIn(Decl *D) { return Var->isFileVarDecl() && Var->isThisDeclarationADefinition() == VarDecl::Definition; if (FunctionDecl *Func = dyn_cast<FunctionDecl>(D)) - return Func->isThisDeclarationADefinition(); + return Func->doesThisDeclarationHaveABody(); return isa<ObjCProtocolDecl>(D) || isa<ObjCImplementationDecl>(D); } @@ -1572,6 +1595,9 @@ Decl *ASTReader::ReadDeclRecord(unsigned Index, DeclID ID) { D = TemplateTemplateParmDecl::Create(*Context, 0, SourceLocation(), 0, 0, false, 0, 0); break; + case DECL_TYPE_ALIAS_TEMPLATE: + D = TypeAliasTemplateDecl::Create(*Context, Decl::EmptyShell()); + break; case DECL_STATIC_ASSERT: D = StaticAssertDecl::Create(*Context, 0, SourceLocation(), 0, 0, SourceLocation()); @@ -1626,7 +1652,7 @@ Decl *ASTReader::ReadDeclRecord(unsigned Index, DeclID ID) { break; case DECL_FIELD: D = FieldDecl::Create(*Context, 0, SourceLocation(), SourceLocation(), 0, - QualType(), 0, 0, false); + QualType(), 0, 0, false, false); break; case DECL_INDIRECTFIELD: D = IndirectFieldDecl::Create(*Context, 0, SourceLocation(), 0, QualType(), diff --git a/contrib/llvm/tools/clang/lib/Serialization/ASTReaderStmt.cpp b/contrib/llvm/tools/clang/lib/Serialization/ASTReaderStmt.cpp index 918db7e..f3f67a7 100644 --- a/contrib/llvm/tools/clang/lib/Serialization/ASTReaderStmt.cpp +++ b/contrib/llvm/tools/clang/lib/Serialization/ASTReaderStmt.cpp @@ -189,7 +189,7 @@ namespace clang { void VisitOpaqueValueExpr(OpaqueValueExpr *E); // CUDA Expressions - void VisitCUDAKernelCallExpr(CUDAKernelCallExpr *E); + void VisitCUDAKernelCallExpr(CUDAKernelCallExpr *E); }; } @@ -2000,6 +2000,10 @@ Stmt *ASTReader::ReadStmtFromStream(PerFileData &F) { case EXPR_CUDA_KERNEL_CALL: S = new (Context) CUDAKernelCallExpr(*Context, Empty); break; + + case EXPR_ASTYPE: + S = new (Context) AsTypeExpr(Empty); + break; } // We hit a STMT_STOP, so we're done with this expression. diff --git a/contrib/llvm/tools/clang/lib/Serialization/ASTWriter.cpp b/contrib/llvm/tools/clang/lib/Serialization/ASTWriter.cpp index 6d44fb6..ba9032e 100644 --- a/contrib/llvm/tools/clang/lib/Serialization/ASTWriter.cpp +++ b/contrib/llvm/tools/clang/lib/Serialization/ASTWriter.cpp @@ -223,6 +223,13 @@ void ASTTypeWriter::VisitDecltypeType(const DecltypeType *T) { Code = TYPE_DECLTYPE; } +void ASTTypeWriter::VisitUnaryTransformType(const UnaryTransformType *T) { + Writer.AddTypeRef(T->getBaseType(), Record); + Writer.AddTypeRef(T->getUnderlyingType(), Record); + Record.push_back(T->getUTTKind()); + Code = TYPE_UNARY_TRANSFORM; +} + void ASTTypeWriter::VisitAutoType(const AutoType *T) { Writer.AddTypeRef(T->getDeducedType(), Record); Code = TYPE_AUTO; @@ -277,7 +284,8 @@ ASTTypeWriter::VisitTemplateSpecializationType( for (TemplateSpecializationType::iterator ArgI = T->begin(), ArgE = T->end(); ArgI != ArgE; ++ArgI) Writer.AddTemplateArgument(*ArgI, Record); - Writer.AddTypeRef(T->isCanonicalUnqualified() ? QualType() + Writer.AddTypeRef(T->isTypeAlias() ? T->getAliasedType() : + T->isCanonicalUnqualified() ? QualType() : T->getCanonicalTypeInternal(), Record); Code = TYPE_TEMPLATE_SPECIALIZATION; @@ -493,6 +501,12 @@ void TypeLocWriter::VisitTypeOfTypeLoc(TypeOfTypeLoc TL) { void TypeLocWriter::VisitDecltypeTypeLoc(DecltypeTypeLoc TL) { Writer.AddSourceLocation(TL.getNameLoc(), Record); } +void TypeLocWriter::VisitUnaryTransformTypeLoc(UnaryTransformTypeLoc TL) { + Writer.AddSourceLocation(TL.getKWLoc(), Record); + Writer.AddSourceLocation(TL.getLParenLoc(), Record); + Writer.AddSourceLocation(TL.getRParenLoc(), Record); + Writer.AddTypeSourceInfo(TL.getUnderlyingTInfo(), Record); +} void TypeLocWriter::VisitAutoTypeLoc(AutoTypeLoc TL) { Writer.AddSourceLocation(TL.getNameLoc(), Record); } @@ -726,6 +740,7 @@ void ASTWriter::WriteBlockInfoBlock() { // AST Top-Level Block. BLOCK(AST_BLOCK); RECORD(ORIGINAL_FILE_NAME); + RECORD(ORIGINAL_FILE_ID); RECORD(TYPE_OFFSET); RECORD(DECL_OFFSET); RECORD(LANGUAGE_OPTIONS); @@ -764,6 +779,7 @@ void ASTWriter::WriteBlockInfoBlock() { RECORD(HEADER_SEARCH_TABLE); RECORD(FP_PRAGMA_OPTIONS); RECORD(OPENCL_EXTENSIONS); + RECORD(DELEGATING_CTORS); // SourceManager Block. BLOCK(SOURCE_MANAGER_BLOCK); @@ -873,13 +889,14 @@ void ASTWriter::WriteBlockInfoBlock() { RECORD(DECL_INDIRECTFIELD); RECORD(DECL_EXPANDED_NON_TYPE_TEMPLATE_PARM_PACK); + // Statements and Exprs can occur in the Decls and Types block. + AddStmtsExprs(Stream, Record); + BLOCK(PREPROCESSOR_DETAIL_BLOCK); RECORD(PPD_MACRO_INSTANTIATION); RECORD(PPD_MACRO_DEFINITION); RECORD(PPD_INCLUSION_DIRECTIVE); - // Statements and Exprs can occur in the Decls and Types block. - AddStmtsExprs(Stream, Record); #undef RECORD #undef BLOCK Stream.ExitBlock(); @@ -951,7 +968,7 @@ void ASTWriter::WriteMetadata(ASTContext &Context, const char *isysroot, const std::string &BlobStr = Chain ? Chain->getFileName() : Target.getTriple().getTriple(); Stream.EmitRecordWithBlob(MetaAbbrevCode, Record, BlobStr); - // Original file name + // Original file name and file ID SourceManager &SM = Context.getSourceManager(); if (const FileEntry *MainFile = SM.getFileEntryForID(SM.getMainFileID())) { BitCodeAbbrev *FileAbbrev = new BitCodeAbbrev(); @@ -969,6 +986,10 @@ void ASTWriter::WriteMetadata(ASTContext &Context, const char *isysroot, RecordData Record; Record.push_back(ORIGINAL_FILE_NAME); Stream.EmitRecordWithBlob(FileAbbrevCode, Record, MainFileNameStr); + + Record.clear(); + Record.push_back(SM.getMainFileID().getOpaqueValue()); + Stream.EmitRecord(ORIGINAL_FILE_ID, Record); } // Original PCH directory @@ -1029,6 +1050,7 @@ void ASTWriter::WriteLanguageOptions(const LangOptions &LangOpts) { Record.push_back(LangOpts.AppleKext); // Apple's kernel extensions ABI Record.push_back(LangOpts.ObjCDefaultSynthProperties); // Objective-C auto-synthesized // properties enabled. + Record.push_back(LangOpts.ObjCInferRelatedResultType); Record.push_back(LangOpts.NoConstantCFStrings); // non cfstring generation enabled.. Record.push_back(LangOpts.PascalStrings); // Allow Pascal strings @@ -1280,7 +1302,8 @@ namespace { using namespace clang::io; uint64_t Start = Out.tell(); (void)Start; - unsigned char Flags = (Data.isImport << 3) + unsigned char Flags = (Data.isImport << 4) + | (Data.isPragmaOnce << 3) | (Data.DirInfo << 1) | Data.Resolved; Emit8(Out, (uint8_t)Flags); @@ -1428,6 +1451,9 @@ void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr, // Write out the source location entry table. We skip the first // entry, which is always the same dummy entry. std::vector<uint32_t> SLocEntryOffsets; + // Write out the offsets of only source location file entries. + // We will go through them in ASTReader::validateFileEntries(). + std::vector<uint32_t> SLocFileEntryOffsets; RecordData PreloadSLocs; unsigned BaseSLocID = Chain ? Chain->getTotalNumSLocs() : 0; SLocEntryOffsets.reserve(SourceMgr.sloc_entry_size() - 1 - BaseSLocID); @@ -1442,9 +1468,10 @@ void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr, // Figure out which record code to use. unsigned Code; if (SLoc->isFile()) { - if (SLoc->getFile().getContentCache()->OrigEntry) + if (SLoc->getFile().getContentCache()->OrigEntry) { Code = SM_SLOC_FILE_ENTRY; - else + SLocFileEntryOffsets.push_back(Stream.GetCurrentBitNo()); + } else Code = SM_SLOC_BUFFER_ENTRY; } else Code = SM_SLOC_INSTANTIATION_ENTRY; @@ -1544,6 +1571,18 @@ void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr, Record.push_back(SourceMgr.getNextOffset() - BaseOffset); Stream.EmitRecordWithBlob(SLocOffsetsAbbrev, Record, data(SLocEntryOffsets)); + Abbrev = new BitCodeAbbrev(); + Abbrev->Add(BitCodeAbbrevOp(FILE_SOURCE_LOCATION_OFFSETS)); + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 16)); // # of slocs + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // offsets + unsigned SLocFileOffsetsAbbrev = Stream.EmitAbbrev(Abbrev); + + Record.clear(); + Record.push_back(FILE_SOURCE_LOCATION_OFFSETS); + Record.push_back(SLocFileEntryOffsets.size()); + Stream.EmitRecordWithBlob(SLocFileOffsetsAbbrev, Record, + data(SLocFileEntryOffsets)); + // Write the source location entry preloads array, telling the AST // reader which source locations entries it should load eagerly. Stream.EmitRecord(SOURCE_LOCATION_PRELOADS, PreloadSLocs); @@ -2663,8 +2702,15 @@ ASTWriter::ASTWriter(llvm::BitstreamWriter &Stream) NextSelectorID(FirstSelectorID), FirstMacroID(1), NextMacroID(FirstMacroID), CollectedStmts(&StmtsToEmit), NumStatements(0), NumMacros(0), NumLexicalDeclContexts(0), - NumVisibleDeclContexts(0), FirstCXXBaseSpecifiersID(1), - NextCXXBaseSpecifiersID(1) + NumVisibleDeclContexts(0), + FirstCXXBaseSpecifiersID(1), NextCXXBaseSpecifiersID(1), + DeclParmVarAbbrev(0), DeclContextLexicalAbbrev(0), + DeclContextVisibleLookupAbbrev(0), UpdateVisibleAbbrev(0), + DeclRefExprAbbrev(0), CharacterLiteralAbbrev(0), + DeclRecordAbbrev(0), IntegerLiteralAbbrev(0), + DeclTypedefAbbrev(0), + DeclVarAbbrev(0), DeclFieldAbbrev(0), + DeclEnumAbbrev(0), DeclObjCIvarAbbrev(0) { } @@ -2722,6 +2768,10 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, MemorizeStatCalls *StatCalls, for (unsigned i=0, e = SemaRef.UnusedFileScopedDecls.size(); i !=e; ++i) AddDeclRef(SemaRef.UnusedFileScopedDecls[i], UnusedFileScopedDecls); + RecordData DelegatingCtorDecls; + for (unsigned i=0, e = SemaRef.DelegatingCtorDecls.size(); i != e; ++i) + AddDeclRef(SemaRef.DelegatingCtorDecls[i], DelegatingCtorDecls); + RecordData WeakUndeclaredIdentifiers; if (!SemaRef.WeakUndeclaredIdentifiers.empty()) { WeakUndeclaredIdentifiers.push_back( @@ -2826,7 +2876,7 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, MemorizeStatCalls *StatCalls, // Keep writing types and declarations until all types and // declarations have been written. - Stream.EnterSubblock(DECLTYPES_BLOCK_ID, 3); + Stream.EnterSubblock(DECLTYPES_BLOCK_ID, NUM_ALLOWED_ABBREVS_SIZE); WriteDeclsBlockAbbrevs(); while (!DeclTypesToEmit.empty()) { DeclOrType DOT = DeclTypesToEmit.front(); @@ -2896,6 +2946,10 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, MemorizeStatCalls *StatCalls, // Write the record containing CUDA-specific declaration references. if (!CUDASpecialDeclRefs.empty()) Stream.EmitRecord(CUDA_SPECIAL_DECL_REFS, CUDASpecialDeclRefs); + + // Write the delegating constructors. + if (!DelegatingCtorDecls.empty()) + Stream.EmitRecord(DELEGATING_CTORS, DelegatingCtorDecls); // Some simple statistics Record.clear(); @@ -2970,6 +3024,14 @@ void ASTWriter::WriteASTChain(Sema &SemaRef, MemorizeStatCalls *StatCalls, AddDeclRef(SemaRef.UnusedFileScopedDecls[i], UnusedFileScopedDecls); } + // Build a record containing all of the delegating constructor decls in this + // file. + RecordData DelegatingCtorDecls; + for (unsigned i=0, e = SemaRef.DelegatingCtorDecls.size(); i != e; ++i) { + if (SemaRef.DelegatingCtorDecls[i]->getPCHLevel() == 0) + AddDeclRef(SemaRef.DelegatingCtorDecls[i], DelegatingCtorDecls); + } + // We write the entire table, overwriting the tables from the chain. RecordData WeakUndeclaredIdentifiers; if (!SemaRef.WeakUndeclaredIdentifiers.empty()) { @@ -3044,7 +3106,7 @@ void ASTWriter::WriteASTChain(Sema &SemaRef, MemorizeStatCalls *StatCalls, AddDeclRef(SemaRef.getStdBadAlloc(), SemaDeclRefs); } - Stream.EnterSubblock(DECLTYPES_BLOCK_ID, 3); + Stream.EnterSubblock(DECLTYPES_BLOCK_ID, NUM_ALLOWED_ABBREVS_SIZE); WriteDeclsBlockAbbrevs(); for (DeclsToRewriteTy::iterator I = DeclsToRewrite.begin(), E = DeclsToRewrite.end(); I != E; ++I) @@ -3127,6 +3189,10 @@ void ASTWriter::WriteASTChain(Sema &SemaRef, MemorizeStatCalls *StatCalls, // Write the record containing declaration references of Sema. if (!SemaDeclRefs.empty()) Stream.EmitRecord(SEMA_DECL_REFS, SemaDeclRefs); + + // Write the delegating constructors. + if (!DelegatingCtorDecls.empty()) + Stream.EmitRecord(DELEGATING_CTORS, DelegatingCtorDecls); // Write the updates to DeclContexts. for (llvm::SmallPtrSet<const DeclContext *, 16>::iterator @@ -3152,7 +3218,7 @@ void ASTWriter::WriteDeclUpdatesBlocks() { return; RecordData OffsetsRecord; - Stream.EnterSubblock(DECL_UPDATES_BLOCK_ID, 3); + Stream.EnterSubblock(DECL_UPDATES_BLOCK_ID, NUM_ALLOWED_ABBREVS_SIZE); for (DeclUpdateMap::iterator I = DeclUpdates.begin(), E = DeclUpdates.end(); I != E; ++I) { const Decl *D = I->first; @@ -3743,16 +3809,19 @@ void ASTWriter::AddCXXCtorInitializers( for (unsigned i=0; i != NumCtorInitializers; ++i) { const CXXCtorInitializer *Init = CtorInitializers[i]; - Record.push_back(Init->isBaseInitializer()); if (Init->isBaseInitializer()) { + Record.push_back(CTOR_INITIALIZER_BASE); AddTypeSourceInfo(Init->getBaseClassInfo(), Record); Record.push_back(Init->isBaseVirtual()); + } else if (Init->isDelegatingInitializer()) { + Record.push_back(CTOR_INITIALIZER_DELEGATING); + AddDeclRef(Init->getTargetConstructor(), Record); + } else if (Init->isMemberInitializer()){ + Record.push_back(CTOR_INITIALIZER_MEMBER); + AddDeclRef(Init->getMember(), Record); } else { - Record.push_back(Init->isIndirectMemberInitializer()); - if (Init->isIndirectMemberInitializer()) - AddDeclRef(Init->getIndirectMember(), Record); - else - AddDeclRef(Init->getMember(), Record); + Record.push_back(CTOR_INITIALIZER_INDIRECT_MEMBER); + AddDeclRef(Init->getIndirectMember(), Record); } AddSourceLocation(Init->getMemberLocation(), Record); @@ -3787,7 +3856,8 @@ void ASTWriter::AddCXXDefinitionData(const CXXRecordDecl *D, RecordDataImpl &Rec Record.push_back(Data.HasPrivateFields); Record.push_back(Data.HasProtectedFields); Record.push_back(Data.HasPublicFields); - Record.push_back(Data.HasTrivialConstructor); + Record.push_back(Data.HasMutableFields); + Record.push_back(Data.HasTrivialDefaultConstructor); Record.push_back(Data.HasConstExprNonCopyMoveConstructor); Record.push_back(Data.HasTrivialCopyConstructor); Record.push_back(Data.HasTrivialMoveConstructor); @@ -3796,6 +3866,7 @@ void ASTWriter::AddCXXDefinitionData(const CXXRecordDecl *D, RecordDataImpl &Rec Record.push_back(Data.HasTrivialDestructor); Record.push_back(Data.HasNonLiteralTypeFieldsOrBases); Record.push_back(Data.ComputedVisibleConversions); + Record.push_back(Data.UserProvidedDefaultConstructor); Record.push_back(Data.DeclaredDefaultConstructor); Record.push_back(Data.DeclaredCopyConstructor); Record.push_back(Data.DeclaredCopyAssignment); diff --git a/contrib/llvm/tools/clang/lib/Serialization/ASTWriterDecl.cpp b/contrib/llvm/tools/clang/lib/Serialization/ASTWriterDecl.cpp index 1ca00a3..7c24088 100644 --- a/contrib/llvm/tools/clang/lib/Serialization/ASTWriterDecl.cpp +++ b/contrib/llvm/tools/clang/lib/Serialization/ASTWriterDecl.cpp @@ -86,6 +86,7 @@ namespace clang { void VisitClassTemplateDecl(ClassTemplateDecl *D); void VisitFunctionTemplateDecl(FunctionTemplateDecl *D); void VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D); + void VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D); void VisitUsingDecl(UsingDecl *D); void VisitUsingShadowDecl(UsingShadowDecl *D); void VisitLinkageSpecDecl(LinkageSpecDecl *D); @@ -123,12 +124,19 @@ namespace clang { void ASTDeclWriter::Visit(Decl *D) { DeclVisitor<ASTDeclWriter>::Visit(D); + // Source locations require array (variable-length) abbreviations. The + // abbreviation infrastructure requires that arrays are encoded last, so + // we handle it here in the case of those classes derived from DeclaratorDecl + if (DeclaratorDecl *DD = dyn_cast<DeclaratorDecl>(D)){ + Writer.AddTypeSourceInfo(DD->getTypeSourceInfo(), Record); + } + // Handle FunctionDecl's body here and write it after all other Stmts/Exprs // have been written. We want it last because we will not read it back when // retrieving it from the AST, we'll just lazily set the offset. if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { - Record.push_back(FD->isThisDeclarationADefinition()); - if (FD->isThisDeclarationADefinition()) + Record.push_back(FD->doesThisDeclarationHaveABody()); + if (FD->doesThisDeclarationHaveABody()) Writer.AddStmt(FD->getBody()); } } @@ -168,6 +176,18 @@ void ASTDeclWriter::VisitTypeDecl(TypeDecl *D) { void ASTDeclWriter::VisitTypedefDecl(TypedefDecl *D) { VisitTypeDecl(D); Writer.AddTypeSourceInfo(D->getTypeSourceInfo(), Record); + + if (!D->hasAttrs() && + !D->isImplicit() && + !D->isUsed(false) && + D->getPCHLevel() == 0 && + D->RedeclLink.getNext() == D && + !D->isInvalidDecl() && + !D->isReferenced() && + D->getAccess() == AS_none && + D->getDeclName().getNameKind() == DeclarationName::Identifier) + AbbrevToUse = Writer.getDeclTypedefAbbrev(); + Code = serialization::DECL_TYPEDEF; } @@ -204,6 +224,21 @@ void ASTDeclWriter::VisitEnumDecl(EnumDecl *D) { Record.push_back(D->isScopedUsingClassTag()); Record.push_back(D->isFixed()); Writer.AddDeclRef(D->getInstantiatedFromMemberEnum(), Record); + + if (!D->hasAttrs() && + !D->isImplicit() && + !D->isUsed(false) && + D->getPCHLevel() == 0 && + !D->hasExtInfo() && + D->RedeclLink.getNext() == D && + !D->isInvalidDecl() && + !D->isReferenced() && + D->getAccess() == AS_none && + !CXXRecordDecl::classofKind(D->getKind()) && + !D->getIntegerTypeSourceInfo() && + D->getDeclName().getNameKind() == DeclarationName::Identifier) + AbbrevToUse = Writer.getDeclEnumAbbrev(); + Code = serialization::DECL_ENUM; } @@ -212,6 +247,20 @@ void ASTDeclWriter::VisitRecordDecl(RecordDecl *D) { Record.push_back(D->hasFlexibleArrayMember()); Record.push_back(D->isAnonymousStructOrUnion()); Record.push_back(D->hasObjectMember()); + + if (!D->hasAttrs() && + !D->isImplicit() && + !D->isUsed(false) && + D->getPCHLevel() == 0 && + !D->hasExtInfo() && + D->RedeclLink.getNext() == D && + !D->isInvalidDecl() && + !D->isReferenced() && + D->getAccess() == AS_none && + !CXXRecordDecl::classofKind(D->getKind()) && + D->getDeclName().getNameKind() == DeclarationName::Identifier) + AbbrevToUse = Writer.getDeclRecordAbbrev(); + Code = serialization::DECL_RECORD; } @@ -226,6 +275,7 @@ void ASTDeclWriter::VisitEnumConstantDecl(EnumConstantDecl *D) { if (D->getInitExpr()) Writer.AddStmt(D->getInitExpr()); Writer.AddAPSInt(D->getInitVal(), Record); + Code = serialization::DECL_ENUM_CONSTANT; } @@ -235,7 +285,6 @@ void ASTDeclWriter::VisitDeclaratorDecl(DeclaratorDecl *D) { Record.push_back(D->hasExtInfo()); if (D->hasExtInfo()) Writer.AddQualifierInfo(*D->getExtInfo(), Record); - Writer.AddTypeSourceInfo(D->getTypeSourceInfo(), Record); } void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) { @@ -321,8 +370,10 @@ void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) { Record.push_back(D->isPure()); Record.push_back(D->hasInheritedPrototype()); Record.push_back(D->hasWrittenPrototype()); - Record.push_back(D->isDeleted()); + Record.push_back(D->isDeletedAsWritten()); Record.push_back(D->isTrivial()); + Record.push_back(D->isDefaulted()); + Record.push_back(D->isExplicitlyDefaulted()); Record.push_back(D->hasImplicitReturnZero()); Writer.AddSourceLocation(D->getLocEnd(), Record); @@ -353,6 +404,7 @@ void ASTDeclWriter::VisitObjCMethodDecl(ObjCMethodDecl *D) { Record.push_back(D->getImplementationControl()); // FIXME: stable encoding for in/out/inout/bycopy/byref/oneway Record.push_back(D->getObjCDeclQualifier()); + Record.push_back(D->hasRelatedResultType()); Record.push_back(D->getNumSelectorArgs()); Writer.AddTypeRef(D->getResultType(), Record); Writer.AddTypeSourceInfo(D->getResultTypeSourceInfo(), Record); @@ -413,6 +465,18 @@ void ASTDeclWriter::VisitObjCIvarDecl(ObjCIvarDecl *D) { // FIXME: stable encoding for @public/@private/@protected/@package Record.push_back(D->getAccessControl()); Record.push_back(D->getSynthesize()); + + if (!D->hasAttrs() && + !D->isImplicit() && + !D->isUsed(false) && + !D->isInvalidDecl() && + !D->isReferenced() && + D->getPCHLevel() == 0 && + !D->getBitWidth() && + !D->hasExtInfo() && + D->getDeclName()) + AbbrevToUse = Writer.getDeclObjCIvarAbbrev(); + Code = serialization::DECL_OBJC_IVAR; } @@ -535,11 +599,28 @@ void ASTDeclWriter::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) { void ASTDeclWriter::VisitFieldDecl(FieldDecl *D) { VisitDeclaratorDecl(D); Record.push_back(D->isMutable()); - Record.push_back(D->getBitWidth()? 1 : 0); + Record.push_back(D->getBitWidth()? 1 : D->hasInClassInitializer() ? 2 : 0); if (D->getBitWidth()) Writer.AddStmt(D->getBitWidth()); + else if (D->hasInClassInitializer()) + Writer.AddStmt(D->getInClassInitializer()); if (!D->getDeclName()) Writer.AddDeclRef(Context.getInstantiatedFromUnnamedFieldDecl(D), Record); + + if (!D->hasAttrs() && + !D->isImplicit() && + !D->isUsed(false) && + !D->isInvalidDecl() && + !D->isReferenced() && + D->getPCHLevel() == 0 && + !D->getBitWidth() && + !D->hasInClassInitializer() && + !D->hasExtInfo() && + !ObjCIvarDecl::classofKind(D->getKind()) && + !ObjCAtDefsFieldDecl::classofKind(D->getKind()) && + D->getDeclName()) + AbbrevToUse = Writer.getDeclFieldAbbrev(); + Code = serialization::DECL_FIELD; } @@ -577,6 +658,22 @@ void ASTDeclWriter::VisitVarDecl(VarDecl *D) { Writer.AddSourceLocation(SpecInfo->getPointOfInstantiation(), Record); } + if (!D->hasAttrs() && + !D->isImplicit() && + !D->isUsed(false) && + !D->isInvalidDecl() && + !D->isReferenced() && + D->getAccess() == AS_none && + D->getPCHLevel() == 0 && + D->getDeclName().getNameKind() == DeclarationName::Identifier && + !D->hasExtInfo() && + D->RedeclLink.getNext() == D && + !D->hasCXXDirectInitializer() && + D->getInit() == 0 && + !ParmVarDecl::classofKind(D->getKind()) && + !SpecInfo) + AbbrevToUse = Writer.getDeclVarAbbrev(); + Code = serialization::DECL_VAR; } @@ -601,8 +698,8 @@ void ASTDeclWriter::VisitParmVarDecl(ParmVarDecl *D) { // If the assumptions about the DECL_PARM_VAR abbrev are true, use it. Here // we dynamically check for the properties that we optimize for, but don't // know are true of all PARM_VAR_DECLs. - if (!D->getTypeSourceInfo() && - !D->hasAttrs() && + if (!D->hasAttrs() && + !D->hasExtInfo() && !D->isImplicit() && !D->isUsed(false) && D->getAccess() == AS_none && @@ -615,7 +712,7 @@ void ASTDeclWriter::VisitParmVarDecl(ParmVarDecl *D) { !D->hasInheritedDefaultArg() && D->getInit() == 0 && !D->hasUninstantiatedDefaultArg()) // No default expr. - AbbrevToUse = Writer.getParmVarDeclAbbrev(); + AbbrevToUse = Writer.getDeclParmVarAbbrev(); // Check things we know are true of *every* PARM_VAR_DECL, which is more than // just us assuming it. @@ -1081,6 +1178,11 @@ void ASTDeclWriter::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) { Code = serialization::DECL_TEMPLATE_TEMPLATE_PARM; } +void ASTDeclWriter::VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) { + VisitRedeclarableTemplateDecl(D); + Code = serialization::DECL_TYPE_ALIAS_TEMPLATE; +} + void ASTDeclWriter::VisitStaticAssertDecl(StaticAssertDecl *D) { VisitDecl(D); Writer.AddStmt(D->getAssertExpr()); @@ -1141,10 +1243,161 @@ void ASTDeclWriter::VisitRedeclarable(Redeclarable<T> *D) { void ASTWriter::WriteDeclsBlockAbbrevs() { using namespace llvm; - // Abbreviation for DECL_PARM_VAR. - BitCodeAbbrev *Abv = new BitCodeAbbrev(); - Abv->Add(BitCodeAbbrevOp(serialization::DECL_PARM_VAR)); + BitCodeAbbrev *Abv; + + // Abbreviation for DECL_FIELD + Abv = new BitCodeAbbrev(); + Abv->Add(BitCodeAbbrevOp(serialization::DECL_FIELD)); + // Decl + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalDeclContext + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Location + Abv->Add(BitCodeAbbrevOp(0)); // isInvalidDecl (!?) + Abv->Add(BitCodeAbbrevOp(0)); // HasAttrs + Abv->Add(BitCodeAbbrevOp(0)); // isImplicit + Abv->Add(BitCodeAbbrevOp(0)); // isUsed + Abv->Add(BitCodeAbbrevOp(0)); // isReferenced + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // AccessSpecifier + Abv->Add(BitCodeAbbrevOp(0)); // PCH level + // NamedDecl + Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Name + // ValueDecl + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type + // DeclaratorDecl + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // InnerStartLoc + Abv->Add(BitCodeAbbrevOp(0)); // hasExtInfo + // FieldDecl + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isMutable + Abv->Add(BitCodeAbbrevOp(0)); //getBitWidth + // Type Source Info + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array)); + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // TypeLoc + DeclFieldAbbrev = Stream.EmitAbbrev(Abv); + + // Abbreviation for DECL_OBJC_IVAR + Abv = new BitCodeAbbrev(); + Abv->Add(BitCodeAbbrevOp(serialization::DECL_OBJC_IVAR)); + // Decl + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalDeclContext + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Location + Abv->Add(BitCodeAbbrevOp(0)); // isInvalidDecl (!?) + Abv->Add(BitCodeAbbrevOp(0)); // HasAttrs + Abv->Add(BitCodeAbbrevOp(0)); // isImplicit + Abv->Add(BitCodeAbbrevOp(0)); // isUsed + Abv->Add(BitCodeAbbrevOp(0)); // isReferenced + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // AccessSpecifier + Abv->Add(BitCodeAbbrevOp(0)); // PCH level + // NamedDecl + Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Name + // ValueDecl + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type + // DeclaratorDecl + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // InnerStartLoc + Abv->Add(BitCodeAbbrevOp(0)); // hasExtInfo + // FieldDecl + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isMutable + Abv->Add(BitCodeAbbrevOp(0)); //getBitWidth + // ObjC Ivar + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // getAccessControl + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // getSynthesize + // Type Source Info + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array)); + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // TypeLoc + DeclObjCIvarAbbrev = Stream.EmitAbbrev(Abv); + + // Abbreviation for DECL_ENUM + Abv = new BitCodeAbbrev(); + Abv->Add(BitCodeAbbrevOp(serialization::DECL_ENUM)); + // Decl + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalDeclContext + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Location + Abv->Add(BitCodeAbbrevOp(0)); // isInvalidDecl (!?) + Abv->Add(BitCodeAbbrevOp(0)); // HasAttrs + Abv->Add(BitCodeAbbrevOp(0)); // isImplicit + Abv->Add(BitCodeAbbrevOp(0)); // isUsed + Abv->Add(BitCodeAbbrevOp(0)); // isReferenced + Abv->Add(BitCodeAbbrevOp(AS_none)); // C++ AccessSpecifier + Abv->Add(BitCodeAbbrevOp(0)); // PCH level + // NamedDecl + Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Name + // TypeDecl + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Source Location + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type Ref + // Redeclarable + Abv->Add(BitCodeAbbrevOp(0)); // No redeclaration + // TagDecl + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // IdentifierNamespace + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // getTagKind + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isDefinition + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // EmbeddedInDeclarator + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SourceLocation + Abv->Add(BitCodeAbbrevOp(0)); // hasExtInfo + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // TypedefNameAnonDecl + // EnumDecl + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // AddTypeRef + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // IntegerType + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // getPromotionType + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // getNumPositiveBits + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // getNumNegativeBits + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isScoped + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isScopedUsingClassTag + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isFixed + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // InstantiatedMembEnum + // DC + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalOffset + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // VisibleOffset + DeclEnumAbbrev = Stream.EmitAbbrev(Abv); + + // Abbreviation for DECL_RECORD + Abv = new BitCodeAbbrev(); + Abv->Add(BitCodeAbbrevOp(serialization::DECL_RECORD)); + // Decl + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalDeclContext + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Location + Abv->Add(BitCodeAbbrevOp(0)); // isInvalidDecl (!?) + Abv->Add(BitCodeAbbrevOp(0)); // HasAttrs + Abv->Add(BitCodeAbbrevOp(0)); // isImplicit + Abv->Add(BitCodeAbbrevOp(0)); // isUsed + Abv->Add(BitCodeAbbrevOp(0)); // isReferenced + Abv->Add(BitCodeAbbrevOp(AS_none)); // C++ AccessSpecifier + Abv->Add(BitCodeAbbrevOp(0)); // PCH level + // NamedDecl + Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Name + // TypeDecl + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Source Location + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type Ref + // Redeclarable + Abv->Add(BitCodeAbbrevOp(0)); // No redeclaration + // TagDecl + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // IdentifierNamespace + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // getTagKind + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isDefinition + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // EmbeddedInDeclarator + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SourceLocation + Abv->Add(BitCodeAbbrevOp(0)); // hasExtInfo + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // TypedefNameAnonDecl + // RecordDecl + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // FlexibleArrayMember + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // AnonymousStructUnion + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // hasObjectMember + // DC + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalOffset + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // VisibleOffset + DeclRecordAbbrev = Stream.EmitAbbrev(Abv); + + // Abbreviation for DECL_PARM_VAR + Abv = new BitCodeAbbrev(); + Abv->Add(BitCodeAbbrevOp(serialization::DECL_PARM_VAR)); // Decl Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalDeclContext @@ -1156,7 +1409,6 @@ void ASTWriter::WriteDeclsBlockAbbrevs() { Abv->Add(BitCodeAbbrevOp(0)); // isReferenced Abv->Add(BitCodeAbbrevOp(AS_none)); // C++ AccessSpecifier Abv->Add(BitCodeAbbrevOp(0)); // PCH level - // NamedDecl Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Name @@ -1165,7 +1417,6 @@ void ASTWriter::WriteDeclsBlockAbbrevs() { // DeclaratorDecl Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // InnerStartLoc Abv->Add(BitCodeAbbrevOp(0)); // hasExtInfo - Abv->Add(BitCodeAbbrevOp(serialization::PREDEF_TYPE_NULL_ID)); // InfoType // VarDecl Abv->Add(BitCodeAbbrevOp(0)); // No redeclaration Abv->Add(BitCodeAbbrevOp(0)); // StorageClass @@ -1185,8 +1436,128 @@ void ASTWriter::WriteDeclsBlockAbbrevs() { Abv->Add(BitCodeAbbrevOp(0)); // KNRPromoted Abv->Add(BitCodeAbbrevOp(0)); // HasInheritedDefaultArg Abv->Add(BitCodeAbbrevOp(0)); // HasUninstantiatedDefaultArg + // Type Source Info + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array)); + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // TypeLoc + DeclParmVarAbbrev = Stream.EmitAbbrev(Abv); - ParmVarDeclAbbrev = Stream.EmitAbbrev(Abv); + // Abbreviation for DECL_TYPEDEF + Abv = new BitCodeAbbrev(); + Abv->Add(BitCodeAbbrevOp(serialization::DECL_TYPEDEF)); + // Decl + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalDeclContext + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Location + Abv->Add(BitCodeAbbrevOp(0)); // isInvalidDecl (!?) + Abv->Add(BitCodeAbbrevOp(0)); // HasAttrs + Abv->Add(BitCodeAbbrevOp(0)); // isImplicit + Abv->Add(BitCodeAbbrevOp(0)); // isUsed + Abv->Add(BitCodeAbbrevOp(0)); // isReferenced + Abv->Add(BitCodeAbbrevOp(AS_none)); // C++ AccessSpecifier + Abv->Add(BitCodeAbbrevOp(0)); // PCH level + // NamedDecl + Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Name + // TypeDecl + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Source Location + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type Ref + // TypedefDecl + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array)); + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // TypeLoc + DeclTypedefAbbrev = Stream.EmitAbbrev(Abv); + + // Abbreviation for DECL_VAR + Abv = new BitCodeAbbrev(); + Abv->Add(BitCodeAbbrevOp(serialization::DECL_VAR)); + // Decl + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalDeclContext + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Location + Abv->Add(BitCodeAbbrevOp(0)); // isInvalidDecl (!?) + Abv->Add(BitCodeAbbrevOp(0)); // HasAttrs + Abv->Add(BitCodeAbbrevOp(0)); // isImplicit + Abv->Add(BitCodeAbbrevOp(0)); // isUsed + Abv->Add(BitCodeAbbrevOp(0)); // isReferenced + Abv->Add(BitCodeAbbrevOp(AS_none)); // C++ AccessSpecifier + Abv->Add(BitCodeAbbrevOp(0)); // PCH level + // NamedDecl + Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Name + // ValueDecl + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type + // DeclaratorDecl + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // InnerStartLoc + Abv->Add(BitCodeAbbrevOp(0)); // hasExtInfo + // VarDecl + Abv->Add(BitCodeAbbrevOp(0)); // No redeclaration + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // StorageClass + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // StorageClassAsWritten + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isThreadSpecified + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // CXXDirectInitializer + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isExceptionVariable + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isNRVOVariable + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isCXXForRangeDecl + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // HasInit + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // HasMemberSpecInfo + // Type Source Info + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array)); + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // TypeLoc + DeclVarAbbrev = Stream.EmitAbbrev(Abv); + + // Abbreviation for EXPR_DECL_REF + Abv = new BitCodeAbbrev(); + Abv->Add(BitCodeAbbrevOp(serialization::EXPR_DECL_REF)); + //Stmt + //Expr + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //IsTypeDependent + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //IsValueDependent + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //UnexpandedParamPack + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); //GetValueKind + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); //GetObjectKind + //DeclRefExpr + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //HasQualifier + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //GetDeclFound + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //ExplicitTemplateArgs + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclRef + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Location + DeclRefExprAbbrev = Stream.EmitAbbrev(Abv); + + // Abbreviation for EXPR_INTEGER_LITERAL + Abv = new BitCodeAbbrev(); + Abv->Add(BitCodeAbbrevOp(serialization::EXPR_INTEGER_LITERAL)); + //Stmt + //Expr + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //IsTypeDependent + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //IsValueDependent + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //UnexpandedParamPack + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); //GetValueKind + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); //GetObjectKind + //Integer Literal + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Location + Abv->Add(BitCodeAbbrevOp(32)); // Bit Width + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Value + IntegerLiteralAbbrev = Stream.EmitAbbrev(Abv); + + // Abbreviation for EXPR_CHARACTER_LITERAL + Abv = new BitCodeAbbrev(); + Abv->Add(BitCodeAbbrevOp(serialization::EXPR_CHARACTER_LITERAL)); + //Stmt + //Expr + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //IsTypeDependent + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //IsValueDependent + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //UnexpandedParamPack + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); //GetValueKind + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); //GetObjectKind + //Character Literal + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // getValue + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Location + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //IsWide + CharacterLiteralAbbrev = Stream.EmitAbbrev(Abv); Abv = new BitCodeAbbrev(); Abv->Add(BitCodeAbbrevOp(serialization::DECL_CONTEXT_LEXICAL)); diff --git a/contrib/llvm/tools/clang/lib/Serialization/ASTWriterStmt.cpp b/contrib/llvm/tools/clang/lib/Serialization/ASTWriterStmt.cpp index bd5889a..00e2404 100644 --- a/contrib/llvm/tools/clang/lib/Serialization/ASTWriterStmt.cpp +++ b/contrib/llvm/tools/clang/lib/Serialization/ASTWriterStmt.cpp @@ -30,6 +30,7 @@ namespace clang { public: serialization::StmtCode Code; + unsigned AbbrevToUse; ASTStmtWriter(ASTWriter &Writer, ASTWriter::RecordData &Record) : Writer(Writer), Record(Record) { } @@ -164,6 +165,8 @@ namespace clang { // CUDA Expressions void VisitCUDAKernelCallExpr(CUDAKernelCallExpr *E); + + void VisitAsTypeExpr(AsTypeExpr *E); }; } @@ -392,6 +395,14 @@ void ASTStmtWriter::VisitDeclRefExpr(DeclRefExpr *E) { Record.push_back(NumTemplateArgs); } + DeclarationName::NameKind nk = (E->getDecl()->getDeclName().getNameKind()); + + if ((!E->hasExplicitTemplateArgs()) && (!E->hasQualifier()) && + (E->getDecl() == E->getFoundDecl()) && + nk == DeclarationName::Identifier) { + AbbrevToUse = Writer.getDeclRefExprAbbrev(); + } + if (E->hasQualifier()) Writer.AddNestedNameSpecifierLoc(E->getQualifierLoc(), Record); @@ -411,6 +422,11 @@ void ASTStmtWriter::VisitIntegerLiteral(IntegerLiteral *E) { VisitExpr(E); Writer.AddSourceLocation(E->getLocation(), Record); Writer.AddAPInt(E->getValue(), Record); + + if (E->getValue().getBitWidth() == 32) { + AbbrevToUse = Writer.getIntegerLiteralAbbrev(); + } + Code = serialization::EXPR_INTEGER_LITERAL; } @@ -449,6 +465,9 @@ void ASTStmtWriter::VisitCharacterLiteral(CharacterLiteral *E) { Record.push_back(E->getValue()); Writer.AddSourceLocation(E->getLocation(), Record); Record.push_back(E->isWide()); + + AbbrevToUse = Writer.getCharacterLiteralAbbrev(); + Code = serialization::EXPR_CHARACTER_LITERAL; } @@ -1416,6 +1435,15 @@ void ASTStmtWriter::VisitCUDAKernelCallExpr(CUDAKernelCallExpr *E) { } //===----------------------------------------------------------------------===// +// OpenCL Expressions and Statements. +//===----------------------------------------------------------------------===// +void ASTStmtWriter::VisitAsTypeExpr(AsTypeExpr *E) { + VisitExpr(E); + Writer.AddStmt(E->getSrcExpr()); + Code = serialization::EXPR_ASTYPE; +} + +//===----------------------------------------------------------------------===// // ASTWriter Implementation //===----------------------------------------------------------------------===// @@ -1460,6 +1488,7 @@ void ASTWriter::WriteSubStmt(Stmt *S) { CollectedStmts = &SubStmts; Writer.Code = serialization::STMT_NULL_PTR; + Writer.AbbrevToUse = 0; Writer.Visit(S); #ifndef NDEBUG @@ -1481,7 +1510,7 @@ void ASTWriter::WriteSubStmt(Stmt *S) { while (!SubStmts.empty()) WriteSubStmt(SubStmts.pop_back_val()); - Stream.EmitRecord(Writer.Code, Record); + Stream.EmitRecord(Writer.Code, Record, Writer.AbbrevToUse); } /// \brief Flush all of the statements that have been added to the diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp index a6a256a..f2f5c1e 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp @@ -42,6 +42,7 @@ public: bool wantsRegionChangeUpdate(const GRState *state) const; const GRState *checkRegionChanges(const GRState *state, + const StoreManager::InvalidatedSymbols *, const MemRegion * const *Begin, const MemRegion * const *End) const; @@ -77,6 +78,7 @@ public: void evalStrcmp(CheckerContext &C, const CallExpr *CE) const; void evalStrncmp(CheckerContext &C, const CallExpr *CE) const; void evalStrcasecmp(CheckerContext &C, const CallExpr *CE) const; + void evalStrncasecmp(CheckerContext &C, const CallExpr *CE) const; void evalStrcmpCommon(CheckerContext &C, const CallExpr *CE, bool isBounded = false, bool ignoreCase = false) const; @@ -711,16 +713,13 @@ void CStringChecker::evalCopyCommon(CheckerContext &C, // If the size is zero, there won't be any actual memory access, so // just bind the return value to the destination buffer and return. if (stateZeroSize) { + stateZeroSize = stateZeroSize->BindExpr(CE, destVal); C.addTransition(stateZeroSize); - if (IsMempcpy) - state->BindExpr(CE, destVal); - else - state->BindExpr(CE, sizeVal); - return; } // If the size can be nonzero, we have to check the other arguments. if (stateNonZeroSize) { + state = stateNonZeroSize; // Ensure the destination is not null. If it is NULL there will be a // NULL pointer dereference. @@ -737,42 +736,55 @@ void CStringChecker::evalCopyCommon(CheckerContext &C, if (!state) return; - // Ensure the buffers do not overlap. - state = stateNonZeroSize; + // Ensure the accesses are valid and that the buffers do not overlap. state = CheckBufferAccess(C, state, Size, Dest, Source, /* FirstIsDst = */ true); if (Restricted) state = CheckOverlap(C, state, Size, Dest, Source); - if (state) { - - // If this is mempcpy, get the byte after the last byte copied and - // bind the expr. - if (IsMempcpy) { - loc::MemRegionVal *destRegVal = dyn_cast<loc::MemRegionVal>(&destVal); - - // Get the length to copy. - SVal lenVal = state->getSVal(Size); - NonLoc *lenValNonLoc = dyn_cast<NonLoc>(&lenVal); - + if (!state) + return; + + // If this is mempcpy, get the byte after the last byte copied and + // bind the expr. + if (IsMempcpy) { + loc::MemRegionVal *destRegVal = dyn_cast<loc::MemRegionVal>(&destVal); + assert(destRegVal && "Destination should be a known MemRegionVal here"); + + // Get the length to copy. + NonLoc *lenValNonLoc = dyn_cast<NonLoc>(&sizeVal); + + if (lenValNonLoc) { // Get the byte after the last byte copied. SVal lastElement = C.getSValBuilder().evalBinOpLN(state, BO_Add, *destRegVal, *lenValNonLoc, Dest->getType()); - + // The byte after the last byte copied is the return value. state = state->BindExpr(CE, lastElement); + } else { + // If we don't know how much we copied, we can at least + // conjure a return value for later. + unsigned Count = C.getNodeBuilder().getCurrentBlockCount(); + SVal result = + C.getSValBuilder().getConjuredSymbolVal(NULL, CE, Count); + state = state->BindExpr(CE, result); } - // Invalidate the destination. - // FIXME: Even if we can't perfectly model the copy, we should see if we - // can use LazyCompoundVals to copy the source values into the destination. - // This would probably remove any existing bindings past the end of the - // copied region, but that's still an improvement over blank invalidation. - state = InvalidateBuffer(C, state, Dest, state->getSVal(Dest)); - C.addTransition(state); + } else { + // All other copies return the destination buffer. + // (Well, bcopy() has a void return type, but this won't hurt.) + state = state->BindExpr(CE, destVal); } + + // Invalidate the destination. + // FIXME: Even if we can't perfectly model the copy, we should see if we + // can use LazyCompoundVals to copy the source values into the destination. + // This would probably remove any existing bindings past the end of the + // copied region, but that's still an improvement over blank invalidation. + state = InvalidateBuffer(C, state, Dest, state->getSVal(Dest)); + C.addTransition(state); } } @@ -782,7 +794,7 @@ void CStringChecker::evalMemcpy(CheckerContext &C, const CallExpr *CE) const { // The return value is the address of the destination buffer. const Expr *Dest = CE->getArg(0); const GRState *state = C.getState(); - state = state->BindExpr(CE, state->getSVal(Dest)); + evalCopyCommon(C, CE, state, CE->getArg(2), Dest, CE->getArg(1), true); } @@ -800,7 +812,7 @@ void CStringChecker::evalMemmove(CheckerContext &C, const CallExpr *CE) const { // The return value is the address of the destination buffer. const Expr *Dest = CE->getArg(0); const GRState *state = C.getState(); - state = state->BindExpr(CE, state->getSVal(Dest)); + evalCopyCommon(C, CE, state, CE->getArg(2), Dest, CE->getArg(1)); } @@ -953,7 +965,7 @@ void CStringChecker::evalStrcpy(CheckerContext &C, const CallExpr *CE) const { } void CStringChecker::evalStrncpy(CheckerContext &C, const CallExpr *CE) const { - // char *strcpy(char *restrict dst, const char *restrict src); + // char *strncpy(char *restrict dst, const char *restrict src, size_t n); evalStrcpyCommon(C, CE, /* returnEnd = */ false, /* isBounded = */ true, @@ -1128,6 +1140,12 @@ void CStringChecker::evalStrcasecmp(CheckerContext &C, evalStrcmpCommon(C, CE, /* isBounded = */ false, /* ignoreCase = */ true); } +void CStringChecker::evalStrncasecmp(CheckerContext &C, + const CallExpr *CE) const { + //int strncasecmp(const char *restrict s1, const char *restrict s2, size_t n); + evalStrcmpCommon(C, CE, /* isBounded = */ true, /* ignoreCase = */ true); +} + void CStringChecker::evalStrcmpCommon(CheckerContext &C, const CallExpr *CE, bool isBounded, bool ignoreCase) const { const GRState *state = C.getState(); @@ -1181,31 +1199,17 @@ void CStringChecker::evalStrcmpCommon(CheckerContext &C, const CallExpr *CE, return; llvm::APSInt lenInt(CI->getValue()); - // Compare using the bounds provided like strncmp() does. - if (ignoreCase) { - // TODO Implement compare_lower(RHS, n) in LLVM StringRef. - // result = s1StrRef.compare_lower(s2StrRef, - // (size_t)lenInt.getLimitedValue()); + // Create substrings of each to compare the prefix. + s1StrRef = s1StrRef.substr(0, (size_t)lenInt.getLimitedValue()); + s2StrRef = s2StrRef.substr(0, (size_t)lenInt.getLimitedValue()); + } - // For now, give up. - return; - } else { - // Create substrings of each to compare the prefix. - llvm::StringRef s1SubStr = - s1StrRef.substr(0, (size_t)lenInt.getLimitedValue()); - llvm::StringRef s2SubStr = - s2StrRef.substr(0, (size_t)lenInt.getLimitedValue()); - - // Compare the substrings. - result = s1SubStr.compare(s2SubStr); - } + if (ignoreCase) { + // Compare string 1 to string 2 the same way strcasecmp() does. + result = s1StrRef.compare_lower(s2StrRef); } else { // Compare string 1 to string 2 the same way strcmp() does. - if (ignoreCase) { - result = s1StrRef.compare_lower(s2StrRef); - } else { - result = s1StrRef.compare(s2StrRef); - } + result = s1StrRef.compare(s2StrRef); } // Build the SVal of the comparison to bind the return value. @@ -1243,11 +1247,11 @@ bool CStringChecker::evalCall(const CallExpr *CE, CheckerContext &C) const { FnCheck evalFunction = llvm::StringSwitch<FnCheck>(Name) .Cases("memcpy", "__memcpy_chk", &CStringChecker::evalMemcpy) - .Case("mempcpy", &CStringChecker::evalMempcpy) + .Cases("mempcpy", "__mempcpy_chk", &CStringChecker::evalMempcpy) .Cases("memcmp", "bcmp", &CStringChecker::evalMemcmp) .Cases("memmove", "__memmove_chk", &CStringChecker::evalMemmove) .Cases("strcpy", "__strcpy_chk", &CStringChecker::evalStrcpy) - .Cases("strncpy", "__strncpy_chk", &CStringChecker::evalStrncpy) + //.Cases("strncpy", "__strncpy_chk", &CStringChecker::evalStrncpy) .Cases("stpcpy", "__stpcpy_chk", &CStringChecker::evalStpcpy) .Cases("strcat", "__strcat_chk", &CStringChecker::evalStrcat) .Cases("strncat", "__strncat_chk", &CStringChecker::evalStrncat) @@ -1256,6 +1260,7 @@ bool CStringChecker::evalCall(const CallExpr *CE, CheckerContext &C) const { .Case("strcmp", &CStringChecker::evalStrcmp) .Case("strncmp", &CStringChecker::evalStrncmp) .Case("strcasecmp", &CStringChecker::evalStrcasecmp) + .Case("strncasecmp", &CStringChecker::evalStrncasecmp) .Case("bcopy", &CStringChecker::evalBcopy) .Default(NULL); @@ -1311,6 +1316,7 @@ bool CStringChecker::wantsRegionChangeUpdate(const GRState *state) const { const GRState * CStringChecker::checkRegionChanges(const GRState *state, + const StoreManager::InvalidatedSymbols *, const MemRegion * const *Begin, const MemRegion * const *End) const { CStringLength::EntryMap Entries = state->get<CStringLength>(); diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp index 63a5917..a51d8e0 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp @@ -97,7 +97,7 @@ public: void CFErrorFunctionChecker::checkASTDecl(const FunctionDecl *D, AnalysisManager &mgr, BugReporter &BR) const { - if (!D->isThisDeclarationADefinition()) + if (!D->doesThisDeclarationHaveABody()) return; if (!D->getResultType()->isVoidType()) return; diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/BasicStore.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/BasicStore.cpp index 4faa84c..7c9f45a 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/BasicStore.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/BasicStore.cpp @@ -49,11 +49,11 @@ public: SVal Retrieve(Store store, Loc loc, QualType T = QualType()); StoreRef invalidateRegion(Store store, const MemRegion *R, const Expr *E, - unsigned Count, InvalidatedSymbols *IS); + unsigned Count, InvalidatedSymbols &IS); StoreRef invalidateRegions(Store store, const MemRegion * const *Begin, const MemRegion * const *End, const Expr *E, - unsigned Count, InvalidatedSymbols *IS, + unsigned Count, InvalidatedSymbols &IS, bool invalidateGlobals, InvalidatedRegions *Regions); @@ -538,7 +538,7 @@ StoreRef BasicStoreManager::invalidateRegions(Store store, const MemRegion * const *I, const MemRegion * const *End, const Expr *E, unsigned Count, - InvalidatedSymbols *IS, + InvalidatedSymbols &IS, bool invalidateGlobals, InvalidatedRegions *Regions) { StoreRef newStore(store, *this); @@ -587,18 +587,16 @@ StoreRef BasicStoreManager::invalidateRegion(Store store, const MemRegion *R, const Expr *E, unsigned Count, - InvalidatedSymbols *IS) { + InvalidatedSymbols &IS) { R = R->StripCasts(); if (!(isa<VarRegion>(R) || isa<ObjCIvarRegion>(R))) return StoreRef(store, *this); - if (IS) { - BindingsTy B = GetBindings(store); - if (BindingsTy::data_type *Val = B.lookup(R)) { - if (SymbolRef Sym = Val->getAsSymbol()) - IS->insert(Sym); - } + BindingsTy B = GetBindings(store); + if (BindingsTy::data_type *Val = B.lookup(R)) { + if (SymbolRef Sym = Val->getAsSymbol()) + IS.insert(Sym); } QualType T = cast<TypedRegion>(R)->getValueType(); diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp index ae8a04c..0ed4ff1 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp @@ -101,7 +101,8 @@ const llvm::APSInt& BasicValueFactory::getValue(uint64_t X, unsigned BitWidth, const llvm::APSInt& BasicValueFactory::getValue(uint64_t X, QualType T) { unsigned bits = Ctx.getTypeSize(T); - llvm::APSInt V(bits, T->isUnsignedIntegerType() || Loc::isLocType(T)); + llvm::APSInt V(bits, + T->isUnsignedIntegerOrEnumerationType() || Loc::isLocType(T)); V = X; return getValue(V); } diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CFRefCount.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CFRefCount.cpp index d9b1ce8..0512e2f 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CFRefCount.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CFRefCount.cpp @@ -930,6 +930,13 @@ RetainSummary* RetainSummaryManager::getSummary(const FunctionDecl* FD) { S = getPersistentStopSummary(); break; } + // For C++ methods, generate an implicit "stop" summary as well. We + // can relax this once we have a clear policy for C++ methods and + // ownership attributes. + if (isa<CXXMethodDecl>(FD)) { + S = getPersistentStopSummary(); + break; + } // [PR 3337] Use 'getAs<FunctionType>' to strip away any typedefs on the // function's type. @@ -1111,15 +1118,11 @@ RetainSummary* RetainSummaryManager::getSummary(const FunctionDecl* FD) { RetainSummary* RetainSummaryManager::getCFCreateGetRuleSummary(const FunctionDecl* FD, StringRef FName) { - if (FName.find("Create") != StringRef::npos || FName.find("Copy") != StringRef::npos) return getCFSummaryCreateRule(FD); - if (FName.find("Get") != StringRef::npos) - return getCFSummaryGetRule(FD); - - return getDefaultSummary(); + return getCFSummaryGetRule(FD); } RetainSummary* @@ -1233,6 +1236,9 @@ RetainSummaryManager::updateSummaryFromAnnotations(RetainSummary &Summ, if (FD->getAttr<CFReturnsRetainedAttr>()) { Summ.setRetEffect(RetEffect::MakeOwned(RetEffect::CF, true)); } + else if (FD->getAttr<CFReturnsNotRetainedAttr>()) { + Summ.setRetEffect(RetEffect::MakeNotOwned(RetEffect::CF)); + } } } @@ -1758,6 +1764,15 @@ public: StmtNodeBuilder& Builder, const ReturnStmt* S, ExplodedNode* Pred); + + void evalReturnWithRetEffect(ExplodedNodeSet& Dst, + ExprEngine& Engine, + StmtNodeBuilder& Builder, + const ReturnStmt* S, + ExplodedNode* Pred, + RetEffect RE, RefVal X, + SymbolRef Sym, const GRState *state); + // Assumptions. @@ -2075,7 +2090,7 @@ PathDiagnosticPiece* CFRefReport::VisitNode(const ExplodedNode* N, } if (CurrV.isOwned()) { - os << "+1 retain count (owning reference)."; + os << "+1 retain count"; if (static_cast<CFRefBug&>(getBugType()).getTF().isGCEnabled()) { assert(CurrV.getObjKind() == RetEffect::CF); @@ -2085,7 +2100,7 @@ PathDiagnosticPiece* CFRefReport::VisitNode(const ExplodedNode* N, } else { assert (CurrV.isNotOwned()); - os << "+0 retain count (non-owning reference)."; + os << "+0 retain count"; } PathDiagnosticLocation Pos(S, BRC.getSourceManager()); @@ -2217,11 +2232,11 @@ PathDiagnosticPiece* CFRefReport::VisitNode(const ExplodedNode* N, case RefVal::ReturnedOwned: os << "Object returned to caller as an owning reference (single retain " - "count transferred to caller)."; + "count transferred to caller)"; break; case RefVal::ReturnedNotOwned: - os << "Object returned to caller with a +0 (non-owning) retain count."; + os << "Object returned to caller with a +0 retain count"; break; default: @@ -2354,12 +2369,7 @@ CFRefLeakReport::getEndPath(BugReporterContext& BRC, llvm::tie(AllocNode, FirstBinding) = GetAllocationSite(BRC.getStateManager(), EndN, Sym); - // Get the allocate site. - assert(AllocNode); - const Stmt* FirstStmt = cast<PostStmt>(AllocNode->getLocation()).getStmt(); - SourceManager& SMgr = BRC.getSourceManager(); - unsigned AllocLine =SMgr.getInstantiationLineNumber(FirstStmt->getLocStart()); // Compute an actual location for the leak. Sometimes a leak doesn't // occur at an actual statement (e.g., transition between blocks; end @@ -2392,10 +2402,14 @@ CFRefLeakReport::getEndPath(BugReporterContext& BRC, std::string sbuf; llvm::raw_string_ostream os(sbuf); - os << "Object allocated on line " << AllocLine; + os << "Object leaked: "; - if (FirstBinding) - os << " and stored into '" << FirstBinding->getString() << '\''; + if (FirstBinding) { + os << "object allocated and stored into '" + << FirstBinding->getString() << '\''; + } + else + os << "allocated object"; // Get the retain count. const RefVal* RV = EndN->getState()->get<RefBindings>(Sym); @@ -2404,12 +2418,22 @@ CFRefLeakReport::getEndPath(BugReporterContext& BRC, // FIXME: Per comments in rdar://6320065, "create" only applies to CF // ojbects. Only "copy", "alloc", "retain" and "new" transfer ownership // to the caller for NS objects. - ObjCMethodDecl& MD = cast<ObjCMethodDecl>(EndN->getCodeDecl()); - os << " is returned from a method whose name ('" - << MD.getSelector().getAsString() - << "') does not contain 'copy' or otherwise starts with" - " 'new' or 'alloc'. This violates the naming convention rules given" - " in the Memory Management Guide for Cocoa (object leaked)"; + const Decl *D = &EndN->getCodeDecl(); + if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) { + os << " is returned from a method whose name ('" + << MD->getSelector().getAsString() + << "') does not start with 'copy', 'mutableCopy', 'alloc' or 'new'." + " This violates the naming convention rules " + " given in the Memory Management Guide for Cocoa"; + } + else { + const FunctionDecl *FD = cast<FunctionDecl>(D); + os << " is return from a function whose name ('" + << FD->getNameAsString() + << "') does not contain 'Copy' or 'Create'. This violates the naming" + " convention rules given the Memory Management Guide for Core " + " Foundation"; + } } else if (RV->getKind() == RefVal::ErrorGCLeakReturned) { ObjCMethodDecl& MD = cast<ObjCMethodDecl>(EndN->getCodeDecl()); @@ -2421,7 +2445,7 @@ CFRefLeakReport::getEndPath(BugReporterContext& BRC, } else os << " is not referenced later in this execution path and has a retain " - "count of +" << RV->getCount() << " (object leaked)"; + "count of +" << RV->getCount(); return new PathDiagnosticEventPiece(L, os.str()); } @@ -2494,6 +2518,23 @@ static QualType GetReturnType(const Expr* RetE, ASTContext& Ctx) { return RetTy; } + +// HACK: Symbols that have ref-count state that are referenced directly +// (not as structure or array elements, or via bindings) by an argument +// should not have their ref-count state stripped after we have +// done an invalidation pass. +// +// FIXME: This is a global to currently share between CFRefCount and +// RetainReleaseChecker. Eventually all functionality in CFRefCount should +// be migrated to RetainReleaseChecker, and we can make this a non-global. +llvm::DenseSet<SymbolRef> WhitelistedSymbols; +namespace { +struct ResetWhiteList { + ResetWhiteList() {} + ~ResetWhiteList() { WhitelistedSymbols.clear(); } +}; +} + void CFRefCount::evalSummary(ExplodedNodeSet& Dst, ExprEngine& Eng, StmtNodeBuilder& Builder, @@ -2510,12 +2551,9 @@ void CFRefCount::evalSummary(ExplodedNodeSet& Dst, SymbolRef ErrorSym = 0; llvm::SmallVector<const MemRegion*, 10> RegionsToInvalidate; - - // HACK: Symbols that have ref-count state that are referenced directly - // (not as structure or array elements, or via bindings) by an argument - // should not have their ref-count state stripped after we have - // done an invalidation pass. - llvm::DenseSet<SymbolRef> WhitelistedSymbols; + + // Use RAII to make sure the whitelist is properly cleared. + ResetWhiteList resetWhiteList; // Invalidate all instance variables of the receiver of a message. // FIXME: We should be able to do better with inter-procedural analysis. @@ -2624,20 +2662,14 @@ void CFRefCount::evalSummary(ExplodedNodeSet& Dst, // NOTE: Even if RegionsToInvalidate is empty, we must still invalidate // global variables. - state = state->invalidateRegions(RegionsToInvalidate.data(), - RegionsToInvalidate.data() + - RegionsToInvalidate.size(), - Ex, Count, &IS, - /* invalidateGlobals = */ true); - - for (StoreManager::InvalidatedSymbols::iterator I = IS.begin(), - E = IS.end(); I!=E; ++I) { - SymbolRef sym = *I; - if (WhitelistedSymbols.count(sym)) - continue; - // Remove any existing reference-count binding. - state = state->remove<RefBindings>(*I); - } + // NOTE: RetainReleaseChecker handles the actual invalidation of symbols. + state = + state->invalidateRegions(RegionsToInvalidate.data(), + RegionsToInvalidate.data() + + RegionsToInvalidate.size(), + Ex, Count, &IS, + /* invalidateGlobals = */ + Eng.doesInvalidateGlobals(callOrMsg)); // Evaluate the effect on the message receiver. if (!ErrorRange.isValid() && Receiver) { @@ -2946,30 +2978,50 @@ void CFRefCount::evalReturn(ExplodedNodeSet& Dst, assert(T); X = *T; + // Consult the summary of the enclosing method. + Decl const *CD = &Pred->getCodeDecl(); + + if (const ObjCMethodDecl* MD = dyn_cast<ObjCMethodDecl>(CD)) { + const RetainSummary &Summ = *Summaries.getMethodSummary(MD); + return evalReturnWithRetEffect(Dst, Eng, Builder, S, + Pred, Summ.getRetEffect(), X, + Sym, state); + } + + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CD)) { + if (!isa<CXXMethodDecl>(FD)) + if (const RetainSummary *Summ = Summaries.getSummary(FD)) + return evalReturnWithRetEffect(Dst, Eng, Builder, S, + Pred, Summ->getRetEffect(), X, + Sym, state); + } +} + +void CFRefCount::evalReturnWithRetEffect(ExplodedNodeSet &Dst, + ExprEngine &Eng, + StmtNodeBuilder &Builder, + const ReturnStmt *S, + ExplodedNode *Pred, + RetEffect RE, RefVal X, + SymbolRef Sym, const GRState *state) { // Any leaks or other errors? if (X.isReturnedOwned() && X.getCount() == 0) { - Decl const *CD = &Pred->getCodeDecl(); - if (const ObjCMethodDecl* MD = dyn_cast<ObjCMethodDecl>(CD)) { - const RetainSummary &Summ = *Summaries.getMethodSummary(MD); - RetEffect RE = Summ.getRetEffect(); + if (RE.getKind() != RetEffect::NoRet) { bool hasError = false; - - if (RE.getKind() != RetEffect::NoRet) { - if (isGCEnabled() && RE.getObjKind() == RetEffect::ObjC) { - // Things are more complicated with garbage collection. If the - // returned object is suppose to be an Objective-C object, we have - // a leak (as the caller expects a GC'ed object) because no - // method should return ownership unless it returns a CF object. - hasError = true; - X = X ^ RefVal::ErrorGCLeakReturned; - } - else if (!RE.isOwned()) { - // Either we are using GC and the returned object is a CF type - // or we aren't using GC. In either case, we expect that the - // enclosing method is expected to return ownership. - hasError = true; - X = X ^ RefVal::ErrorLeakReturned; - } + if (isGCEnabled() && RE.getObjKind() == RetEffect::ObjC) { + // Things are more complicated with garbage collection. If the + // returned object is suppose to be an Objective-C object, we have + // a leak (as the caller expects a GC'ed object) because no + // method should return ownership unless it returns a CF object. + hasError = true; + X = X ^ RefVal::ErrorGCLeakReturned; + } + else if (!RE.isOwned()) { + // Either we are using GC and the returned object is a CF type + // or we aren't using GC. In either case, we expect that the + // enclosing method is expected to return ownership. + hasError = true; + X = X ^ RefVal::ErrorLeakReturned; } if (hasError) { @@ -2987,26 +3039,24 @@ void CFRefCount::evalReturn(ExplodedNodeSet& Dst, } } } + return; } - else if (X.isReturnedNotOwned()) { - Decl const *CD = &Pred->getCodeDecl(); - if (const ObjCMethodDecl* MD = dyn_cast<ObjCMethodDecl>(CD)) { - const RetainSummary &Summ = *Summaries.getMethodSummary(MD); - if (Summ.getRetEffect().isOwned()) { - // Trying to return a not owned object to a caller expecting an - // owned object. - - static int ReturnNotOwnedForOwnedTag = 0; - state = state->set<RefBindings>(Sym, X ^ RefVal::ErrorReturnedNotOwned); - if (ExplodedNode *N = - Builder.generateNode(PostStmt(S, Pred->getLocationContext(), - &ReturnNotOwnedForOwnedTag), - state, Pred)) { - CFRefReport *report = - new CFRefReport(*static_cast<CFRefBug*>(returnNotOwnedForOwned), - *this, N, Sym); - BR->EmitReport(report); - } + + if (X.isReturnedNotOwned()) { + if (RE.isOwned()) { + // Trying to return a not owned object to a caller expecting an + // owned object. + + static int ReturnNotOwnedForOwnedTag = 0; + state = state->set<RefBindings>(Sym, X ^ RefVal::ErrorReturnedNotOwned); + if (ExplodedNode *N = + Builder.generateNode(PostStmt(S, Pred->getLocationContext(), + &ReturnNotOwnedForOwnedTag), + state, Pred)) { + CFRefReport *report = + new CFRefReport(*static_cast<CFRefBug*>(returnNotOwnedForOwned), + *this, N, Sym); + BR->EmitReport(report); } } } @@ -3418,12 +3468,43 @@ void CFRefCount::ProcessNonLeakError(ExplodedNodeSet& Dst, namespace { class RetainReleaseChecker - : public Checker< check::PostStmt<BlockExpr> > { + : public Checker< check::PostStmt<BlockExpr>, check::RegionChanges > { public: + bool wantsRegionUpdate; + + RetainReleaseChecker() : wantsRegionUpdate(true) {} + + void checkPostStmt(const BlockExpr *BE, CheckerContext &C) const; + const GRState *checkRegionChanges(const GRState *state, + const StoreManager::InvalidatedSymbols *invalidated, + const MemRegion * const *begin, + const MemRegion * const *end) const; + + bool wantsRegionChangeUpdate(const GRState *state) const { + return wantsRegionUpdate; + } }; } // end anonymous namespace +const GRState * +RetainReleaseChecker::checkRegionChanges(const GRState *state, + const StoreManager::InvalidatedSymbols *invalidated, + const MemRegion * const *begin, + const MemRegion * const *end) const { + if (!invalidated) + return state; + + for (StoreManager::InvalidatedSymbols::const_iterator I=invalidated->begin(), + E = invalidated->end(); I!=E; ++I) { + SymbolRef sym = *I; + if (WhitelistedSymbols.count(sym)) + continue; + // Remove any existing reference-count binding. + state = state->remove<RefBindings>(sym); + } + return state; +} void RetainReleaseChecker::checkPostStmt(const BlockExpr *BE, CheckerContext &C) const { diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CXXExprEngine.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CXXExprEngine.cpp index 54cbca0..ef7bc20 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CXXExprEngine.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CXXExprEngine.cpp @@ -132,7 +132,7 @@ void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *E, assert(CD); #if 0 - if (!(CD->isThisDeclarationADefinition() && AMgr.shouldInlineCall())) + if (!(CD->doesThisDeclarationHaveABody() && AMgr.shouldInlineCall())) // FIXME: invalidate the object. return; #endif @@ -246,7 +246,7 @@ void ExprEngine::VisitCXXDestructor(const CXXDestructorDecl *DD, const Stmt *S, ExplodedNode *Pred, ExplodedNodeSet &Dst) { - if (!(DD->isThisDeclarationADefinition() && AMgr.shouldInlineCall())) + if (!(DD->doesThisDeclarationHaveABody() && AMgr.shouldInlineCall())) return; // Create the context for 'this' region. const StackFrameContext *SFC = AMgr.getStackFrame(DD, diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp index 4a25490..ba7c384 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp @@ -345,6 +345,7 @@ bool CheckerManager::wantsRegionChangeUpdate(const GRState *state) { /// \brief Run checkers for region changes. const GRState * CheckerManager::runCheckersForRegionChanges(const GRState *state, + const StoreManager::InvalidatedSymbols *invalidated, const MemRegion * const *Begin, const MemRegion * const *End) { for (unsigned i = 0, e = RegionChangesCheckers.size(); i != e; ++i) { @@ -352,7 +353,7 @@ CheckerManager::runCheckersForRegionChanges(const GRState *state, // bail out. if (!state) return NULL; - state = RegionChangesCheckers[i].CheckFn(state, Begin, End); + state = RegionChangesCheckers[i].CheckFn(state, invalidated, Begin, End); } return state; } @@ -415,6 +416,15 @@ void CheckerManager::runCheckersForEvalCall(ExplodedNodeSet &Dst, } } +/// \brief Run checkers for the entire Translation Unit. +void CheckerManager::runCheckersOnEndOfTranslationUnit( + const TranslationUnitDecl *TU, + AnalysisManager &mgr, + BugReporter &BR) { + for (unsigned i = 0, e = EndOfTranslationUnitCheckers.size(); i != e; ++i) + EndOfTranslationUnitCheckers[i](TU, mgr, BR); +} + //===----------------------------------------------------------------------===// // Internal registration functions for AST traversing. //===----------------------------------------------------------------------===// @@ -494,6 +504,11 @@ void CheckerManager::_registerForEvalCall(EvalCallFunc checkfn) { EvalCallCheckers.push_back(checkfn); } +void CheckerManager::_registerForEndOfTranslationUnit( + CheckEndOfTranslationUnit checkfn) { + EndOfTranslationUnitCheckers.push_back(checkfn); +} + //===----------------------------------------------------------------------===// // Implementation details. //===----------------------------------------------------------------------===// diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/Environment.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/Environment.cpp index a00f9dc1..48f126b 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/Environment.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/Environment.cpp @@ -39,6 +39,9 @@ SVal Environment::getSVal(const Stmt *E, SValBuilder& svalBuilder, } for (;;) { + if (const Expr *Ex = dyn_cast<Expr>(E)) + E = Ex->IgnoreParens(); + switch (E->getStmtClass()) { case Stmt::AddrLabelExprClass: return svalBuilder.makeLoc(cast<AddrLabelExpr>(E)); @@ -48,13 +51,10 @@ SVal Environment::getSVal(const Stmt *E, SValBuilder& svalBuilder, continue; } case Stmt::ParenExprClass: - // ParenExprs are no-ops. - E = cast<ParenExpr>(E)->getSubExpr(); - continue; case Stmt::GenericSelectionExprClass: - // GenericSelectionExprs are no-ops. - E = cast<GenericSelectionExpr>(E)->getResultExpr(); - continue; + llvm_unreachable("ParenExprs and GenericSelectionExprs should " + "have been handled by IgnoreParens()"); + return UnknownVal(); case Stmt::CharacterLiteralClass: { const CharacterLiteral* C = cast<CharacterLiteral>(E); return svalBuilder.makeIntVal(C->getValue(), C->getType()); @@ -77,21 +77,6 @@ SVal Environment::getSVal(const Stmt *E, SValBuilder& svalBuilder, // For special C0xx nullptr case, make a null pointer SVal. case Stmt::CXXNullPtrLiteralExprClass: return svalBuilder.makeNull(); - case Stmt::ImplicitCastExprClass: - case Stmt::CXXFunctionalCastExprClass: - case Stmt::CStyleCastExprClass: { - // We blast through no-op casts to get the descendant - // subexpression that has a value. - const CastExpr* C = cast<CastExpr>(E); - QualType CT = C->getType(); - if (CT->isVoidType()) - return UnknownVal(); - if (C->getCastKind() == CK_NoOp) { - E = C->getSubExpr(); - continue; - } - break; - } case Stmt::ExprWithCleanupsClass: E = cast<ExprWithCleanups>(E)->getSubExpr(); continue; diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp index 657420d..aed39eb 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -156,6 +156,27 @@ const GRState* ExprEngine::getInitialState(const LocationContext *InitLoc) { return state; } +bool +ExprEngine::doesInvalidateGlobals(const CallOrObjCMessage &callOrMessage) const +{ + if (callOrMessage.isFunctionCall() && !callOrMessage.isCXXCall()) { + SVal calleeV = callOrMessage.getFunctionCallee(); + if (const FunctionTextRegion *codeR = + llvm::dyn_cast_or_null<FunctionTextRegion>(calleeV.getAsRegion())) { + + const FunctionDecl *fd = codeR->getDecl(); + if (const IdentifierInfo *ii = fd->getIdentifier()) { + llvm::StringRef fname = ii->getName(); + if (fname == "strlen") + return false; + } + } + } + + // The conservative answer: invalidates globals. + return true; +} + //===----------------------------------------------------------------------===// // Top-level transfer function logic (Dispatcher). //===----------------------------------------------------------------------===// @@ -179,9 +200,11 @@ bool ExprEngine::wantsRegionChangeUpdate(const GRState* state) { const GRState * ExprEngine::processRegionChanges(const GRState *state, - const MemRegion * const *Begin, - const MemRegion * const *End) { - return getCheckerManager().runCheckersForRegionChanges(state, Begin, End); + const StoreManager::InvalidatedSymbols *invalidated, + const MemRegion * const *Begin, + const MemRegion * const *End) { + return getCheckerManager().runCheckersForRegionChanges(state, invalidated, + Begin, End); } void ExprEngine::processEndWorklist(bool hasWorkRemaining) { @@ -516,6 +539,7 @@ void ExprEngine::Visit(const Stmt* S, ExplodedNode* Pred, case Stmt::VAArgExprClass: case Stmt::CUDAKernelCallExprClass: case Stmt::OpaqueValueExprClass: + case Stmt::AsTypeExprClass: // Fall through. // Cases we intentionally don't evaluate, since they don't need @@ -2462,7 +2486,7 @@ void ExprEngine::VisitOffsetOfExpr(const OffsetOfExpr* OOE, const APSInt &IV = Res.Val.getInt(); assert(IV.getBitWidth() == getContext().getTypeSize(OOE->getType())); assert(OOE->getType()->isIntegerType()); - assert(IV.isSigned() == OOE->getType()->isSignedIntegerType()); + assert(IV.isSigned() == OOE->getType()->isSignedIntegerOrEnumerationType()); SVal X = svalBuilder.makeIntVal(IV); MakeNode(Dst, OOE, Pred, GetState(Pred)->BindExpr(OOE, X)); return; @@ -2701,7 +2725,7 @@ void ExprEngine::VisitUnaryOperator(const UnaryOperator* U, if (U->isLValue()) state = state->BindExpr(U, loc); else - state = state->BindExpr(U, V2); + state = state->BindExpr(U, U->isPostfix() ? V2 : Result); // Perform the store. evalStore(Dst, NULL, U, *I2, state, loc, Result); diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/FlatStore.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/FlatStore.cpp index 7bdca6b..ca867ae 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/FlatStore.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/FlatStore.cpp @@ -59,7 +59,7 @@ public: StoreRef invalidateRegions(Store store, const MemRegion * const *I, const MemRegion * const *E, const Expr *Ex, - unsigned Count, InvalidatedSymbols *IS, + unsigned Count, InvalidatedSymbols &IS, bool invalidateGlobals, InvalidatedRegions *Regions); @@ -175,7 +175,7 @@ StoreRef FlatStoreManager::invalidateRegions(Store store, const MemRegion * const *I, const MemRegion * const *E, const Expr *Ex, unsigned Count, - InvalidatedSymbols *IS, + InvalidatedSymbols &IS, bool invalidateGlobals, InvalidatedRegions *Regions) { assert(false && "Not implemented"); diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/GRState.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/GRState.cpp index 7b21677..0f6ff1e 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/GRState.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/GRState.cpp @@ -141,6 +141,20 @@ const GRState *GRState::invalidateRegions(const MemRegion * const *Begin, const Expr *E, unsigned Count, StoreManager::InvalidatedSymbols *IS, bool invalidateGlobals) const { + if (!IS) { + StoreManager::InvalidatedSymbols invalidated; + return invalidateRegionsImpl(Begin, End, E, Count, + invalidated, invalidateGlobals); + } + return invalidateRegionsImpl(Begin, End, E, Count, *IS, invalidateGlobals); +} + +const GRState * +GRState::invalidateRegionsImpl(const MemRegion * const *Begin, + const MemRegion * const *End, + const Expr *E, unsigned Count, + StoreManager::InvalidatedSymbols &IS, + bool invalidateGlobals) const { GRStateManager &Mgr = getStateManager(); SubEngine* Eng = Mgr.getOwningEngine(); @@ -150,7 +164,7 @@ const GRState *GRState::invalidateRegions(const MemRegion * const *Begin, = Mgr.StoreMgr->invalidateRegions(getStore(), Begin, End, E, Count, IS, invalidateGlobals, &Regions); const GRState *newState = makeWithStore(newStore); - return Eng->processRegionChanges(newState, + return Eng->processRegionChanges(newState, &IS, &Regions.front(), &Regions.back()+1); } diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ObjCMessage.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ObjCMessage.cpp index c005819..c000600 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ObjCMessage.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ObjCMessage.cpp @@ -141,6 +141,13 @@ SVal CallOrObjCMessage::getArgSValAsScalarOrLoc(unsigned i) const { return UnknownVal(); } +SVal CallOrObjCMessage::getFunctionCallee() const { + assert(isFunctionCall()); + assert(!isCXXCall()); + const Expr *callee = CallE->getCallee()->IgnoreParenCasts(); + return State->getSVal(callee); +} + SVal CallOrObjCMessage::getCXXCallee() const { assert(isCXXCall()); const Expr *callee = diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/RegionStore.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/RegionStore.cpp index 4522f97..d0d8f60 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/RegionStore.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/RegionStore.cpp @@ -240,7 +240,7 @@ public: const MemRegion * const *Begin, const MemRegion * const *End, const Expr *E, unsigned Count, - InvalidatedSymbols *IS, + InvalidatedSymbols &IS, bool invalidateGlobals, InvalidatedRegions *Regions); @@ -586,14 +586,14 @@ class invalidateRegionsWorker : public ClusterAnalysis<invalidateRegionsWorker> { const Expr *Ex; unsigned Count; - StoreManager::InvalidatedSymbols *IS; + StoreManager::InvalidatedSymbols &IS; StoreManager::InvalidatedRegions *Regions; public: invalidateRegionsWorker(RegionStoreManager &rm, GRStateManager &stateMgr, RegionBindings b, const Expr *ex, unsigned count, - StoreManager::InvalidatedSymbols *is, + StoreManager::InvalidatedSymbols &is, StoreManager::InvalidatedRegions *r, bool includeGlobals) : ClusterAnalysis<invalidateRegionsWorker>(rm, stateMgr, b, includeGlobals), @@ -609,9 +609,8 @@ private: void invalidateRegionsWorker::VisitBinding(SVal V) { // A symbol? Mark it touched by the invalidation. - if (IS) - if (SymbolRef Sym = V.getAsSymbol()) - IS->insert(Sym); + if (SymbolRef Sym = V.getAsSymbol()) + IS.insert(Sym); if (const MemRegion *R = V.getAsRegion()) { AddToWorkList(R); @@ -648,11 +647,9 @@ void invalidateRegionsWorker::VisitCluster(const MemRegion *baseR, } void invalidateRegionsWorker::VisitBaseRegion(const MemRegion *baseR) { - if (IS) { - // Symbolic region? Mark that symbol touched by the invalidation. - if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(baseR)) - IS->insert(SR->getSymbol()); - } + // Symbolic region? Mark that symbol touched by the invalidation. + if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(baseR)) + IS.insert(SR->getSymbol()); // BlockDataRegion? If so, invalidate captured variables that are passed // by reference. @@ -724,7 +721,7 @@ StoreRef RegionStoreManager::invalidateRegions(Store store, const MemRegion * const *I, const MemRegion * const *E, const Expr *Ex, unsigned Count, - InvalidatedSymbols *IS, + InvalidatedSymbols &IS, bool invalidateGlobals, InvalidatedRegions *Regions) { invalidateRegionsWorker W(*this, StateMgr, @@ -1066,6 +1063,11 @@ SVal RegionStoreManager::RetrieveElement(Store store, // return *y; // FIXME: This is a hack, and doesn't do anything really intelligent yet. const RegionRawOffset &O = R->getAsArrayOffset(); + + // If we cannot reason about the offset, return an unknown value. + if (!O.getRegion()) + return UnknownVal(); + if (const TypedRegion *baseR = dyn_cast_or_null<TypedRegion>(O.getRegion())) { QualType baseT = baseR->getValueType(); if (baseT->isScalarType()) { diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp index 1ee694e..20762e0 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp @@ -262,7 +262,8 @@ const GRState *SimpleConstraintManager::assumeSymRel(const GRState *state, QualType T = Sym->getType(Ctx); assert(T->isIntegerType() || Loc::isLocType(T)); unsigned bitwidth = Ctx.getTypeSize(T); - bool isSymUnsigned = T->isUnsignedIntegerType() || Loc::isLocType(T); + bool isSymUnsigned + = T->isUnsignedIntegerOrEnumerationType() || Loc::isLocType(T); // Convert the adjustment. Adjustment.setIsUnsigned(isSymUnsigned); diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp index 5d80251..197442b 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp @@ -97,7 +97,8 @@ SVal SimpleSValBuilder::evalCastFromNonLoc(NonLoc val, QualType castTy) { return UnknownVal(); llvm::APSInt i = cast<nonloc::ConcreteInt>(val).getValue(); - i.setIsUnsigned(castTy->isUnsignedIntegerType() || Loc::isLocType(castTy)); + i.setIsUnsigned(castTy->isUnsignedIntegerOrEnumerationType() || + Loc::isLocType(castTy)); i = i.extOrTrunc(Context.getTypeSize(castTy)); if (isLocType) @@ -129,7 +130,8 @@ SVal SimpleSValBuilder::evalCastFromLoc(Loc val, QualType castTy) { return makeLocAsInteger(val, BitWidth); llvm::APSInt i = cast<loc::ConcreteInt>(val).getValue(); - i.setIsUnsigned(castTy->isUnsignedIntegerType() || Loc::isLocType(castTy)); + i.setIsUnsigned(castTy->isUnsignedIntegerOrEnumerationType() || + Loc::isLocType(castTy)); i = i.extOrTrunc(BitWidth); return makeIntVal(i); } diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp index fe6e1fd..b8dbb54 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp @@ -200,18 +200,20 @@ void AnalysisConsumer::HandleDeclContext(ASTContext &C, DeclContext *dc) { } break; } - + + case Decl::ObjCCategoryImpl: case Decl::ObjCImplementation: { - ObjCImplementationDecl* ID = cast<ObjCImplementationDecl>(*I); + ObjCImplDecl* ID = cast<ObjCImplDecl>(*I); HandleCode(ID); - for (ObjCImplementationDecl::method_iterator MI = ID->meth_begin(), + for (ObjCContainerDecl::method_iterator MI = ID->meth_begin(), ME = ID->meth_end(); MI != ME; ++MI) { checkerMgr->runCheckersOnASTDecl(*MI, *Mgr, BR); if ((*MI)->isThisDeclarationADefinition()) { if (!Opts.AnalyzeSpecificFunction.empty() && - Opts.AnalyzeSpecificFunction != (*MI)->getSelector().getAsString()) + Opts.AnalyzeSpecificFunction != + (*MI)->getSelector().getAsString()) break; DisplayFunction(*MI); HandleCode(*MI); @@ -232,6 +234,9 @@ void AnalysisConsumer::HandleTranslationUnit(ASTContext &C) { checkerMgr->runCheckersOnASTDecl(TU, *Mgr, BR); HandleDeclContext(C, TU); + // After all decls handled, run checkers on the entire TranslationUnit. + checkerMgr->runCheckersOnEndOfTranslationUnit(TU, *Mgr, BR); + // Explicitly destroy the PathDiagnosticClient. This will flush its output. // FIXME: This should be replaced with something that doesn't rely on // side-effects in PathDiagnosticClient's destructor. This is required when diff --git a/contrib/llvm/tools/clang/lib/Tooling/JsonCompileCommandLineDatabase.cpp b/contrib/llvm/tools/clang/lib/Tooling/JsonCompileCommandLineDatabase.cpp deleted file mode 100644 index 7f027cf..0000000 --- a/contrib/llvm/tools/clang/lib/Tooling/JsonCompileCommandLineDatabase.cpp +++ /dev/null @@ -1,214 +0,0 @@ -//===--- JsonCompileCommandLineDatabase.cpp - Simple JSON database --------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements reading a compile command line database, as written -// out for example by CMake. -// -//===----------------------------------------------------------------------===// - -#include "JsonCompileCommandLineDatabase.h" -#include "llvm/ADT/Twine.h" - -namespace clang { -namespace tooling { - -namespace { - -// A parser for JSON escaped strings of command line arguments with \-escaping -// for quoted arguments (see the documentation of UnescapeJsonCommandLine(...)). -class CommandLineArgumentParser { - public: - CommandLineArgumentParser(llvm::StringRef CommandLine) - : Input(CommandLine), Position(Input.begin()-1) {} - - std::vector<std::string> Parse() { - bool HasMoreInput = true; - while (HasMoreInput && NextNonWhitespace()) { - std::string Argument; - HasMoreInput = ParseStringInto(Argument); - CommandLine.push_back(Argument); - } - return CommandLine; - } - - private: - // All private methods return true if there is more input available. - - bool ParseStringInto(std::string &String) { - do { - if (*Position == '"') { - if (!ParseQuotedStringInto(String)) return false; - } else { - if (!ParseFreeStringInto(String)) return false; - } - } while (*Position != ' '); - return true; - } - - bool ParseQuotedStringInto(std::string &String) { - if (!Next()) return false; - while (*Position != '"') { - if (!SkipEscapeCharacter()) return false; - String.push_back(*Position); - if (!Next()) return false; - } - return Next(); - } - - bool ParseFreeStringInto(std::string &String) { - do { - if (!SkipEscapeCharacter()) return false; - String.push_back(*Position); - if (!Next()) return false; - } while (*Position != ' ' && *Position != '"'); - return true; - } - - bool SkipEscapeCharacter() { - if (*Position == '\\') { - return Next(); - } - return true; - } - - bool NextNonWhitespace() { - do { - if (!Next()) return false; - } while (*Position == ' '); - return true; - } - - bool Next() { - ++Position; - if (Position == Input.end()) return false; - // Remove the JSON escaping first. This is done unconditionally. - if (*Position == '\\') ++Position; - return Position != Input.end(); - } - - const llvm::StringRef Input; - llvm::StringRef::iterator Position; - std::vector<std::string> CommandLine; -}; - -} // end namespace - -std::vector<std::string> UnescapeJsonCommandLine( - llvm::StringRef JsonEscapedCommandLine) { - CommandLineArgumentParser parser(JsonEscapedCommandLine); - return parser.Parse(); -} - -JsonCompileCommandLineParser::JsonCompileCommandLineParser( - const llvm::StringRef Input, CompileCommandHandler *CommandHandler) - : Input(Input), Position(Input.begin()-1), CommandHandler(CommandHandler) {} - -bool JsonCompileCommandLineParser::Parse() { - NextNonWhitespace(); - return ParseTranslationUnits(); -} - -std::string JsonCompileCommandLineParser::GetErrorMessage() const { - return ErrorMessage; -} - -bool JsonCompileCommandLineParser::ParseTranslationUnits() { - if (!ConsumeOrError('[', "at start of compile command file")) return false; - if (!ParseTranslationUnit(/*First=*/true)) return false; - while (Consume(',')) { - if (!ParseTranslationUnit(/*First=*/false)) return false; - } - if (!ConsumeOrError(']', "at end of array")) return false; - if (CommandHandler != NULL) { - CommandHandler->EndTranslationUnits(); - } - return true; -} - -bool JsonCompileCommandLineParser::ParseTranslationUnit(bool First) { - if (First) { - if (!Consume('{')) return true; - } else { - if (!ConsumeOrError('{', "at start of object")) return false; - } - if (!Consume('}')) { - if (!ParseObjectKeyValuePairs()) return false; - if (!ConsumeOrError('}', "at end of object")) return false; - } - if (CommandHandler != NULL) { - CommandHandler->EndTranslationUnit(); - } - return true; -} - -bool JsonCompileCommandLineParser::ParseObjectKeyValuePairs() { - do { - llvm::StringRef Key; - if (!ParseString(Key)) return false; - if (!ConsumeOrError(':', "between name and value")) return false; - llvm::StringRef Value; - if (!ParseString(Value)) return false; - if (CommandHandler != NULL) { - CommandHandler->HandleKeyValue(Key, Value); - } - } while (Consume(',')); - return true; -} - -bool JsonCompileCommandLineParser::ParseString(llvm::StringRef &String) { - if (!ConsumeOrError('"', "at start of string")) return false; - llvm::StringRef::iterator First = Position; - llvm::StringRef::iterator Last = Position; - while (!Consume('"')) { - Consume('\\'); - ++Position; - // We need to store Position, as Consume will change Last before leaving - // the loop. - Last = Position; - } - String = llvm::StringRef(First, Last - First); - return true; -} - -bool JsonCompileCommandLineParser::Consume(char C) { - if (Position == Input.end()) return false; - if (*Position != C) return false; - NextNonWhitespace(); - return true; -} - -bool JsonCompileCommandLineParser::ConsumeOrError( - char C, llvm::StringRef Message) { - if (!Consume(C)) { - SetExpectError(C, Message); - return false; - } - return true; -} - -void JsonCompileCommandLineParser::SetExpectError( - char C, llvm::StringRef Message) { - ErrorMessage = (llvm::Twine("'") + llvm::StringRef(&C, 1) + - "' expected " + Message + ".").str(); -} - -void JsonCompileCommandLineParser::NextNonWhitespace() { - do { - ++Position; - } while (IsWhitespace()); -} - -bool JsonCompileCommandLineParser::IsWhitespace() { - if (Position == Input.end()) return false; - return (*Position == ' ' || *Position == '\t' || - *Position == '\n' || *Position == '\r'); -} - -} // end namespace tooling -} // end namespace clang diff --git a/contrib/llvm/tools/clang/lib/Tooling/JsonCompileCommandLineDatabase.h b/contrib/llvm/tools/clang/lib/Tooling/JsonCompileCommandLineDatabase.h deleted file mode 100644 index 9e776d6..0000000 --- a/contrib/llvm/tools/clang/lib/Tooling/JsonCompileCommandLineDatabase.h +++ /dev/null @@ -1,107 +0,0 @@ -//===--- JsonCompileCommandLineDatabase - Simple JSON database --*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements reading a compile command line database, as written -// out for example by CMake. It only supports the subset of the JSON standard -// that is needed to parse the CMake output. -// See http://www.json.org/ for the full standard. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_TOOLING_JSON_COMPILE_COMMAND_LINE_DATABASE_H -#define LLVM_CLANG_TOOLING_JSON_COMPILE_COMMAND_LINE_DATABASE_H - -#include "llvm/ADT/StringRef.h" -#include <string> -#include <vector> - -namespace clang { -namespace tooling { - -/// \brief Converts a JSON escaped command line to a vector of arguments. -/// -/// \param JsonEscapedCommandLine The escaped command line as a string. This -/// is assumed to be escaped as a JSON string (e.g. " and \ are escaped). -/// In addition, any arguments containing spaces are assumed to be \-escaped -/// -/// For example, the input (|| denoting non C-escaped strings): -/// |./call a \"b \\\" c \\\\ \" d| -/// would yield: -/// [ |./call|, |a|, |b " c \ |, |d| ]. -std::vector<std::string> UnescapeJsonCommandLine( - llvm::StringRef JsonEscapedCommandLine); - -/// \brief Interface for users of the JsonCompileCommandLineParser. -class CompileCommandHandler { - public: - virtual ~CompileCommandHandler() {} - - /// \brief Called after all translation units are parsed. - virtual void EndTranslationUnits() {} - - /// \brief Called at the end of a single translation unit. - virtual void EndTranslationUnit() {} - - /// \brief Called for every (Key, Value) pair in a translation unit - /// description. - virtual void HandleKeyValue(llvm::StringRef Key, llvm::StringRef Value) {} -}; - -/// \brief A JSON parser that supports the subset of JSON needed to parse -/// JSON compile command line databases as written out by CMake. -/// -/// The supported subset describes a list of compile command lines for -/// each processed translation unit. The translation units are stored in a -/// JSON array, where each translation unit is described by a JSON object -/// containing (Key, Value) pairs for the working directory the compile command -/// line was executed from, the main C/C++ input file of the translation unit -/// and the actual compile command line, for example: -/// [ -/// { -/// "file":"/file.cpp", -/// "directory":"/", -/// "command":"/cc /file.cpp" -/// } -/// ] -class JsonCompileCommandLineParser { - public: - /// \brief Create a parser on 'Input', calling 'CommandHandler' to handle the - /// parsed constructs. 'CommandHandler' may be NULL in order to just check - /// the validity of 'Input'. - JsonCompileCommandLineParser(const llvm::StringRef Input, - CompileCommandHandler *CommandHandler); - - /// \brief Parses the specified input. Returns true if no parsing errors were - /// foudn. - bool Parse(); - - /// \brief Returns an error message if Parse() returned false previously. - std::string GetErrorMessage() const; - - private: - bool ParseTranslationUnits(); - bool ParseTranslationUnit(bool First); - bool ParseObjectKeyValuePairs(); - bool ParseString(llvm::StringRef &String); - bool Consume(char C); - bool ConsumeOrError(char C, llvm::StringRef Message); - void NextNonWhitespace(); - bool IsWhitespace(); - void SetExpectError(char C, llvm::StringRef Message); - - const llvm::StringRef Input; - llvm::StringRef::iterator Position; - std::string ErrorMessage; - CompileCommandHandler * const CommandHandler; -}; - -} // end namespace tooling -} // end namespace clang - -#endif // LLVM_CLANG_TOOLING_JSON_COMPILE_COMMAND_LINE_DATABASE_H diff --git a/contrib/llvm/tools/clang/lib/Tooling/Tooling.cpp b/contrib/llvm/tools/clang/lib/Tooling/Tooling.cpp deleted file mode 100644 index c1714a9..0000000 --- a/contrib/llvm/tools/clang/lib/Tooling/Tooling.cpp +++ /dev/null @@ -1,322 +0,0 @@ -//===--- Tooling.cpp - Running clang standalone tools --------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements functions to run clang tools standalone instead -// of running them as a plugin. -// -//===----------------------------------------------------------------------===// - -#include "clang/Tooling/Tooling.h" -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/SmallString.h" -#include "llvm/Support/CommandLine.h" -#include "llvm/Support/Host.h" -#include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/ManagedStatic.h" -#include "llvm/Support/Path.h" -#include "llvm/Support/raw_ostream.h" -#include "clang/Basic/DiagnosticIDs.h" -#include "clang/Driver/Compilation.h" -#include "clang/Driver/Driver.h" -#include "clang/Driver/Tool.h" -#include "clang/Frontend/CompilerInstance.h" -#include "clang/Frontend/FrontendAction.h" -#include "clang/Frontend/FrontendDiagnostic.h" -#include "clang/Frontend/TextDiagnosticPrinter.h" -#include "JsonCompileCommandLineDatabase.h" -#include <map> -#include <cstdio> - -namespace clang { -namespace tooling { - -namespace { - -// Checks that the input conforms to the argv[] convention as in -// main(). Namely: -// - it must contain at least a program path, -// - argv[0], ..., and argv[argc - 1] mustn't be NULL, and -// - argv[argc] must be NULL. -void ValidateArgv(int argc, char* argv[]) { - if (argc < 1) { - fprintf(stderr, "ERROR: argc is %d. It must be >= 1.\n", argc); - abort(); - } - - for (int i = 0; i < argc; ++i) { - if (argv[i] == NULL) { - fprintf(stderr, "ERROR: argv[%d] is NULL.\n", i); - abort(); - } - } - - if (argv[argc] != NULL) { - fprintf(stderr, "ERROR: argv[argc] isn't NULL.\n"); - abort(); - } -} - -} // end namespace - -// FIXME: This file contains structural duplication with other parts of the -// code that sets up a compiler to run tools on it, and we should refactor -// it to be based on the same framework. - -static clang::Diagnostic* NewTextDiagnostics() { - llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs> DiagIDs( - new clang::DiagnosticIDs()); - clang::TextDiagnosticPrinter *DiagClient = new clang::TextDiagnosticPrinter( - llvm::errs(), clang::DiagnosticOptions()); - return new clang::Diagnostic(DiagIDs, DiagClient); -} - -// Exists solely for the purpose of lookup of the main executable. -static int StaticSymbol; - -/// \brief Builds a clang driver initialized for running clang tools. -static clang::driver::Driver* NewDriver(clang::Diagnostic* Diagnostics, - const char* BinaryName) { - // This just needs to be some symbol in the binary. - void* const SymbolAddr = &StaticSymbol; - const llvm::sys::Path ExePath = - llvm::sys::Path::GetMainExecutable(BinaryName, SymbolAddr); - - const std::string DefaultOutputName = "a.out"; - clang::driver::Driver* CompilerDriver = new clang::driver::Driver( - ExePath.str(), llvm::sys::getHostTriple(), - DefaultOutputName, false, false, *Diagnostics); - CompilerDriver->setTitle("clang_based_tool"); - return CompilerDriver; -} - -/// \brief Retrieves the clang CC1 specific flags out of the compilation's jobs. -/// Returns NULL on error. -static const clang::driver::ArgStringList* GetCC1Arguments( - clang::Diagnostic* Diagnostics, clang::driver::Compilation* Compilation) { - // We expect to get back exactly one Command job, if we didn't something - // failed. Extract that job from the Compilation. - const clang::driver::JobList &Jobs = Compilation->getJobs(); - if (Jobs.size() != 1 || !isa<clang::driver::Command>(*Jobs.begin())) { - llvm::SmallString<256> error_msg; - llvm::raw_svector_ostream error_stream(error_msg); - Compilation->PrintJob(error_stream, Compilation->getJobs(), "; ", true); - Diagnostics->Report(clang::diag::err_fe_expected_compiler_job) - << error_stream.str(); - return NULL; - } - - // The one job we find should be to invoke clang again. - const clang::driver::Command *Cmd = - cast<clang::driver::Command>(*Jobs.begin()); - if (llvm::StringRef(Cmd->getCreator().getName()) != "clang") { - Diagnostics->Report(clang::diag::err_fe_expected_clang_command); - return NULL; - } - - return &Cmd->getArguments(); -} - -/// \brief Returns a clang build invocation initialized from the CC1 flags. -static clang::CompilerInvocation* NewInvocation( - clang::Diagnostic* Diagnostics, - const clang::driver::ArgStringList& CC1Args) { - clang::CompilerInvocation* Invocation = new clang::CompilerInvocation; - clang::CompilerInvocation::CreateFromArgs( - *Invocation, CC1Args.data(), CC1Args.data() + CC1Args.size(), - *Diagnostics); - Invocation->getFrontendOpts().DisableFree = false; - return Invocation; -} - -/// \brief Runs the specified clang tool action and returns whether it executed -/// successfully. -static bool RunInvocation(const char* BinaryName, - clang::driver::Compilation* Compilation, - clang::CompilerInvocation* Invocation, - const clang::driver::ArgStringList& CC1Args, - clang::FrontendAction* ToolAction) { - llvm::OwningPtr<clang::FrontendAction> ScopedToolAction(ToolAction); - // Show the invocation, with -v. - if (Invocation->getHeaderSearchOpts().Verbose) { - llvm::errs() << "clang Invocation:\n"; - Compilation->PrintJob(llvm::errs(), Compilation->getJobs(), "\n", true); - llvm::errs() << "\n"; - } - - // Create a compiler instance to handle the actual work. - clang::CompilerInstance Compiler; - Compiler.setInvocation(Invocation); - - // Create the compilers actual diagnostics engine. - Compiler.createDiagnostics(CC1Args.size(), - const_cast<char**>(CC1Args.data())); - if (!Compiler.hasDiagnostics()) - return false; - - // Infer the builtin include path if unspecified. - if (Compiler.getHeaderSearchOpts().UseBuiltinIncludes && - Compiler.getHeaderSearchOpts().ResourceDir.empty()) { - // This just needs to be some symbol in the binary. - void* const SymbolAddr = &StaticSymbol; - Compiler.getHeaderSearchOpts().ResourceDir = - clang::CompilerInvocation::GetResourcesPath(BinaryName, SymbolAddr); - } - - const bool Success = Compiler.ExecuteAction(*ToolAction); - return Success; -} - -/// \brief Converts a string vector representing a Command line into a C -/// string vector representing the Argv (including the trailing NULL). -std::vector<char*> CommandLineToArgv(const std::vector<std::string>* Command) { - std::vector<char*> Result(Command->size() + 1); - for (std::vector<char*>::size_type I = 0; I < Command->size(); ++I) { - Result[I] = const_cast<char*>((*Command)[I].c_str()); - } - Result[Command->size()] = NULL; - return Result; -} - -bool RunToolWithFlags( - clang::FrontendAction* ToolAction, int Args, char* Argv[]) { - ValidateArgv(Args, Argv); - const llvm::OwningPtr<clang::Diagnostic> Diagnostics(NewTextDiagnostics()); - const llvm::OwningPtr<clang::driver::Driver> Driver( - NewDriver(Diagnostics.get(), Argv[0])); - const llvm::OwningPtr<clang::driver::Compilation> Compilation( - Driver->BuildCompilation(llvm::ArrayRef<const char*>(Argv, Args))); - const clang::driver::ArgStringList* const CC1Args = GetCC1Arguments( - Diagnostics.get(), Compilation.get()); - if (CC1Args == NULL) { - return false; - } - llvm::OwningPtr<clang::CompilerInvocation> Invocation( - NewInvocation(Diagnostics.get(), *CC1Args)); - return RunInvocation(Argv[0], Compilation.get(), Invocation.take(), - *CC1Args, ToolAction); -} - -/// \brief Runs 'ToolAction' on the code specified by 'FileContents'. -/// -/// \param FileContents A mapping from file name to source code. For each -/// entry a virtual file mapping will be created when running the tool. -bool RunToolWithFlagsOnCode( - const std::vector<std::string>& CommandLine, - const std::map<std::string, std::string>& FileContents, - clang::FrontendAction* ToolAction) { - const std::vector<char*> Argv = CommandLineToArgv(&CommandLine); - const char* const BinaryName = Argv[0]; - - const llvm::OwningPtr<clang::Diagnostic> Diagnostics(NewTextDiagnostics()); - const llvm::OwningPtr<clang::driver::Driver> Driver( - NewDriver(Diagnostics.get(), BinaryName)); - - // Since the Input is only virtual, don't check whether it exists. - Driver->setCheckInputsExist(false); - - const llvm::OwningPtr<clang::driver::Compilation> Compilation( - Driver->BuildCompilation(llvm::ArrayRef<const char*>(&Argv[0], - Argv.size() - 1))); - const clang::driver::ArgStringList* const CC1Args = GetCC1Arguments( - Diagnostics.get(), Compilation.get()); - if (CC1Args == NULL) { - return false; - } - llvm::OwningPtr<clang::CompilerInvocation> Invocation( - NewInvocation(Diagnostics.get(), *CC1Args)); - - for (std::map<std::string, std::string>::const_iterator - It = FileContents.begin(), End = FileContents.end(); - It != End; ++It) { - // Inject the code as the given file name into the preprocessor options. - const llvm::MemoryBuffer* Input = - llvm::MemoryBuffer::getMemBuffer(It->second.c_str()); - Invocation->getPreprocessorOpts().addRemappedFile(It->first.c_str(), Input); - } - - return RunInvocation(BinaryName, Compilation.get(), - Invocation.take(), *CC1Args, ToolAction); -} - -bool RunSyntaxOnlyToolOnCode( - clang::FrontendAction *ToolAction, llvm::StringRef Code) { - const char* const FileName = "input.cc"; - const char* const CommandLine[] = { - "clang-tool", "-fsyntax-only", FileName - }; - std::map<std::string, std::string> FileContents; - FileContents[FileName] = Code; - return RunToolWithFlagsOnCode( - std::vector<std::string>( - CommandLine, - CommandLine + sizeof(CommandLine)/sizeof(CommandLine[0])), - FileContents, ToolAction); -} - -namespace { - -// A CompileCommandHandler implementation that finds compile commands for a -// specific input file. -// -// FIXME: Implement early exit when JsonCompileCommandLineParser supports it. -class FindHandler : public clang::tooling::CompileCommandHandler { - public: - explicit FindHandler(llvm::StringRef File) - : FileToMatch(File), FoundMatchingCommand(false) {} - - virtual void EndTranslationUnits() { - if (!FoundMatchingCommand && ErrorMessage.empty()) { - ErrorMessage = "ERROR: No matching command found."; - } - } - - virtual void EndTranslationUnit() { - if (File == FileToMatch) { - FoundMatchingCommand = true; - MatchingCommand.Directory = Directory; - MatchingCommand.CommandLine = UnescapeJsonCommandLine(Command); - } - } - - virtual void HandleKeyValue(llvm::StringRef Key, llvm::StringRef Value) { - if (Key == "directory") { Directory = Value; } - else if (Key == "file") { File = Value; } - else if (Key == "command") { Command = Value; } - else { - ErrorMessage = (llvm::Twine("Unknown key: \"") + Key + "\"").str(); - } - } - - const llvm::StringRef FileToMatch; - bool FoundMatchingCommand; - CompileCommand MatchingCommand; - std::string ErrorMessage; - - llvm::StringRef Directory; - llvm::StringRef File; - llvm::StringRef Command; -}; - -} // end namespace - -CompileCommand FindCompileArgsInJsonDatabase( - llvm::StringRef FileName, llvm::StringRef JsonDatabase, - std::string &ErrorMessage) { - FindHandler find_handler(FileName); - JsonCompileCommandLineParser parser(JsonDatabase, &find_handler); - if (!parser.Parse()) { - ErrorMessage = parser.GetErrorMessage(); - return CompileCommand(); - } - return find_handler.MatchingCommand; -} - -} // end namespace tooling -} // end namespace clang - |